1 /***************************************************************************
2                           cmessagehandler.cpp  -  description
3                              -------------------
4     begin                : Sun Sep 30 2001
5     copyright            : (C) 2001-2005 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 "cmessagehandler.h"
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 
23 #include "core/cbytearray.h"
24 #include "core/cbase64.h"
25 #include "core/cnetaddr.h"
26 #include "core/ciconv.h"
27 
28 // needed for remote encoding setting
29 #include "cconfig.h"
30 
31 // parsed messages
32 #define DC_S_MESSAGE_CHAT 		"<"
33 #define DC_S_MESSAGE_SEARCH 		"$Search "
34 #define DC_S_MESSAGE_MYINFO 		"$MyINFO "
35 #define DC_S_MESSAGE_HELLO 		"$Hello "
36 #define DC_S_MESSAGE_QUIT 		"$Quit "
37 #define DC_S_MESSAGE_NICKLIST 		"$NickList "
38 #define DC_S_MESSAGE_OPLIST 		"$OpList "
39 #define DC_S_MESSAGE_CONNECTTOME 	"$ConnectToMe "
40 #define DC_S_MESSAGE_KEY 		"$Key "
41 #define DC_S_MESSAGE_HUBNAME 		"$HubName "
42 #define DC_S_MESSAGE_LOCK 		"$Lock "
43 #define DC_S_MESSAGE_TO 		"$To: "
44 #define DC_S_MESSAGE_FORCEMOVE 		"$ForceMove "
45 #define DC_S_MESSAGE_REVCONNECTTOME 	"$RevConnectToMe "
46 #define DC_S_MESSAGE_SR 		"$SR "
47 #define DC_S_MESSAGE_MYNICK 		"$MyNick "
48 #define DC_S_MESSAGE_DIRECTION 		"$Direction "
49 #define DC_S_MESSAGE_MAXEDOUT 		"$MaxedOut"	// no free slots
50 #define DC_S_MESSAGE_FILELENGTH 	"$FileLength "	// recv. file
51 #define DC_S_MESSAGE_GET 		"$Get "
52 #define DC_S_MESSAGE_ERROR		"$Error "
53 #define DC_S_MESSAGE_GETLISTLEN		"$GetListLen"
54 #define DC_S_MESSAGE_VALIDATEDENIDE 	"$ValidateDenide"  //hub login failed ...
55 #define DC_S_MESSAGE_HUBISFULL 		"$HubIsFull"
56 #define DC_S_MESSAGE_LISTLEN		"$ListLen "
57 #define DC_S_MESSAGE_SEND		"$Send"
58 #define DC_S_MESSAGE_GETINFO 		"$GetINFO "
59 #define DC_S_MESSAGE_PING 		"$Ping"
60 #define DC_S_MESSAGE_GETPASS 		"$GetPass"
61 #define DC_S_MESSAGE_BADPASS 		"$BadPass"
62 #define DC_S_MESSAGE_LOGEDIN		"$LogedIn"
63 #define DC_S_MESSAGE_CANCEL		"$Cancel"
64 #define DC_S_MESSAGE_CANCELED		"$Canceled"
65 #define DC_S_MESSAGE_SUPPORTS		"$Supports "
66 #define DC_S_MESSAGE_HUB_TOPIC		"$HubTopic "
67 #define DC_S_MESSAGE_GET_NET_INFO	"$GetNetInfo"
68 #define DC_S_MESSAGE_USER_IP		"$UserIP "
69 // ignored messages
70 #define DC_S_MESSAGE_MULTISEARCH	"$MultiSearch "
71 #define DC_S_MESSAGE_USER_COMMAND	"$UserCommand " // ??? ( $UserCommand 0 / $UserCommand 1 Read Help$<%[mynick]> +help&#124;<%[mynick]> -help&#124; )
72 
73 // todo: parse
74 #define DC_S_MESSAGE_AGE 		"age="		// age=NEWS ... ???
75 #define DC_S_EXTRA_DCPLUS		"$DCPlus "
76 
77 #define DC_S_MESSAGE_UGETBLOCK		"$UGetBlock "
78 #define DC_S_MESSAGE_UGETZBLOCK		"$UGetZBlock "
79 // ZLIB compression messages
80 #define DC_S_MESSAGE_GETZBLOCK		"$GetZBlock "
81 #define DC_S_MESSAGE_SENDING		"$Sending "
82 #define DC_S_MESSAGE_FAILED		"$Failed "
83 
84 //ADCGet command and response
85 #define DC_S_MESSAGE_ADCGET		"$ADCGET "
86 #define DC_S_MESSAGE_ADCSND		"$ADCSND "
87 
88 // ZPipe message - just $ZOn|
89 // Although CMessageHandler may be able to parse the $ZOn| itself
90 // it can not handle any compressed data so there's no point
91 // parsing it, CClient already found it and can deal with it itself
92 #define DC_S_MESSAGE_ZON		"$ZOn"
93 
CMessageHandler(CString remote)94 CMessageHandler::CMessageHandler( CString remote )
95 {
96 	CString to = "UTF-8";
97 
98 	if ( CConfig::Instance() != 0 )
99 	{
100 		to = CConfig::Instance()->GetLocalEncoding();
101 		if ( remote.IsEmpty() )
102 		{
103 			remote = CConfig::Instance()->GetRemoteEncoding();
104 		}
105 	}
106 
107 	m_pRemoteToLocal = new CIconv( remote, to );
108 	m_pUTF8ToLocal = new CIconv( "UTF-8", to );
109 }
110 
~CMessageHandler()111 CMessageHandler::~CMessageHandler()
112 {
113 	delete m_pRemoteToLocal;
114 	m_pRemoteToLocal = 0;
115 	delete m_pUTF8ToLocal;
116 	m_pUTF8ToLocal = 0;
117 }
118 
GetContent(const CString sMessage,const CString * sData,CString & sContent)119 bool CMessageHandler::GetContent( const CString sMessage, const CString * sData, CString & sContent )
120 {
121 	if ( sData->StartsWith(sMessage) )
122 	{
123 		sContent = sData->Mid(sMessage.Length(),sData->Length()-sMessage.Length());
124 		return true;
125 	}
126 
127 	return false;
128 }
129 
130 /** */
Parse(const CString * sMessage,int & pointer,CDCMessage ** Object)131 eDCMessage CMessageHandler::Parse( const CString * sMessage, int & pointer, CDCMessage ** Object  )
132 {
133 	CString t;
134 	CString sContent;
135 	int old_index,index;
136 
137 	old_index = index = pointer;
138 
139 	*Object = 0;
140 
141 	index = sMessage->Find('|',index);
142 
143 	if ( index >= 0 )
144 	{
145 		pointer = index+1;
146 
147 		t = sMessage->Mid(old_index,index-old_index);
148 
149 		if ( t.IsEmpty() )
150 		{
151 			if ( old_index != index )
152 			{
153 				printf("!!!!!!! PARSER ERROR index: %d %d\n",old_index,index);
154 				printf("%s\n",sMessage->Data());
155 			}
156 			return DC_MESSAGE_UNKNOWN;
157 		}
158 
159 		/*
160 		 * Commands that you get more often should be higher in the if statement.
161 		 * Main change was moving ADCGET / ADCSND towards the top of the list, which
162 		 * is more important now DC++ does segmented downloading.
163 		 */
164 		// check chat
165 		/* well '<' != '$' so "check another chat" can catch it */
166 		/* if ( t.Data()[0] == '<' )
167 		{
168 			sContent = t;
169 
170 			*Object  = ParseChat(sContent);
171 
172 			return DC_MESSAGE_CHAT;
173 		} */
174 		// check another chat
175 		if ( t.Data()[0] != '$' )
176 		{
177 			sContent = t;
178 
179 			*Object  = ParseChat(sContent);
180 
181 			return DC_MESSAGE_CHAT;
182 		}
183 		else if ( GetContent(DC_S_MESSAGE_SEARCH,&t,sContent) )
184 		{
185 			*Object = ParseSearch(sContent);
186 
187 			return DC_MESSAGE_SEARCH_FILE;
188 		}
189 		else if ( GetContent(DC_S_MESSAGE_MYINFO,&t,sContent) )
190 		{
191 			*Object  = ParseMyInfo(sContent);
192 
193 			return DC_MESSAGE_MYINFO;
194 		}
195 		else if ( GetContent(DC_S_MESSAGE_SR,&t,sContent) )
196 		{
197 			*Object = ParseSearchResult(sContent);
198 
199 			return DC_MESSAGE_SEARCHRESULT;
200 		}
201 		else if ( GetContent(DC_S_MESSAGE_ADCGET,&t,sContent) )
202 		{
203 			*Object = ParseADCGet(sContent);
204 
205 			return DC_MESSAGE_ADCGET;
206 		}
207 		else if ( GetContent(DC_S_MESSAGE_ADCSND,&t,sContent) )
208 		{
209 			*Object = ParseADCSnd(sContent);
210 
211 			return DC_MESSAGE_ADCSND;
212 		}
213 		else if ( GetContent(DC_S_MESSAGE_HELLO,&t,sContent) )
214 		{
215 			*Object  = ParseHello(sContent);
216 
217 			return DC_MESSAGE_HELLO;
218 		}
219 		else if ( GetContent(DC_S_MESSAGE_QUIT,&t,sContent) )
220 		{
221 			*Object  = ParseQuit(sContent);
222 
223 			return DC_MESSAGE_QUIT;
224 		}
225 		else if ( GetContent(DC_S_MESSAGE_NICKLIST,&t,sContent) )
226 		{
227 			*Object = ParseNickList(sContent);
228 
229 			return DC_MESSAGE_NICKLIST;
230 		}
231 		else if ( GetContent(DC_S_MESSAGE_OPLIST,&t,sContent) )
232 		{
233 			*Object = ParseOpList(sContent);
234 
235 			return DC_MESSAGE_OPLIST;
236 		}
237 		else if ( GetContent(DC_S_MESSAGE_SUPPORTS,&t,sContent) )
238 		{
239 			*Object = ParseSupports(sContent);
240 
241 			return DC_MESSAGE_SUPPORTS;
242 		}
243 		else if ( GetContent(DC_S_MESSAGE_CONNECTTOME,&t,sContent) )
244 		{
245 			*Object  = ParseConnectToMe(sContent);
246 
247 			return DC_MESSAGE_CONNECTTOME;
248 		}
249 		else if ( GetContent(DC_S_MESSAGE_REVCONNECTTOME,&t,sContent) )
250 		{
251 			*Object  = ParseRevConnectToMe(sContent);
252 
253 			return DC_MESSAGE_REVCONNECTTOME;
254 		}
255 		else if ( GetContent(DC_S_MESSAGE_KEY,&t,sContent) )
256 		{
257 			*Object = new CMessageKey();
258 
259 			return DC_MESSAGE_KEY;
260 		}
261 		else if ( GetContent(DC_S_MESSAGE_HUBNAME,&t,sContent) )
262 		{
263 			*Object  = ParseHubName(sContent);
264 
265 			return DC_MESSAGE_HUBNAME;
266 		}
267 		else if ( GetContent(DC_S_MESSAGE_LOCK,&t,sContent) )
268 		{
269 			*Object  = ParseLock(sContent);
270 
271 			return DC_MESSAGE_LOCK;
272 		}
273 		else if ( GetContent(DC_S_MESSAGE_TO,&t,sContent) )
274 		{
275 			*Object  = ParsePrivateChat(sContent);
276 
277 			return DC_MESSAGE_PRIVATECHAT;
278 		}
279 		else if ( GetContent(DC_S_MESSAGE_FORCEMOVE,&t,sContent) )
280 		{
281 			*Object  = ParseForceMove(sContent);
282 
283 			return DC_MESSAGE_FORCEMOVE;
284 		}
285 		else if ( GetContent(DC_S_MESSAGE_MYNICK,&t,sContent) )
286 		{
287 			*Object  = ParseMyNick(sContent);
288 
289 			return DC_MESSAGE_MYNICK;
290 		}
291 		else if ( GetContent(DC_S_MESSAGE_DIRECTION,&t,sContent) )
292 		{
293 			*Object = ParseDirection(sContent);
294 
295 			return DC_MESSAGE_DIRECTION;
296 		}
297 		else if ( GetContent(DC_S_MESSAGE_FILELENGTH,&t,sContent) )
298 		{
299 			*Object = ParseFileLength(sContent);
300 
301 			return DC_MESSAGE_FILELENGTH;
302 		}
303 		else if ( GetContent(DC_S_MESSAGE_LISTLEN,&t,sContent) )
304 		{
305 			*Object = ParseFileLength(sContent);
306 
307 			return DC_MESSAGE_LISTLEN;
308 		}
309 		else if ( GetContent(DC_S_MESSAGE_GET,&t,sContent) )
310 		{
311 			*Object = ParseGet(sContent);
312 
313 			return DC_MESSAGE_GET;
314 		}
315 		else if ( GetContent(DC_S_MESSAGE_UGETBLOCK,&t,sContent) )
316 		{
317 			*Object = ParseUGetBlock(sContent);
318 
319 			return DC_MESSAGE_GET;
320 		}
321 		else if ( GetContent(DC_S_MESSAGE_UGETZBLOCK,&t,sContent) )
322 		{
323 			*Object = ParseUGetZBlock(sContent);
324 
325 			return DC_MESSAGE_GET;
326 		}
327 		else if ( GetContent(DC_S_MESSAGE_ERROR,&t,sContent) )
328 		{
329 			*Object = ParseError(sContent);
330 
331 			return DC_MESSAGE_ERROR;
332 		}
333 		else if ( GetContent(DC_S_MESSAGE_GETINFO,&t,sContent) )
334 		{
335 			*Object = ParseGetInfo(sContent);
336 
337 			return DC_MESSAGE_GETINFO;
338 		}
339 		else if ( GetContent(DC_S_MESSAGE_MAXEDOUT,&t,sContent) )
340 		{
341 			*Object = new CMessageMaxedOut();
342 
343 			return DC_MESSAGE_MAXEDOUT;
344 		}
345 		else if ( GetContent(DC_S_MESSAGE_CANCEL,&t,sContent) )
346 		{
347 			*Object = new CMessageCancel();
348 
349 			return DC_MESSAGE_CANCEL;
350 		}
351 		else if ( GetContent(DC_S_MESSAGE_CANCELED,&t,sContent) )
352 		{
353 			*Object = new CMessageCanceled();
354 
355 			return DC_MESSAGE_CANCELED;
356 		}
357 		else if ( GetContent(DC_S_MESSAGE_SENDING,&t,sContent) )
358 		{
359 			*Object = ParseSending(sContent);
360 
361 			return DC_MESSAGE_SENDING;
362 		}
363 		else if ( GetContent(DC_S_MESSAGE_SEND,&t,sContent) )
364 		{
365 			*Object = new CMessageSend();
366 
367 			return DC_MESSAGE_SEND;
368 		}
369 		else if ( GetContent(DC_S_MESSAGE_GETLISTLEN,&t,sContent) )
370 		{
371 			*Object = new CMessageGetListLen();
372 
373 			return DC_MESSAGE_GETLISTLEN;
374 		}
375 		else if ( GetContent(DC_S_MESSAGE_VALIDATEDENIDE,&t,sContent) )
376 		{
377 			*Object = new CMessageValidateDenide();
378 
379 			return DC_MESSAGE_VALIDATEDENIDE;
380 		}
381 		else if ( GetContent(DC_S_MESSAGE_HUBISFULL,&t,sContent) )
382 		{
383 			*Object = new CMessageHubIsFull();
384 
385 			return DC_MESSAGE_HUBISFULL;
386 		}
387 		else if ( GetContent(DC_S_MESSAGE_PING,&t,sContent) )
388 		{
389 			*Object = new CMessagePing();
390 
391 			return DC_MESSAGE_PING;
392 		}
393 		else if ( GetContent(DC_S_MESSAGE_GETPASS,&t,sContent) )
394 		{
395 			*Object = new CMessageGetPass();
396 
397 			return DC_MESSAGE_GETPASS;
398 		}
399 		else if ( GetContent(DC_S_MESSAGE_BADPASS,&t,sContent) )
400 		{
401 			*Object = new CMessageBadPass();
402 
403 			return DC_MESSAGE_BADPASS;
404 		}
405 		else if ( GetContent(DC_S_MESSAGE_LOGEDIN,&t,sContent) )
406 		{
407 			*Object = ParseLogedIn(sContent);
408 
409 			return DC_MESSAGE_LOGEDIN;
410 		}
411 		else if ( GetContent(DC_S_MESSAGE_HUB_TOPIC,&t,sContent) )
412 		{
413 			*Object = ParseHubTopic(sContent);
414 
415 			return DC_MESSAGE_HUB_TOPIC;
416 		}
417 		else if ( GetContent(DC_S_MESSAGE_GET_NET_INFO,&t,sContent) )
418 		{
419 			*Object = new CMessageGetNetInfo();
420 
421 			return DC_MESSAGE_GET_NET_INFO;
422 		}
423 		else if ( GetContent(DC_S_MESSAGE_USER_COMMAND,&t,sContent) )
424 		{
425 			*Object = ParseUserCommand(sContent);
426 
427 			return DC_MESSAGE_USER_COMMAND;
428 		}
429 		else if ( GetContent(DC_S_MESSAGE_GETZBLOCK,&t,sContent) )
430 		{
431 			*Object = ParseGetZBlock(sContent);
432 
433 			return DC_MESSAGE_GET;
434 		}
435 		else if ( GetContent(DC_S_MESSAGE_FAILED,&t,sContent) )
436 		{
437 			*Object = ParseError(sContent);
438 
439 			return DC_MESSAGE_ERROR;
440 		}
441 		else if ( GetContent(DC_S_MESSAGE_USER_IP,&t,sContent) )
442 		{
443 			*Object = ParseUserIP(sContent);
444 
445 			return DC_MESSAGE_USERIP;
446 		}
447 		else
448 		{
449 			printf("!!!!!!!!!!!!!! unknown start ");
450 			printf("index: %d %d!!!!!!!!!!!!!!\n",old_index,index);
451 			printf("%s\n",t.Data());
452 			printf("!!!!!!!!!!!!!! unknown end !!!!!!!!!!!!!!\n");
453 			return DC_MESSAGE_UNKNOWN;
454 		}
455 	}
456 	else
457 	{
458 //		printf("%s\n",sMessage.Data());
459 	}
460 
461 	return DC_MESSAGE_PARSE_ERROR;
462 }
463 
464 /** */
ParseLock(const CString & sContent)465 CDCMessage * CMessageHandler::ParseLock( const CString & sContent )
466 {
467 	CMessageLock * msg = new CMessageLock();
468 
469 	int i,i1;
470 
471 	i = sContent.Find(" Pk=");
472 
473 	// lock without pk
474 	if ( i < 0 )
475 	{
476 		msg->m_sData = sContent;
477 	}
478 	else
479 	{
480 		msg->m_sData = sContent.Left(i);
481 		msg->m_sPK   = sContent.Mid(i+4,sContent.Length()-i-4);
482 	}
483 
484 //	printf("TR: '%s' '%s'\n",msg->m_sData.Data(),msg->m_sPK.Data());
485 
486 	if ( msg->m_sData.StartsWith("EXTENDEDPROTOCOL",16) )
487 	{
488 		msg->m_bExtProtocol = true;
489 	}
490 
491 	// DC++ client
492 	if ( msg->m_sPK.StartsWith("DCPLUSPLUS",10) )
493 	{
494 		msg->m_eClientVersion = eucvDCPP;
495 
496 		if ( (i = msg->m_sPK.Find("ABC")) != -1 )
497 		{
498 			msg->m_sVersionString = msg->m_sPK.Mid(10,i-10);
499 		}
500 	}
501 	// DC++H Hub
502 	else if ( msg->m_sPK.StartsWith("DCHUBPLUSPLUS",13) )
503 	{
504 		msg->m_eClientVersion = eucvDCHPP;
505 
506 		if ( (i = msg->m_sPK.Find("ABC")) != -1 )
507 		{
508 			msg->m_sVersionString = msg->m_sPK.Mid(13,i-13);
509 		}
510 	}
511 	// PtokaX Hub
512 	else if ( msg->m_sPK.Left(6).ToUpper() == "PTOKAX" )
513 	{
514 		msg->m_eClientVersion = eucvPTOKAX;
515 	}
516 	// ZPoc Hub - removed typoed CHRISITAN,
517 	// apparently it could also be ZDCROOMSERVERAABC but i doubt anyone cares
518 	else if ( msg->m_sPK.StartsWith("ZPOC",4) )
519 	{
520 		msg->m_eClientVersion = eucvZPOC;
521 	}
522 	// opendcd Hub
523 	else if ( msg->m_sPK.StartsWith("opendcd",7) )
524 	{
525 		msg->m_eClientVersion = eucvOPENDCD;
526 	}
527 	// dclib based valknut
528 	else if ( msg->m_sPK.StartsWith("DCGUI",5) )
529 	{
530 		msg->m_eClientVersion = eucvDCGUI;
531 
532 		if ( (i = msg->m_sPK.Find("ABC")) != -1 )
533 		{
534 			msg->m_sVersionString = msg->m_sPK.Mid(5,i-5);
535 		}
536 	}
537 	// microdc client
538 	else if ( msg->m_sPK.StartsWith("MICRODC",7) )
539 	{
540 		msg->m_eClientVersion = eucvMICRODC;
541 	}
542 	// shakespeer client
543 	else if ( msg->m_sPK.StartsWith("ShakesPeer",10) )
544 	{
545 		msg->m_eClientVersion = eucvSHAKESPEER;
546 
547 		if ( (i = msg->m_sPK.Find("ABC")) != -1 )
548 		{
549 			msg->m_sVersionString = msg->m_sPK.Mid(10,i-10);
550 		}
551 	}
552 
553 	if ( msg->m_sVersionString.NotEmpty() )
554 	{
555 		if ( (i=msg->m_sVersionString.Find('.')) != -1 )
556 		{
557 			msg->m_nVersionMajor = msg->m_sVersionString.Mid(0,i).asINT();
558 			i++;
559 			if ( (i1=msg->m_sVersionString.Find('.',i)) != -1 )
560 			{
561 				msg->m_nVersionMinor = msg->m_sVersionString.Mid(i,msg->m_sVersionString.Length()-i1).asINT();
562 				i=i1+1;
563 				msg->m_nVersionPatch = msg->m_sVersionString.Mid(i,msg->m_sVersionString.Length()-i).asINT();
564 			}
565 			else
566 			{
567 				msg->m_nVersionMinor = msg->m_sVersionString.Mid(i,msg->m_sVersionString.Length()-i).asINT();
568 			}
569 		}
570 	}
571 
572 	return msg;
573 }
574 
575 /** */
ParseHello(const CString & sContent)576 CDCMessage * CMessageHandler::ParseHello( const CString & sContent )
577 {
578 	CMessageHello * msg = new CMessageHello();
579 
580 	msg->m_sNick = m_pRemoteToLocal->encode(sContent);
581 
582 	return msg;
583 }
584 
585 /** */
ParseMyNick(const CString & sContent)586 CDCMessage * CMessageHandler::ParseMyNick( const CString & sContent )
587 {
588 	CMessageMyNick * msg = new CMessageMyNick();
589 
590 	msg->m_sNick = m_pRemoteToLocal->encode(sContent);
591 
592 	return msg;
593 }
594 
595 /** */
ParseChat(const CString & sContent)596 CDCMessage * CMessageHandler::ParseChat( const CString & sContent )
597 {
598 	CMessageChat * msg = new CMessageChat();
599 
600 	int i=-1,i1=-1;
601 
602 	if ( (i=sContent.Find('<')) == 0 )
603 		i1 = sContent.Find('>',i+1);
604 
605 	if ( (i != -1) && (i1 != -1) )
606 	{
607 		msg->m_sNick    = m_pRemoteToLocal->encode(sContent.Mid(i+1,i1-1));
608 		// check if after the '>' a space
609 		if ( sContent.Data()[i1+1] == ' ' )
610 			i1++;
611 
612 		msg->m_sMessage = m_pRemoteToLocal->encode(sContent.Mid(i1+1,sContent.Length()-i1-1));
613 	}
614 	else
615 	{
616 		// no < nick > found ... use complete message
617 		msg->m_sMessage = m_pRemoteToLocal->encode(sContent);
618 	}
619 
620 	// reconvert dcproto chars
621 	msg->m_sMessage = msg->m_sMessage.Replace( "&#36;", "$" );
622 	msg->m_sMessage = msg->m_sMessage.Replace( "&#124;", "|" );
623 
624 	return msg;
625 }
626 
627 /** */
ParseMyInfo(const CString & sContent)628 CDCMessage * CMessageHandler::ParseMyInfo( const CString & sContent )
629 {
630 	/* $MyINFO $ALL xyzzy desc<DCGUI V:0.3.19svn,M:A,H:1/0/0,S:2>$ $DSL$ejs1920@yahoo.co.uk$35036485563$| */
631 	/* $MyINFO $ALL strongdc_test desc<StrgDC++ V:2.21,M:A,H:1/0/0,S:2>$ $0.005$email$1123919289$| */
632 	CMessageMyInfo * msg=0;
633 	CString s;
634 	int i,i1,i2,i3,i4,i5,i6;
635 
636 	// dest e.g. $ALL
637 	if ( (i=sContent.Find(' ')) < 0 )
638 		return 0;
639 
640 	if ( (i1=sContent.Find(' ',i+1)) < 0 )
641 		return 0;
642 
643 	if ( (i2=sContent.Find('$',i1+1)) < 0 )
644 		return 0;
645 
646 	if ( (i3=sContent.Find('$',i2+1)) < 0 )
647 		return 0;
648 
649 	if ( (i4=sContent.Find('$',i3+1)) < 0 )
650 		return 0;
651 
652 	if ( (i5=sContent.Find('$',i4+1)) < 0 )
653 		return 0;
654 
655 	if ( (i6=sContent.Find('$',i5+1)) < 0 )
656 		return 0;
657 
658 	msg = new CMessageMyInfo();
659 
660 	msg->m_sNick    = m_pRemoteToLocal->encode(sContent.Mid(i +1,i1-i -1));
661 	msg->m_sUnknown = m_pRemoteToLocal->encode(sContent.Mid(i2+1,i3-i2-1));
662 
663 	// check user mode
664 	if ( (i4-i3-1) > 0 )
665 	{
666 		const char c = sContent.Data()[i4-1];
667 
668 		if ( c & emsfNormal )
669 		{
670 			msg->m_eAwayMode = euamNORMAL;
671 		}
672 		else if ( c & emsfAway )
673 		{
674 			msg->m_eAwayMode = euamAWAY;
675 		}
676 
677 		if ( c & emsfServer )
678 		{
679 			msg->m_bServerFlag = true;
680 		}
681 
682 		if ( c & emsfFireball )
683 		{
684 			msg->m_bFireballFlag = true;
685 		}
686 
687 		if ( c & emsfTLS )
688 		{
689 			msg->m_bTLSFlag = true;
690 		}
691 	}
692 
693 	s = sContent.Mid(i3+1,i4-i3-2);
694 
695 	if ( s == "28.8Kbps" )
696 		msg->m_eUserSpeed = eus288KBPS;
697 	else if ( s == "33.6Kbps" )
698 		msg->m_eUserSpeed = eus288KBPS;
699 	else if ( s == "56Kbps" )
700 		msg->m_eUserSpeed = eus56KBPS;
701 	else if ( s == "Modem" )
702 		msg->m_eUserSpeed = eusMODEM;
703 	else if ( s == "ISDN" )
704 		msg->m_eUserSpeed = eusISDN;
705 	else if ( s == "DSL" )
706 		msg->m_eUserSpeed = eusDSL;
707 	else if ( s == "Satellite" )
708 		msg->m_eUserSpeed = eusSATELLITE;
709 	else if ( s == "Cable" )
710 		msg->m_eUserSpeed = eusCABLE;
711 	else if ( s == "LAN(T1)" )
712 		msg->m_eUserSpeed = eusLANT1;
713 	else if ( s == "LAN(T3)" )
714 		msg->m_eUserSpeed = eusLANT3;
715 	else if ( s == "Wireless" )
716 		msg->m_eUserSpeed = eusWIRELESS;
717 	else if ( s == "Microwave" )
718 		msg->m_eUserSpeed = eusMICROWAVE;
719 	else if ( s == "0.005" )
720 		msg->m_eUserSpeed = eus0005;
721 	else if ( s == "0.01" )
722 		msg->m_eUserSpeed = eus001;
723 	else if ( s == "0.02" )
724 		msg->m_eUserSpeed = eus002;
725 	else if ( s == "0.05" )
726 		msg->m_eUserSpeed = eus005;
727 	else if ( s == "0.1" )
728 		msg->m_eUserSpeed = eus01;
729 	else if ( s == "0.2" )
730 		msg->m_eUserSpeed = eus02;
731 	else if ( s == "0.5" )
732 		msg->m_eUserSpeed = eus05;
733 	else if ( s == "1" )
734 		msg->m_eUserSpeed = eus1;
735 	else if ( s == "2" )
736 		msg->m_eUserSpeed = eus2;
737 	else if ( s == "5" )
738 		msg->m_eUserSpeed = eus5;
739 	else if ( s == "10" )
740 		msg->m_eUserSpeed = eus10;
741 	else if ( s == "20" )
742 		msg->m_eUserSpeed = eus20;
743 	else if ( s == "50" )
744 		msg->m_eUserSpeed = eus50;
745 	else if ( s == "100" )
746 		msg->m_eUserSpeed = eus100;
747 	else if ( s == "1000" )
748 		msg->m_eUserSpeed = eus1000;
749 	else
750 		msg->m_eUserSpeed = eusUNKNOWN;
751 
752 	msg->m_sUserSpeed = s;
753 	msg->m_sEMail = m_pRemoteToLocal->encode(sContent.Mid(i4+1,i5-i4-1));
754 
755 	s = sContent.Mid(i5+1,i6-i5-1);
756 	msg->m_nShared = s.asULL();
757 
758 	// parse comment
759 	s = sContent.Mid(i1+1,i2-i1-1);
760 
761 	// find version start tag
762 	if ( (i=s.FindRev("<++ ")) != -1 )
763 		msg->m_eClientVersion = eucvDCPP;
764 	else if ( (i=s.FindRev("<DCGUI ")) != -1 )
765 		msg->m_eClientVersion = eucvDCGUI;
766 	else if ( (i=s.FindRev("<DCTC ")) != -1 )
767 		msg->m_eClientVersion = eucvDCTC;
768 	else if ( (i=s.FindRev("<DC ")) != -1 )
769 		msg->m_eClientVersion = eucvNMDC;
770 	else if ( (i=s.FindRev("<QuickDC ")) != -1 )
771 		msg->m_eClientVersion = eucvQUICKDC;
772 	else if ( (i=s.FindRev("<oDC ")) != -1 )
773 		msg->m_eClientVersion = eucvOPERADC;
774 	else if ( (i=s.FindRev("<SdDC++ ")) != -1 )
775 		msg->m_eClientVersion = eucvSDDC;
776 	else if ( (i=s.FindRev("<StrgDC++ ")) != -1 )
777 		msg->m_eClientVersion = eucvSTRGDCPP;
778 	else if ( (i=s.FindRev("<RMDC++ ")) != -1 )
779 		msg->m_eClientVersion = eucvRMDC;
780 	else if ( (i=s.FindRev("<DC:PRO ")) != -1 )
781 		msg->m_eClientVersion = eucvDCPRO;
782 	else if ( (i=s.FindRev("<iDC")) != -1 )
783 		msg->m_eClientVersion = eucvIDC;
784 	else if ( (i=s.FindRev("<PerlDC")) != -1 )
785 		msg->m_eClientVersion = eucvPERLDC;
786 	else if ( (i=s.FindRev("<microdc")) != -1 )
787 		msg->m_eClientVersion = eucvMICRODC;
788 	else if ( (i=s.FindRev("<SP")) != -1 )
789 		msg->m_eClientVersion = eucvSHAKESPEER;
790 	else if ( (i=s.FindRev("<")) != -1 )
791 		msg->m_eClientVersion = eucvUNKNOWN;
792 	else
793 		msg->m_eClientVersion = eucvNONE;
794 
795 	msg->m_eClientMode = ecmPASSIVE;
796 
797 	// find version end tag
798 	if ( (i!=-1) && ((i1=s.Find('>',i)) != -1) )
799 	{
800 		msg->m_sComment    = m_pRemoteToLocal->encode(s.Left(i));
801 		msg->m_sVerComment = s.Mid(i,i1-i+1);
802 
803 		// try to find some default tags for unknown clients
804 		if ( msg->m_eClientVersion == eucvUNKNOWN )
805 		{
806 			if ( (msg->m_sVerComment.Find("V:") == -1) ||
807 			     (msg->m_sVerComment.Find("M:") == -1) )
808 			{
809 				msg->m_eClientVersion = eucvNONE;
810 			}
811 		}
812 
813 		if ( msg->m_eClientVersion != eucvNONE )
814 		{
815 			// search for the active tag
816 			// A: active, P: passive 5: socks5
817 			if ( msg->m_sVerComment.Find("M:A") != -1 )
818 			{
819 				msg->m_eClientMode = ecmACTIVE;
820 			}
821 		}
822 	}
823 
824 	// reset values
825 	if ( msg->m_eClientVersion == eucvNONE )
826 	{
827 		msg->m_sComment    = m_pRemoteToLocal->encode(s);
828 		msg->m_sVerComment.Empty();
829 	}
830 
831 	// set myinfo valid flag
832 	msg->m_bValid = true;
833 
834 	return msg;
835 }
836 
837 /** */
ParseConnectToMe(const CString & sContent)838 CDCMessage * CMessageHandler::ParseConnectToMe( const CString & sContent )
839 {
840 	CMessageConnectToMe * msg=0;
841 	CString s;
842 
843 	int i,i1;
844 
845 	if ( (i=sContent.Find(' ')) < 0 )
846 	{
847 		return 0;
848 	}
849 
850 	if ( (i1=sContent.Find(':',i+1)) < 0 )
851 	{
852 		return 0;
853 	}
854 
855 	msg = new CMessageConnectToMe();
856 
857 	msg->m_sNick = m_pRemoteToLocal->encode(sContent.Mid(0,i));
858 	msg->m_sHost = sContent.Mid(i+1,i1-i-1);
859 
860 	/* connect using TLS specified by 'S' appended to port */
861 	if ( sContent.Data()[sContent.Length()-1] == 'S' )
862 	{
863 		msg->m_bCrypto = true;
864 		s = sContent.Mid(i1+1,sContent.Length()-i1-2);
865 	}
866 	else
867 	{
868 		/* m_bCrypto set to false in CMessageConnectToMe constructor */
869 		s = sContent.Mid(i1+1,sContent.Length()-i1-1);
870 	}
871 
872 	if ( s.IsEmpty() )
873 	{
874 		msg->m_nPort = 411;
875 	}
876 	else
877 	{
878 		msg->m_nPort = s.asINT();
879 
880 		// fix negative ports
881 		if ( msg->m_nPort < 0 )
882 			msg->m_nPort += 65536;
883 	}
884 
885 	return msg;
886 }
887 
888 /** */
ParseRevConnectToMe(const CString & sContent)889 CDCMessage * CMessageHandler::ParseRevConnectToMe( const CString & sContent )
890 {
891 	CMessageRevConnectToMe * msg=0;
892 
893 	int i;
894 
895 	if ( (i=sContent.Find(' ')) < 0 )
896 	{
897 		return 0;
898 	}
899 
900 	msg = new CMessageRevConnectToMe();
901 
902 	msg->m_sDstNick = m_pRemoteToLocal->encode(sContent.Mid(0,i));
903 	msg->m_sNick    = m_pRemoteToLocal->encode(sContent.Mid(i+1,sContent.Length()-i-1));
904 
905 	return msg;
906 }
907 
908 /** */
ParseNickList(const CString & sContent)909 CDCMessage * CMessageHandler::ParseNickList( const CString & sContent )
910 {
911 	CMessageNickList * msg = new CMessageNickList();
912 	int i = 0, i1 = 0;
913 
914 	while ( (i=sContent.Find('$',i)) >= 0 )
915 	{
916 		msg->m_NickList.Add(new CString(m_pRemoteToLocal->encode(sContent.Mid(i1,i-i1))));
917 
918 		i+=2;
919 		i1=i;
920 	}
921 
922 	return msg;
923 }
924 
925 /** */
ParseOpList(const CString & sContent)926 CDCMessage * CMessageHandler::ParseOpList( const CString & sContent )
927 {
928 	CMessageOpList * msg = new CMessageOpList();
929 	int i = 0, i1 = 0;
930 
931 	while ( (i=sContent.Find('$',i)) >= 0 )
932 	{
933 		msg->m_NickList.Add(new CString(m_pRemoteToLocal->encode(sContent.Mid(i1,i-i1))));
934 
935 		i+=2;
936 		i1=i;
937 	}
938 
939 	return msg;
940 }
941 
942 /** */
ParseQuit(const CString & sContent)943 CDCMessage * CMessageHandler::ParseQuit( const CString & sContent )
944 {
945 	CMessageQuit * msg = new CMessageQuit();
946 
947 	msg->m_sNick = m_pRemoteToLocal->encode(sContent);
948 
949 	return msg;
950 }
951 
952 /** */
ParseSearch(const CString & sContent)953 CDCMessage * CMessageHandler::ParseSearch( const CString & sContent )
954 {
955 	CMessageSearchFile * msg=0;
956 
957 	CString s,s1;
958 	int t,i,i1,i2,i3,i4,i5,i6;
959 
960 //	printf("Entering PARSESEARCH\n");
961 	if ( (i=sContent.Find(' ')) < 0 )
962 		return 0;
963 
964 	if ( (i1=sContent.Find('?',i+1)) < 0 )
965 		return 0;
966 
967 	if ( (i2=sContent.Find('?',i1+1)) < 0 )
968 		return 0;
969 
970 	if ( (i3=sContent.Find('?',i2+1)) < 0 )
971 		return 0;
972 
973 	if ( (i4=sContent.Find('?',i3+1)) < 0 )
974 		return 0;
975 
976 	s = sContent.Left(i);
977 
978 	if ( (i5 = s.Find(':')) < 0 )
979 	{
980 		return 0;
981 	}
982 
983 	msg = new CMessageSearchFile();
984 
985 	s1 = s.Left(i5+1);
986 
987 	if ( s1 == "Hub:" )
988 	{
989 		msg->m_bLocal  = true;
990 		msg->m_sSource = m_pRemoteToLocal->encode(s.Mid(i5+1,s.Length()-i5-1));
991 	}
992 	else
993 	{
994 		// parse the host string
995 		msg->m_bLocal  = false;
996 
997 		i6 = s.Find(':');
998 
999 		if ( i6 > 0 )
1000 		{
1001 			s1 = s.Mid(i6+1,s.Length()-i6-1);
1002 		}
1003 		else
1004 		{
1005 			s1.Empty();
1006 		}
1007 
1008 		if ( (i6 < 0) || (s1.IsEmpty()) )
1009 		{
1010 			msg->m_sSource = s;
1011 			msg->m_nPort   = 411;
1012 		}
1013 		else
1014 		{
1015 			msg->m_sSource = s.Mid(0,i6);
1016 			msg->m_nPort   = s1.asINT();
1017 
1018 			// fix negative ports
1019 			if ( msg->m_nPort < 0 )
1020 				msg->m_nPort += 65536;
1021 		}
1022 	}
1023 
1024 	// sizelimit
1025 	if ( sContent.Mid(i+1,i1-i-1) == "F" )
1026 		msg->m_bSizeLimit = false;
1027 	else
1028 		msg->m_bSizeLimit = true;
1029 
1030 	// at most or at least
1031 	if ( sContent.Mid(i1+1,i2-i1-1) == "F" )
1032 		msg->m_eSizeType = esstATLEAST;
1033 	else
1034 		msg->m_eSizeType = esstATMOST;
1035 
1036 	// size
1037 	s1 = sContent.Mid(i2+1,i3-i2-1);
1038 	msg->m_nSize = s1.asULL();
1039 
1040 	// type
1041 	s1 = sContent.Mid(i3+1,i4-i3-1);
1042 	t = s1.asINT();
1043 
1044 	switch(t)
1045 	{
1046 		case 1:
1047 			msg->m_eFileType = eftALL;
1048 			break;
1049 		case 2:
1050 			msg->m_eFileType = eftMP3;
1051 			break;
1052 		case 3:
1053 			msg->m_eFileType = eftARCHIVE;
1054 			break;
1055 		case 4:
1056 			msg->m_eFileType = eftDOCUMENT;
1057 			break;
1058 		case 5:
1059 			msg->m_eFileType = eftAPPLICATION;
1060 			break;
1061 		case 6:
1062 			msg->m_eFileType = eftPICTURE;
1063 			break;
1064 		case 7:
1065 			msg->m_eFileType = eftVIDEO;
1066 			break;
1067 		case 8:
1068 			msg->m_eFileType = eftFOLDER;
1069 			break;
1070 		case 9:
1071 			msg->m_eFileType = eftHASH;
1072 			break;
1073 		default:
1074 			msg->m_eFileType = eftUNKNOWN;
1075 			break;
1076 	}
1077 
1078 	// the search string
1079 	s = m_pRemoteToLocal->encode(sContent.Mid(i4+1,sContent.Length()-i4-1));
1080 
1081 	if ( msg->m_eFileType == eftHASH )
1082 	{
1083 		s = s.Mid(4);
1084 	}
1085 
1086 	// check if ext proto
1087 	/*
1088 		STRING: EXT<BASE64>
1089 		BASE64: XYEXT:<PROTO>
1090 		X     : PADDING TO EVEN LENGTH
1091 		Y     : UNSIGNED CHAR <> 0
1092 	*/
1093 	msg->m_bExtended = false;
1094 
1095 	if ( (i=s.Find("EXT")) == 0 )
1096 	{
1097 		CByteArray in,out;
1098 
1099 		s1 = s.Mid(i+3,s.Length()-i-3);
1100 
1101 		in.SetSize(0);
1102 		in.Append( (unsigned char*)s1.Data(), s1.Length()+1 );
1103 		i = CBase64::Decode(&out,&in);
1104 		if ( i > 5 )
1105 		{
1106 			s1.Set( (char*)out.Data(), out.Size() );
1107 			i=s1.Find("EXT:");
1108 			if ( (i == 1) || (i==2) )
1109 			{
1110 				printf("Found ext decode: '%s'\n",s1.Data());
1111 				s = s1.Mid(i+4,s1.Length()-i-4);
1112 				msg->m_bExtended = true;
1113 			}
1114 		}
1115 	}
1116 
1117 	s = s.Replace('$'," ");
1118 	s = s.Replace("&#36;","$");
1119 	msg->m_sString = s.Replace("&#124;","|");
1120 
1121 //	printf("Quitting PARSESEARCH\n");
1122 
1123 	return msg;
1124 }
1125 
1126 /** */
ParseSearchResult(const CString & sContent)1127 CDCMessage * CMessageHandler::ParseSearchResult( const CString & sContent )
1128 {
1129 	int i;
1130 
1131 	if ( (i=sContent.Find(0x05)) < 0 )
1132 		return 0;
1133 
1134 	if ( sContent.Find(0x05,i+1) < 0 )
1135 	{
1136 		return ParseSearchResultFolder(sContent);
1137 	}
1138 	else
1139 	{
1140 		return ParseSearchResultFile(sContent);
1141 	}
1142 }
1143 
1144 /**
1145  * $SR <source_nick> <file_name><0x05><file_size> <free_slots>/<total slots><0x05><hub_name> (<hub_ip:port>)|
1146  *                  i           i1               i2                         i3
1147  */
ParseSearchResultFile(const CString & sContent)1148 CDCMessage * CMessageHandler::ParseSearchResultFile( const CString & sContent )
1149 {
1150 	CMessageSearchResult * msg=0;
1151 	CString s;
1152 	int i,i1,i2,i3;
1153 
1154 /*	for(i=0;i<sContent.Length();i++)
1155 		printf("%02X ",sContent.Data()[i]);
1156 	printf("\n");*/
1157 
1158 	if ( (i=sContent.Find(' ')) < 0 )
1159 		return 0;
1160 
1161 	if ( (i1=sContent.Find(0x05,i+1)) < 0 )
1162 		return 0;
1163 
1164 	if ( (i2=sContent.Find(' ',i1+1)) < 0 )
1165 		return 0;
1166 
1167 	if ( (i3=sContent.Find(0x05,i2+1)) < 0 )
1168 		return 0;
1169 
1170 	msg = new CMessageSearchResult();
1171 
1172 	msg->m_sNick = m_pRemoteToLocal->encode(sContent.Mid(0,i));
1173 	msg->m_sFile = m_pRemoteToLocal->encode(sContent.Mid(i+1,i1-i-1));
1174 	s = sContent.Mid(i1+1,i2-i1-1);
1175 	msg->m_nSize = s.asULL();
1176 
1177 	// parse the user slots
1178 	s = sContent.Mid(i2+1,i3-i2-1);
1179 	msg->m_nFreeSlot = 0;
1180 	msg->m_nMaxSlot  = 0;
1181 
1182 	if ( (i1 = s.Find('/')) != -1 )
1183 	{
1184 		msg->m_nFreeSlot = s.Mid(0,i1).asUINT();
1185 		msg->m_nMaxSlot  = s.Mid(i1+1,s.Length()-i1-1).asUINT();
1186 	}
1187 
1188 	s = sContent.Mid(i3+1,sContent.Length()-i3-1);
1189 
1190 	if ( s.NotEmpty() )
1191 	{
1192 		if ( (i1 = s.FindRev(')')) != -1 )
1193 		{
1194 			if ( (i2 = s.FindRev('('),i1-1) != -1 )
1195 			{
1196 				if ( i2 > 0 ) i2--; // remove space " ("
1197 				msg->m_sHubName = m_pRemoteToLocal->encode(s.Mid(0,i2));
1198 				msg->m_sHubHost = s.Mid(i2+2,i1-i2-2);
1199 			}
1200 		}
1201 	}
1202 
1203 	// check negative ports
1204 	CString ip;
1205 	unsigned int port;
1206 
1207 	CNetAddr::ParseHost( msg->m_sHubHost, ip, port );
1208 
1209 	msg->m_sHubHost = ip;
1210 
1211 	if ( port != 0 )
1212 	{
1213 		 msg->m_sHubHost += ':';
1214 		 msg->m_sHubHost += CString::number(port);
1215 	}
1216 
1217 	// parse special content in hubname
1218 	if ( msg->m_sHubName.StartsWith("TTH:",4) )
1219 	{
1220 		// tiger tree hash
1221 		msg->m_sHash = msg->m_sHubName.Mid(4);
1222 		// set dummy hubname
1223 		msg->m_sHubName = msg->m_sHubHost;
1224 	}
1225 
1226 /*	printf("%s\n%s | %s | %s | %s | %s | %s\n",\
1227 		sContent.Data(),
1228 		msg->sNick.Data(),
1229 		msg->sFile.Data(),
1230 		msg->sSize.Data(),
1231 		msg->sSlot.Data(),
1232 		msg->sHubName.Data(),
1233 		msg->sHubHost.Data() );*/
1234 
1235 	msg->m_bFolder = false;
1236 
1237 	return msg;
1238 }
1239 
1240 /**
1241  * $SR <source_nick> <directory_name> <free_slots>/<total_slots><0x05><hub_name> (<hub_ip:port>)|
1242  *                  s1               s2                         i1
1243  */
ParseSearchResultFolder(const CString & sContent)1244 CDCMessage * CMessageHandler::ParseSearchResultFolder( const CString & sContent )
1245 {
1246 	CMessageSearchResult * msg=0;
1247 	CString s;
1248 	int s1,s2,i1,slash,openBracket,closeBracket;
1249 
1250 /*	for(i=0;i<sContent.Length();i++)
1251 		printf("%02X ",sContent.Data()[i]);
1252 	printf("\n");*/
1253 
1254 	if ( (s1=sContent.Find(' ')) < 0 )
1255 		return 0;
1256 
1257 	if ( (i1=sContent.Find(0x05,s1+1)) < 0 )
1258 		return 0;
1259 
1260 	if ( (s2=sContent.FindRev(' ',i1)) < 0 )
1261 		return 0;
1262 
1263 	msg = new CMessageSearchResult();
1264 
1265 	msg->m_sNick = m_pRemoteToLocal->encode(sContent.Mid(0,s1));
1266 	msg->m_sFile = m_pRemoteToLocal->encode(sContent.Mid(s1+1,s2-s1-1));
1267 	msg->m_nSize = 0;
1268 
1269 	// parse the user slots
1270 	s = sContent.Mid(s2+1,i1-s2-1);
1271 	msg->m_nFreeSlot = 0;
1272 	msg->m_nMaxSlot  = 0;
1273 
1274 	if ( (slash = s.Find('/')) != -1 )
1275 	{
1276 		msg->m_nFreeSlot = s.Mid(0,slash).asUINT();
1277 		msg->m_nMaxSlot  = s.Mid(slash+1,s.Length()-slash-1).asUINT();
1278 	}
1279 
1280 	s = sContent.Mid(i1+1,sContent.Length()-i1-1);
1281 
1282 	if ( s.NotEmpty() )
1283 	{
1284 		if ( (closeBracket = s.FindRev(')')) != -1 )
1285 		{
1286 			if ( (openBracket = s.FindRev('('),closeBracket-1) != -1 )
1287 			{
1288 				if ( openBracket > 0 ) openBracket--; // remove space " ("
1289 				msg->m_sHubName = m_pRemoteToLocal->encode(s.Mid(0,openBracket));
1290 				msg->m_sHubHost = s.Mid(openBracket+2,closeBracket-openBracket-2);
1291 			}
1292 		}
1293 	}
1294 
1295 	// check negative ports
1296 	CString ip;
1297 	unsigned int port;
1298 
1299 	CNetAddr::ParseHost( msg->m_sHubHost, ip, port );
1300 
1301 	msg->m_sHubHost = ip;
1302 
1303 	if ( port != 0 )
1304 	{
1305 		 msg->m_sHubHost += ':';
1306 		 msg->m_sHubHost += CString::number(port);
1307 	}
1308 
1309 	// parse special content in hubname
1310 	if ( msg->m_sHubName.StartsWith("TTH:",4) )
1311 	{
1312 		// tiger tree hash
1313 		msg->m_sHash = msg->m_sHubName.Mid(4);
1314 		// set dummy hubname
1315 		msg->m_sHubName = msg->m_sHubHost;
1316 	}
1317 
1318 	/* printf("%s\n%s : %s : %l : %s : %s : %s : %l : %l\n",\
1319 		sContent.Data(),
1320 		msg->m_sNick.Data(),
1321 		msg->m_sFile.Data(),
1322 		msg->m_nSize,
1323 		msg->m_sHubName.Data(),
1324 		msg->m_sHubHost.Data(),
1325 		msg->m_sHash.Data(),
1326 		msg->m_nFreeSlot,
1327 		msg->m_nMaxSlot ); */
1328 
1329 	msg->m_bFolder = true;
1330 
1331 	return msg;
1332 }
1333 
1334 /** */
ParsePrivateChat(const CString & sContent)1335 CDCMessage * CMessageHandler::ParsePrivateChat( const CString & sContent )
1336 {
1337 	/* $To: target nick From: source nick $ <multi src nick> message text| */
1338 	/* "$To: " and "|" are already removed leaving */
1339 	/* target nick From: source nick $ <multi src nick> message text */
1340 
1341 	int p1 = sContent.Find( " From:", 0 );
1342 
1343 	if ( p1 == -1 )
1344 	{
1345 		return 0;
1346 	}
1347 
1348 	int p2 = sContent.Find( '$', p1+6 );
1349 
1350 	if ( p2 == -1 )
1351 	{
1352 		return 0;
1353 	}
1354 
1355 	CMessagePrivateChat * msg = new CMessagePrivateChat();
1356 
1357 	msg->m_sDstNick = m_pRemoteToLocal->encode( sContent.Mid(0,p1) );
1358 	msg->m_sSrcNick = m_pRemoteToLocal->encode( sContent.Mid(p1+7,p2-p1-8) );
1359 
1360 	CString s = sContent.Mid(p2+1,sContent.Length()-p2-1);
1361 
1362 	p1 = s.Find('<');
1363 	p2 = s.Find('>',p1+1);
1364 
1365 	if ( (p1==-1) || (p2==-1) )
1366 	{
1367 		msg->m_sMessage = m_pRemoteToLocal->encode(s);
1368 	}
1369 	else
1370 	{
1371 		msg->m_sMultiSrcNick = m_pRemoteToLocal->encode(s.Mid(p1+1,p2-p1-1));
1372 
1373 		if ( (s.Length() > p2+1) && (s.Data()[p2+1] == ' ') )
1374 		{
1375 			++p2;
1376 		}
1377 
1378 		msg->m_sMessage      = m_pRemoteToLocal->encode(s.Mid(p2+1,s.Length()-p2-1));
1379 	}
1380 
1381 	// reconvert dcproto chars
1382 	msg->m_sMessage = msg->m_sMessage.Replace( "&#36;", "$" );
1383 	msg->m_sMessage = msg->m_sMessage.Replace( "&#124;", "|" );
1384 
1385 /*
1386 	printf("%s\n%s\n%s\n%s\n",\
1387 		sContent.Data(),
1388 		msg->sNick.Data(),
1389 		msg->sFrom.Data(),
1390 		msg->sString.Data() );
1391 */
1392 
1393 	return msg;
1394 }
1395 
1396 /** */
ParseForceMove(const CString & sContent)1397 CDCMessage * CMessageHandler::ParseForceMove( const CString & sContent )
1398 {
1399 	if ( sContent.IsEmpty() )
1400 	{
1401 		return 0;
1402 	}
1403 
1404 	int i = sContent.Find(':');
1405 	CString s;
1406 
1407 	CMessageForceMove * msg = new CMessageForceMove();
1408 
1409 	if ( i > 0 )
1410 	{
1411 		s = sContent.Mid(i+1,sContent.Length()-i-1);
1412 	}
1413 
1414 	if ( (i < 0) || (s.IsEmpty()) )
1415 	{
1416 		msg->m_sHost = sContent;
1417 		msg->m_nPort   = 411;
1418 	}
1419 	else
1420 	{
1421 		msg->m_sHost = sContent.Mid(0,i);
1422 		msg->m_nPort = s.asINT();
1423 
1424 		// fix negative ports
1425 		if ( msg->m_nPort < 0 )
1426 			msg->m_nPort += 65536;
1427 	}
1428 
1429 	return msg;
1430 }
1431 
1432 /** */
ParseDirection(const CString & sContent)1433 CDCMessage * CMessageHandler::ParseDirection( const CString & sContent )
1434 {
1435 	int i;
1436 
1437 	if ( (i=sContent.Find(' ')) < 0 )
1438 		return 0;
1439 
1440 	CMessageDirection * msg = new CMessageDirection();
1441 
1442 	CString s = sContent.Mid(0,i);
1443 
1444 	if ( s == "Upload" )
1445 		msg->m_eDirection = edUPLOAD;
1446 	else if ( s == "Download" )
1447 		msg->m_eDirection = edDOWNLOAD;
1448 	else
1449 		msg->m_eDirection = edNONE;
1450 
1451 	s = sContent.Mid(i+1,sContent.Length()-i-1);
1452 	if ( s.IsEmpty() )
1453 		msg->m_nLevel = 0;
1454 	else
1455 		msg->m_nLevel = s.asINT();
1456 
1457 	return msg;
1458 }
1459 
1460 /** */
ParseFileLength(const CString & sContent)1461 CDCMessage * CMessageHandler::ParseFileLength( const CString & sContent )
1462 {
1463 	CMessageFileLength * msg = new CMessageFileLength();
1464 
1465 	if ( sContent.IsEmpty() )
1466 		msg->m_nFileLength = 0;
1467 	else
1468 		msg->m_nFileLength = sContent.asULL();
1469 
1470 	return msg;
1471 }
1472 
1473 /** */
ParseGet(const CString & sContent)1474 CDCMessage * CMessageHandler::ParseGet( const CString & sContent )
1475 {
1476 	int last,secondlast;
1477 	CString pos, size;
1478 	CMessageGet * msg = 0;
1479 
1480 	// last $ will usually be 1-starting based file position
1481 	// but will be size if using valknut CHUNK extension
1482 	last = sContent.FindRev('$');
1483 
1484 	if ( last < 0 )
1485 	{
1486 		return 0;
1487 	}
1488 
1489 	msg = new CMessageGet();
1490 
1491 	// second last $ may be in the filename
1492 	// but will be file position if using valknut CHUNK extension
1493 	secondlast = sContent.FindRev('$',last-1);
1494 
1495 	if ( secondlast < 0 )
1496 	{
1497 		pos = sContent.Mid(last+1);
1498 		secondlast = last;
1499 	}
1500 	else
1501 	{
1502 		size = sContent.Mid(last+1);
1503 		pos = sContent.Mid(secondlast+1,last-(secondlast+1));
1504 
1505 		if ( pos.asULL() == 0 ) // $Get starts at 1
1506 		{
1507 			pos = size;
1508 			size.Empty();
1509 			secondlast = last;
1510 		}
1511 	}
1512 
1513 	msg->m_sFilename = m_pRemoteToLocal->encode(sContent.Mid(0,secondlast));
1514 
1515 	msg->m_nPos = pos.asULL();
1516 
1517 	if ( size.NotEmpty() )
1518 	{
1519 		msg->m_nSize = size.asULL();
1520 	}
1521 
1522 	//printf( "name=%s pos=%llu size=%llu\n", msg->m_sFilename.Data(), msg->m_nPos, msg->m_nSize );
1523 
1524 	return msg;
1525 }
1526 
1527 /** */
ParseUGetBlock(const CString & sContent)1528 CDCMessage * CMessageHandler::ParseUGetBlock( const CString & sContent )
1529 {
1530 	/* This parser is copied and pasted into ParseGetZBlock */
1531 	int i,i1;
1532 	CString s;
1533 	CMessageGet * msg = new CMessageGet();
1534 
1535 	i = sContent.Find(' ');
1536 	i1= sContent.Find(' ',i+1);
1537 	msg->m_nPos  = sContent.Mid(0,i).asULL();
1538 	msg->m_nSize = sContent.Mid(i+1,i1-i).asULL();
1539 	s = sContent.Mid(i1+1,sContent.Length()-i1-1);
1540 
1541 	/* encode the filename from UTF-8 to local encoding */
1542 	msg->m_sFilename = m_pUTF8ToLocal->encode(s);
1543 	msg->m_bUGet = true;
1544 
1545 	// fix start position
1546 	msg->m_nPos++;
1547 /*
1548 	printf("UGET '%s'\n%llu %llu\n'%s'\n",
1549 		sContent.Data(),
1550 		msg->m_nPos,
1551 		msg->m_nSize,
1552 		msg->m_sFilename.Data());
1553 */
1554 
1555 	return msg;
1556 }
1557 
1558 /** */
ParseUGetZBlock(const CString & sContent)1559 CDCMessage * CMessageHandler::ParseUGetZBlock( const CString & sContent )
1560 {
1561 	CMessageGet * msg = (CMessageGet*) ParseUGetBlock(sContent);
1562 
1563 	msg->m_bZLib = true;
1564 
1565 	return msg;
1566 }
1567 
1568 /** */
ParseError(const CString & sContent)1569 CDCMessage * CMessageHandler::ParseError( const CString & sContent )
1570 {
1571 	CMessageError * msg = new CMessageError();
1572 
1573 	msg->m_sError = m_pRemoteToLocal->encode(sContent);
1574 
1575 	return msg;
1576 }
1577 
1578 /** */
ParseHubName(const CString & sContent)1579 CDCMessage * CMessageHandler::ParseHubName( const CString & sContent )
1580 {
1581 	CMessageHubName * msg = new CMessageHubName();
1582 
1583 	msg->m_sHubName = m_pRemoteToLocal->encode(sContent);
1584 
1585 	return msg;
1586 }
1587 
1588 /** */
ParseGetInfo(const CString & sContent)1589 CDCMessage * CMessageHandler::ParseGetInfo( const CString & sContent )
1590 {
1591 	int i;
1592 
1593 	if ( (i=sContent.Find(' ')) < 0 )
1594 	{
1595 		return 0;
1596 	}
1597 
1598 	CMessageGetInfo * msg = new CMessageGetInfo();
1599 
1600 	msg->m_sDstNick = m_pRemoteToLocal->encode(sContent.Mid(0,i));
1601 	msg->m_sSrcNick = m_pRemoteToLocal->encode(sContent.Mid(i+1,sContent.Length()-i-1));
1602 
1603 	return msg;
1604 }
1605 
1606 /** */
ParseLogedIn(CString sContent)1607 CDCMessage * CMessageHandler::ParseLogedIn( CString sContent )
1608 {
1609 	CMessageLogedIn * msg = new CMessageLogedIn();
1610 
1611 	// remove the space
1612 	if ( sContent.NotEmpty() && (sContent.Data()[0] == ' ') )
1613 	{
1614 		sContent = sContent.Mid(1,sContent.Length()-1);
1615 	}
1616 
1617 	msg->m_sNick = m_pRemoteToLocal->encode(sContent);
1618 
1619 	return msg;
1620 }
1621 
1622 #define DC_SUPPORT_TAG_MINISLOTS	"MiniSlots "
1623 #define DC_SUPPORT_TAG_XMLBZLIST	"XmlBZList "
1624 #define DC_SUPPORT_TAG_ADCGET		"ADCGet "
1625 #define DC_SUPPORT_TAG_TTHL		"TTHL "
1626 #define DC_SUPPORT_TAG_TTHF		"TTHF "
1627 #define DC_SUPPORT_TAG_ZLIG		"ZLIG "
1628 
1629 /* These are obsolete and should not be used. */
1630 #define DC_SUPPORT_TAG_GETZBLOCK	"GetZBlock "
1631 #define DC_SUPPORT_TAG_BZLIST		"BZList "
1632 
1633 /* These are obsolete dclib extensions and should not be used. */
1634 #define DC_SUPPORT_TAG_SSL		"SSL "
1635 #define DC_SUPPORT_TAG_CHUNK		"CHUNK "
1636 
1637 /* These are all ignored - either unused client extensions or hub extensions. */
1638 #define DC_SUPPORT_TAG_GETTESTZBLOCK	"GetTestZBlock "
1639 #define DC_SUPPORT_TAG_USER_CMD		"UserCommand "
1640 #define DC_SUPPORT_TAG_NOGETINFO	"NoGetINFO "
1641 #define DC_SUPPORT_TAG_USERIP		"UserIP "
1642 #define DC_SUPPORT_TAG_USERIP2		"UserIP2 "
1643 #define DC_SUPPORT_TAG_XRULES		"XRules "
1644 #define DC_SUPPORT_TAG_BOTINFO		"BotINFO "
1645 #define DC_SUPPORT_TAG_BOTINFO_2	"BotInfo "
1646 #define DC_SUPPORT_TAG_NOHELLO		"NoHello "
1647 #define DC_SUPPORT_TAG_OPPLUS		"OpPlus "
1648 #define DC_SUPPORT_TAG_MCTO		"MCTo "
1649 #define DC_SUPPORT_TAG_BOTLIST		"BotList "
1650 #define DC_SUPPORT_TAG_CLIENTID		"ClientID "
1651 #define DC_SUPPORT_TAG_SECUREDEXECUTOR	"SecuredExecutor "
1652 #define DC_SUPPORT_TAG_FEED		"Feed "
1653 #define DC_SUPPORT_TAG_ZLINE		"ZLine "
1654 #define DC_SUPPORT_TAG_ZPIPE0		"ZPipe0 "
1655 #define DC_SUPPORT_TAG_CDM		"CDM "
1656 #define DC_SUPPORT_TAG_GETCID		"GetCID "
1657 #define DC_SUPPORT_TAG_BANMSG		"BanMsg "
1658 
1659 /** */
ParseSupports(CString sContent)1660 CDCMessage * CMessageHandler::ParseSupports( CString sContent )
1661 {
1662 	int i = 0, i1 = 0;
1663 	CString s;
1664 
1665 	if ( sContent.Right(1) != " " )
1666 	{
1667 		sContent += ' ';
1668 	}
1669 
1670 	CMessageSupports * msg = new CMessageSupports();
1671 
1672 	msg->m_sContent = sContent;
1673 
1674 	while( (i1=sContent.Find(' ',i)) != -1 )
1675 	{
1676 		++i1;
1677 
1678 		s = sContent.Mid(i,i1-i);
1679 
1680 		if ( s == DC_SUPPORT_TAG_MINISLOTS )
1681 		{
1682 			msg->m_bMiniSlots = true;
1683 		}
1684 		else if ( s == DC_SUPPORT_TAG_XMLBZLIST )
1685 		{
1686 			msg->m_bXMLBZList = true;
1687 		}
1688 		else if ( s == DC_SUPPORT_TAG_ADCGET )
1689 		{
1690 			msg->m_bADCGet = true;
1691 		}
1692 		else if ( s == DC_SUPPORT_TAG_TTHL )
1693 		{
1694 			msg->m_bTTHL = true;
1695 		}
1696 		else if ( s == DC_SUPPORT_TAG_TTHF )
1697 		{
1698 			msg->m_bTTHF = true;
1699 		}
1700 		else if ( s == DC_SUPPORT_TAG_ZLIG )
1701 		{
1702 			msg->m_bZLIG = true;
1703 		}
1704 		else if ( s == DC_SUPPORT_TAG_GETZBLOCK ) /* obsolete */
1705 		{
1706 			msg->m_bZBlock = true;
1707 		}
1708 		else if ( s == DC_SUPPORT_TAG_BZLIST ) /* obsolete */
1709 		{
1710 			msg->m_bBZList = true;
1711 		}
1712 		else if ( s == DC_SUPPORT_TAG_SSL ) /* obsolete dclib specific */
1713 		{
1714 			msg->m_bSSL = true;
1715 		}
1716 		else if ( s == DC_SUPPORT_TAG_CHUNK ) /* obsolete dclib specific */
1717 		{
1718 			msg->m_bChunk = true;
1719 		}
1720 #if 0
1721 		else if ( s == DC_SUPPORT_TAG_GETTESTZBLOCK )
1722 		{
1723 			// ignore
1724 		}
1725 		else if ( s == DC_SUPPORT_TAG_USER_CMD )
1726 		{
1727 			// ignore
1728 		}
1729 		else if ( s == DC_SUPPORT_TAG_NOGETINFO )
1730 		{
1731 			// ignore
1732 		}
1733 		else if ( s == DC_SUPPORT_TAG_USERIP )
1734 		{
1735 			// ignore
1736 		}
1737 		else if ( s == DC_SUPPORT_TAG_USERIP2 )
1738 		{
1739 			// ignore
1740 		}
1741 		else if ( s == DC_SUPPORT_TAG_XRULES )
1742 		{
1743 			// ignore
1744 		}
1745 		else if ( s == DC_SUPPORT_TAG_BOTINFO )
1746 		{
1747 			// ignore
1748 		}
1749 		else if ( s == DC_SUPPORT_TAG_BOTINFO_2 )
1750 		{
1751 			// ignore
1752 		}
1753 		else if ( s == DC_SUPPORT_TAG_NOHELLO )
1754 		{
1755 			// ignore
1756 		}
1757 		else if ( s == DC_SUPPORT_TAG_OPPLUS )
1758 		{
1759 			// ignore
1760 		}
1761 		else if ( s == DC_SUPPORT_TAG_MCTO )
1762 		{
1763 			// ignore
1764 		}
1765 		else if ( s == DC_SUPPORT_TAG_BOTLIST )
1766 		{
1767 			// ignore
1768 		}
1769 		else if ( s == DC_SUPPORT_TAG_CLIENTID )
1770 		{
1771 			// ignore
1772 		}
1773 		else if ( s == DC_SUPPORT_TAG_SECUREDEXECUTOR )
1774 		{
1775 			// ignore
1776 		}
1777 		else if ( s == DC_SUPPORT_TAG_FEED )
1778 		{
1779 			// ignore
1780 		}
1781 		else if ( s == DC_SUPPORT_TAG_ZLINE )
1782 		{
1783 			// ignore
1784 		}
1785 		else if ( s == DC_SUPPORT_TAG_ZPIPE0 )
1786 		{
1787 			// ignore
1788 		}
1789 		else if ( s == DC_SUPPORT_TAG_CDM )
1790 		{
1791 			// ignore
1792 		}
1793 		else if ( s == DC_SUPPORT_TAG_GETCID )
1794 		{
1795 			// ignore
1796 		}
1797 		else if ( s == DC_SUPPORT_TAG_BANMSG )
1798 		{
1799 			// ignore
1800 		}
1801 		else
1802 		{
1803 			printf("Unknown support tag: '%s'\n",s.Data());
1804 		}
1805 
1806 #endif
1807 		i = i1;
1808 	}
1809 
1810 	return msg;
1811 }
1812 
1813 /** */
ParseHubTopic(const CString & sContent)1814 CDCMessage * CMessageHandler::ParseHubTopic( const CString & sContent )
1815 {
1816 	CMessageHubTopic * msg = new CMessageHubTopic();
1817 
1818 	msg->m_sTopic = m_pRemoteToLocal->encode(sContent);
1819 
1820 	return msg;
1821 }
1822 
1823 /** $UserCommand 1 2 Menu\SubMenu\SayHello $<%[mynick]> hello&#124;| */
ParseUserCommand(const CString & sContent)1824 CDCMessage * CMessageHandler::ParseUserCommand( const CString & sContent )
1825 {
1826 	int type = -1;
1827 	int context = -1;
1828 	CString name;
1829 	CString command;
1830 
1831 	int i = sContent.Find(' ');
1832 	if ( i > 0 )
1833 	{
1834 		type = sContent.Mid(0,i).asINT();
1835 		int i2 = sContent.Find(' ',i+1);
1836 		if ( i2 > 0 )
1837 		{
1838 			context = sContent.Mid(i+1,i2-i-1).asINT();
1839 			int i3 = sContent.Find('$',i2+1);
1840 			if ( i3 > 0 )
1841 			{
1842 				name = sContent.Mid(i2+1,i3-i2-1);
1843 				command = sContent.Mid(i3+1);
1844 			}
1845 			else
1846 			{
1847 				name = sContent.Mid(i2+1);
1848 			}
1849 		}
1850 		else
1851 		{
1852 			context = sContent.Mid(i+1).asINT();
1853 		}
1854 	}
1855 	else
1856 	{
1857 		type = sContent.asINT();
1858 	}
1859 
1860 	if ( name.Right(1) == " " )
1861 	{
1862 		name = name.Left(name.Length()-1);
1863 	}
1864 
1865 	name = m_pRemoteToLocal->encode(name);
1866 	command = m_pRemoteToLocal->encode(command);
1867 
1868 	command = command.Replace( "&#36;", "$" );
1869 	command = command.Replace( "&#124;", "|" );
1870 
1871 	// printf("UserCommand type=%d context=%d name='%s' command='%s'\n",type,context,name.Data(),command.Data());
1872 
1873 	CMessageUserCommand * msg = new CMessageUserCommand();
1874 	msg->type = type;
1875 	msg->context = context;
1876 	msg->name = name;
1877 	msg->command = command;
1878 
1879 	return msg;
1880 }
1881 
1882 /** */
ParseGetZBlock(const CString & sContent)1883 CDCMessage * CMessageHandler::ParseGetZBlock( const CString & sContent )
1884 {
1885 	/* This parser is copied and pasted from ParseUGetBlock */
1886 	int i,i1;
1887 	CString s;
1888 	CMessageGet * msg = new CMessageGet();
1889 
1890 	i = sContent.Find(' ');
1891 	i1= sContent.Find(' ',i+1);
1892 	msg->m_nPos  = sContent.Mid(0,i).asULL();
1893 	msg->m_nSize = sContent.Mid(i+1,i1-i).asULL();
1894 	s = sContent.Mid(i1+1,sContent.Length()-i1-1);
1895 
1896 	/* encode the filename from remote to local encoding */
1897 	msg->m_sFilename = m_pRemoteToLocal->encode(s);
1898 	msg->m_bZLib = true;
1899 
1900 	// fix start position
1901 	msg->m_nPos++;
1902 /*
1903 	printf("GETZBLOCK '%s'\n%llu %llu\n'%s'\n",
1904 		sContent.Data(),
1905 		msg->m_nPos,
1906 		msg->m_nSize,
1907 		msg->m_sFilename.Data());
1908 */
1909 
1910 	return msg;
1911 }
1912 
1913 /** */
ParseSending(const CString & sContent)1914 CDCMessage * CMessageHandler::ParseSending( const CString & sContent )
1915 {
1916 	CMessageSending * msg = new CMessageSending();
1917 
1918 	if ( sContent.IsEmpty() )
1919 		msg->m_nLength = 0;
1920 	else
1921 		msg->m_nLength = sContent.asULL();
1922 
1923 	return msg;
1924 }
1925 
1926 /** $ADCGET file TTH/PPUROLR2WSYTGPLCM3KV4V6LJC36SCTFQJFDJKA 0 1154 ZL1| */
ParseADCGet(const CString & sContent)1927 CDCMessage * CMessageHandler::ParseADCGet( const CString & sContent )
1928 {
1929 	//printf("sContent=\"%s\"\n", sContent.Data());
1930 
1931 	CMessageADCGet * msg = new CMessageADCGet();
1932 
1933 	int i = sContent.Find(' ');
1934 	CString s = sContent.Mid(0,i);
1935 	if ( s == "file" )
1936 	{
1937 		msg->m_eADCType = eAdcFile;
1938 	}
1939 	else if ( s == "tthl" )
1940 	{
1941 		msg->m_eADCType = eAdcTTHL;
1942 	}
1943 	else if ( s == "list" )
1944 	{
1945 		msg->m_eADCType = eAdcList;
1946 	}
1947 	else
1948 	{
1949 		delete msg;
1950 		printf("CMessageHandler::ParseADCGet: Unknown ADCGET type '%s'\n",s.Data());
1951 		return 0;
1952 	}
1953 
1954 	s = sContent.Mid(i+1,sContent.Length()-i-1);
1955 
1956 	if (s.Right(4).ToUpper() == " ZL1")
1957 	{
1958 		msg->m_bZlib = true;
1959 		s = s.Mid(0, s.Length() - 4);
1960 	}
1961 	else
1962 	{
1963 		msg->m_bZlib = false;
1964 	}
1965 
1966 	i = s.FindRev(' ');
1967 	msg->m_nSize = s.Mid(i, s.Length() - i).asLONGLONG();
1968 	s = s.Mid(0, i);
1969 
1970 	i = s.FindRev(' ');
1971 	msg->m_nPos = s.Mid(i, s.Length() - i).asULL();
1972 	s = s.Mid(0, i);
1973 
1974 	if ( s.StartsWith("TTH/",4) )
1975 	{
1976 		msg->m_sTTH = s.Mid(4);
1977 	}
1978 	else
1979 	{
1980 		// unescape spaces
1981 		s = s.Replace( "\\ ", " " );
1982 		msg->m_sFile = m_pUTF8ToLocal->encode(s);
1983 	}
1984 
1985 	//printf("ADCGET Type=%s TTH=%s Pos=%lld Size=%lld Zlib=%d\n File=%s\n", msg->m_sType.Data(),
1986 	//	msg->m_sTTH.Data(), msg->m_nPos, msg->m_nSize, msg->m_bZlib, msg->m_sFile.Data() );
1987 
1988 	return msg;
1989 }
1990 
1991 /** $ADCSND file TTH/PPUROLR2WSYTGPLCM3KV4V6LJC36SCTFQJFDJKA 0 1154 ZL1| */
ParseADCSnd(const CString & sContent)1992 CDCMessage * CMessageHandler::ParseADCSnd( const CString & sContent )
1993 {
1994 	//printf("sContent=\"%s\"\n", sContent.Data());
1995 
1996 	CMessageADCSnd * msg = new CMessageADCSnd();
1997 
1998 	int i = sContent.Find(' ');
1999 	CString s = sContent.Mid(0,i);
2000 	if ( s == "file" )
2001 	{
2002 		msg->m_eADCType = eAdcFile;
2003 	}
2004 	else if ( s == "tthl" )
2005 	{
2006 		msg->m_eADCType = eAdcTTHL;
2007 	}
2008 	else if ( s == "list" )
2009 	{
2010 		msg->m_eADCType = eAdcList;
2011 	}
2012 	else
2013 	{
2014 		delete msg;
2015 		printf("CMessageHandler::ParseADCGet: Unknown ADCSND type '%s'\n",s.Data());
2016 		return 0;
2017 	}
2018 
2019 	s = sContent.Mid(i+1,sContent.Length()-i-1);
2020 
2021 	if (s.Right(4).ToUpper() == " ZL1")
2022 	{
2023 		msg->m_bZlib = true;
2024 		s = s.Mid(0, s.Length() - 4);
2025 	}
2026 	else
2027 	{
2028 		msg->m_bZlib = false;
2029 	}
2030 
2031 	i = s.FindRev(' ');
2032 	msg->m_nSize = s.Mid(i, s.Length() - i).asLONGLONG();
2033 	s = s.Mid(0, i);
2034 
2035 	i = s.FindRev(' ');
2036 	msg->m_nPos = s.Mid(i, s.Length() - i).asULL();
2037 	s = s.Mid(0, i);
2038 
2039 	if ( s.StartsWith("TTH/",4) )
2040 	{
2041 		msg->m_sTTH = s.Mid(4);
2042 	}
2043 	else
2044 	{
2045 		// unescape spaces
2046 		s = s.Replace( "\\ ", " " );
2047 		msg->m_sFile = m_pUTF8ToLocal->encode(s);
2048 	}
2049 
2050 	//printf("ADCSND Type=%s TTH=%s Pos=%lld Size=%lld Zlib=%d File=%d\n", msg->m_sType.Data(),
2051 	//	msg->m_sTTH.Data(), msg->m_nPos, msg->m_nSize, msg->m_bZlib, msg->m_sFile.Data() );
2052 
2053 	return msg;
2054 }
2055 
2056 /**
2057  * $UserIP nick ip|
2058  * $UserIP nick1 ip1$$nick2 ip2$$|
2059  */
ParseUserIP(CString sContent)2060 CDCMessage * CMessageHandler::ParseUserIP( CString sContent )
2061 {
2062 	int middle = sContent.Find(' ');
2063 	if ( middle < 0 )
2064 	{
2065 		return 0;
2066 	}
2067 
2068 	CMessageUserIP * msg = new CMessageUserIP();
2069 
2070 	if ( sContent.Right(2) != "$$" )
2071 	{
2072 		sContent += "$$";
2073 	}
2074 
2075 	int list_sep = sContent.Find("$$");
2076 	int start = 0;
2077 	while ( (list_sep != -1) && (middle != -1) )
2078 	{
2079 		msg->m_lNicks.push_back( m_pRemoteToLocal->encode(sContent.Mid(start,middle-start)) );
2080 		++middle;
2081 		msg->m_lIPs.push_back( sContent.Mid( middle, list_sep - middle ) );
2082 
2083 		start = list_sep + 2;
2084 		list_sep = sContent.Find("$$",start);
2085 		middle = sContent.Find(' ',start);
2086 	}
2087 
2088 	return msg;
2089 }
2090