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|<%[mynick]> -help| )
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( "$", "$" );
622 msg->m_sMessage = msg->m_sMessage.Replace( "|", "|" );
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("$","$");
1119 msg->m_sString = s.Replace("|","|");
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( "$", "$" );
1383 msg->m_sMessage = msg->m_sMessage.Replace( "|", "|" );
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|| */
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( "$", "$" );
1869 command = command.Replace( "|", "|" );
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