1 /***************************************************************************
2 chublistmanager.cpp - description
3 -------------------
4 begin : Don Mai 16 2002
5 copyright : (C) 2002-2003 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 "chublistmanager.h"
19
20 #include "cconfig.h"
21 #include "core/cmanager.h"
22 #include "dcobject.h"
23 #include "core/cbytearray.h"
24 #include "chttp.h"
25 #include "core/cbz.h"
26 #include "core/cxml.h"
27 #include "core/ccallback.h"
28 #include "core/ciconv.h"
29
30 #ifndef WIN32
31 #include <unistd.h>
32 #include <stdlib.h>
33 #endif
34
35 #include <stdio.h>
36
37 /** */
CHubListManager()38 CHubListManager::CHubListManager()
39 {
40 m_pCallback = new CCallback0<CHubListManager>( this, &CHubListManager::Callback );
41 CManager::Instance()->Add( m_pCallback );
42
43 if ( CConfig::Instance()->GetReloadHubListTime() != 0 )
44 {
45 m_nReloadHubListTimeout = time(0) + CConfig::Instance()->GetReloadHubListTime()*60*60;
46 }
47 else
48 {
49 m_nReloadHubListTimeout = 0;
50 }
51
52 // get hublist stuff
53 m_pHttp = 0;
54 m_pHubListUrlList = 0;
55 m_pHubListUrl = 0;
56 m_pHubListData = 0;
57
58 m_bGetHubListDone = false;
59
60 m_pXml = 0;
61 m_pXmlHubs = new CList<DCConfigHubItem>;
62 }
63
64 /** */
~CHubListManager()65 CHubListManager::~CHubListManager()
66 {
67 m_Thread.Stop();
68
69 SetInstance(0);
70
71 CManager::Instance()->Remove( m_pCallback );
72
73 delete m_pCallback;
74 m_pCallback = 0;
75
76 delete m_pXml;
77 m_pXml = 0;
78
79 delete m_pXmlHubs;
80 m_pXmlHubs = 0;
81 }
82
83 /** thread callbackfunction */
Callback()84 int CHubListManager::Callback()
85 {
86 m_Thread.Lock();
87
88 // check reload hublist timeout
89 if ( CConfig::Instance() )
90 {
91 if ( CConfig::Instance()->GetReloadHubListTime() != 0 )
92 {
93 if ( m_nReloadHubListTimeout != 0 )
94 {
95 if ( time(0) >= m_nReloadHubListTimeout )
96 {
97 GetPublicHubList();
98
99 m_nReloadHubListTimeout = time(0) + CConfig::Instance()->GetReloadHubListTime()*60*60;
100 }
101 }
102 else // change from config
103 {
104 m_nReloadHubListTimeout = time(0) + CConfig::Instance()->GetReloadHubListTime()*60*60;
105 }
106 }
107 else
108 {
109 m_nReloadHubListTimeout = 0;
110 }
111 }
112
113 // cleanup all objects
114 if ( m_bGetHubListDone )
115 {
116 delete m_pHttp;
117 m_pHttp = 0;
118
119 delete m_pHubListUrlList;
120 m_pHubListUrlList = 0;
121
122 delete m_pHubListData;
123 m_pHubListData = 0;
124
125 if ( m_pXmlHubs )
126 {
127 m_pXmlHubs->Clear();
128 }
129
130 m_pHubListUrl = 0;
131
132 DCMessageGetHubList * msg = new DCMessageGetHubList();
133
134 msg->m_bRun = false;
135
136 if ( DC_CallBack(msg) == -1 )
137 {
138 delete msg;
139 }
140
141 m_bGetHubListDone = false;
142 }
143
144 m_Thread.UnLock();
145
146 return 0;
147 }
148
149 /** http callback function */
HttpCallBack(CDCMessage * dcmsg)150 int CHubListManager::HttpCallBack( CDCMessage * dcmsg )
151 {
152 CByteArray in;
153
154 switch ( dcmsg->m_eType )
155 {
156 case DC_MESSAGE_CONNECTION_STATE:
157 {
158 CMessageConnectionState *msg = (CMessageConnectionState*)dcmsg;
159
160 if ( msg->m_eState == estDISCONNECTED )
161 {
162 if ( (m_pHttp->GetHttpError() == 200) && m_pHttp->GetData(&in) )
163 {
164 HandleHubListData( m_pHttp->GetUrl(), &in );
165 }
166
167 // redirect
168 if ( m_pHttp->GetHttpError() == 302 )
169 {
170 m_pHttp->GetUrl(m_pHttp->GetLocation());
171 }
172 else if ( NextHubListUrl() == false )
173 {
174 // parse public hub list in own thread
175 m_Thread.SetThreadCallBackFunction( new CCallback0<CHubListManager>( this, &CHubListManager::ParsePublicHubList ) );
176 m_Thread.Start();
177 }
178 }
179
180 break;
181 }
182
183 case DC_MESSAGE_TRANSFER:
184 {
185 if ( DC_CallBack( (CMessageTransfer*)dcmsg ) != -1 )
186 {
187 dcmsg = 0;
188 }
189
190 break;
191 }
192
193 default:
194 {
195 break;
196 }
197 }
198
199 if ( dcmsg )
200 {
201 delete dcmsg;
202 }
203
204 return 0;
205 }
206
207 /** */
HandleHubListData(const CString & url,CByteArray * in)208 void CHubListManager::HandleHubListData( const CString & url, CByteArray * in )
209 {
210 CByteArray out;
211
212 if ( url.Right(4).ToLower() == ".bz2" )
213 {
214 if ( CBZ::Decompress( in, &out ) )
215 {
216 if ( url.Right(8).ToLower() == ".xml.bz2" )
217 {
218 if ( m_pXml == 0 )
219 {
220 m_pXml = new CXml();
221 }
222
223 if ( m_pXml->ParseFixMemory(&out) && m_pXml->DocFirstChild() )
224 {
225 ParseXmlPublicHubList();
226 }
227 else
228 {
229 printf("Failed to parse XML hublist.\n");
230 }
231
232 delete m_pXml;
233 m_pXml = 0;
234 }
235 else
236 {
237 m_pHubListData->Append(out.Data(),out.Size());
238 m_pHubListData->Append("\xD\xA",2);
239 }
240 }
241 else
242 {
243 printf("bz2 decompress failed\n");
244 }
245 }
246 else
247 {
248 if ( url.Right(4).ToLower() == ".xml" )
249 {
250 if ( m_pXml == 0 )
251 {
252 m_pXml = new CXml();
253 }
254
255 if ( m_pXml->ParseFixMemory(in) && m_pXml->DocFirstChild() )
256 {
257 ParseXmlPublicHubList();
258 }
259 else
260 {
261 printf("Failed to parse XML hublist.\n");
262 }
263
264 delete m_pXml;
265 m_pXml = 0;
266 }
267 else
268 {
269 m_pHubListData->Append(in->Data(),in->Size());
270 m_pHubListData->Append("\xD\xA",2);
271 }
272 }
273 }
274
275 /** */
GetPublicHubList()276 bool CHubListManager::GetPublicHubList()
277 {
278 bool res = false;
279
280 if ( m_pHttp != 0 )
281 {
282 // get hublist allready running
283 return res;
284 }
285
286 m_pHubListUrlList = new CList<DCConfigHubListUrl>();
287
288 // get all hublist urls
289 CConfig::Instance()->GetHubListUrlList(m_pHubListUrlList);
290
291 // check hublist url count
292 if ( m_pHubListUrlList->Count() == 0 )
293 {
294 delete m_pHubListUrlList;
295 m_pHubListUrlList = 0;
296 return res;
297 }
298
299 // init first url
300 m_pHubListUrl = 0;
301
302 m_pHubListData = new CByteArray();
303 m_pHttp = new CHttp();
304 m_pHttp->SetCallBackFunction( new CCallback1<CHubListManager, CDCMessage*>( this, &CHubListManager::HttpCallBack ) );
305
306 res = NextHubListUrl();
307
308 if ( !res )
309 {
310 m_bGetHubListDone = true;
311 }
312 else
313 {
314 DCMessageGetHubList * msg = new DCMessageGetHubList();
315
316 msg->m_bRun = true;
317
318 if ( DC_CallBack(msg) == -1 )
319 {
320 delete msg;
321 }
322 }
323
324 return res;
325 }
326
327 /** */
ParsePublicHubList()328 int CHubListManager::ParsePublicHubList()
329 {
330 CString line;
331 CString s;
332 CString s1,s2,s3,s4;
333 long i=0,i1=0;
334
335 DCConfigHubItem * hubitem = 0;
336
337 if ( (m_pHubListData->Size() == 0) && (m_pXmlHubs->Count() == 0) )
338 {
339 m_Thread.Stop(false);
340 m_Thread.SetThreadCallBackFunction(0);
341 m_bGetHubListDone = true;
342
343 return 0;
344 }
345
346 while ( (hubitem = m_pXmlHubs->Next(hubitem)) != 0 )
347 {
348 // name, host, description, usercount, country, shared, minshare, extra
349 CConfig::Instance()->AddPublicHub(
350 hubitem->m_sName,
351 hubitem->m_sHost,
352 hubitem->m_sDescription,
353 hubitem->m_nUserCount,
354 hubitem->m_sCountry,
355 hubitem->m_nShared,
356 hubitem->m_nMinShare,
357 hubitem->m_sExtra
358 );
359 }
360
361 if ( m_pHubListData->Size() > 0 )
362 {
363
364 s.Set((const char*)m_pHubListData->Data(),m_pHubListData->Size());
365
366 CIconv * pIconv = new CIconv( CConfig::Instance()->GetRemoteEncoding(), CConfig::Instance()->GetLocalEncoding() );
367
368 while( (i = s.Find(0x0d,i)) != -1 )
369 {
370 line = s.Mid(i1,i-i1);
371
372 if ( !line.IsEmpty() )
373 {
374 s1 = line.Section( '|', 0, 0 );
375 s2 = line.Section( '|', 1, 1 );
376 s3 = line.Section( '|', 2, 2 );
377 s4 = line.Section( '|', 3, 3 );
378
379 // replace all spaces
380 s2 = s2.Replace(" ","");
381
382 // remove line ends
383 s1 = s1.Replace("\n", "");
384
385 // name, host, description, usercount
386 CConfig::Instance()->AddPublicHub( pIconv->encode(s1), pIconv->encode(s2), pIconv->encode(s3), s4.asULL() );
387 }
388
389 i1 = i+2;
390 i += 2;
391 }
392
393 delete pIconv;
394
395 }
396
397 // store the list
398 if ( CConfig::Instance()->GetHubListStoreLocal() )
399 {
400 CConfig::Instance()->SaveDCHub();
401 }
402
403 m_Thread.Stop(false);
404 m_Thread.SetThreadCallBackFunction(0);
405 m_bGetHubListDone = true;
406
407 return 0;
408 }
409
410 /** */
NextHubListUrl()411 bool CHubListManager::NextHubListUrl()
412 {
413 bool res = false;
414
415 while( (m_pHubListUrl=m_pHubListUrlList->Next(m_pHubListUrl)) != 0 )
416 {
417 if ( m_pHubListUrl->bEnabled )
418 {
419 if ( m_pHubListUrl->sUrl.Left(7) == "file://" )
420 {
421 CByteArray * data = new CByteArray();
422 if ( data->LoadFromFile(m_pHubListUrl->sUrl.Mid(7)) )
423 {
424 HandleHubListData( m_pHubListUrl->sUrl, data );
425 }
426 delete data;
427
428 if ( NextHubListUrl() == false )
429 {
430 // parse public hub list in own thread
431 m_Thread.SetThreadCallBackFunction( new CCallback0<CHubListManager>( this, &CHubListManager::ParsePublicHubList ) );
432 m_Thread.Start();
433 }
434
435 res = true;
436 break;
437 }
438 else if ( m_pHubListUrl->sUrl.NotEmpty() )
439 {
440 m_pHttp->GetUrl(m_pHubListUrl->sUrl);
441
442 res = true;
443 break;
444 }
445 }
446 }
447
448 return res;
449 }
450
451 /** */
ParseXmlPublicHubList()452 int CHubListManager::ParseXmlPublicHubList()
453 {
454 int count = 0;
455
456 printf("Parse XML hub list...\n");
457
458 do
459 {
460 if ( (m_pXml->Name() == "Hublist") && m_pXml->FirstChild() )
461 {
462 CList<CXmlColumn> * cols = FindAndParseXmlColumns();
463
464 if ( !cols )
465 {
466 /*
467 * The column headings are only needed so that the Extra
468 * field is filled in.
469 */
470 printf("ParseXmlPublicHubList: no column headings found, trying with defaults\n");
471
472 cols = new CList<CXmlColumn>;
473
474 CXmlColumn * xmlcol = new CXmlColumn();
475 xmlcol->m_sName = "Name";
476 xmlcol->m_sType = "string";
477 cols->Add(xmlcol);
478
479 xmlcol = new CXmlColumn();
480 xmlcol->m_sName = "Address";
481 xmlcol->m_sType = "string";
482 cols->Add(xmlcol);
483
484 xmlcol = new CXmlColumn();
485 xmlcol->m_sName = "Description";
486 xmlcol->m_sType = "string";
487 cols->Add(xmlcol);
488
489 xmlcol = new CXmlColumn();
490 xmlcol->m_sName = "Port";
491 xmlcol->m_sType = "int";
492 cols->Add(xmlcol);
493
494 xmlcol = new CXmlColumn();
495 xmlcol->m_sName = "Users";
496 xmlcol->m_sType = "int";
497 cols->Add(xmlcol);
498 }
499
500 /* go back to start */
501 m_pXml->DocFirstChild();
502 m_pXml->FirstChild();
503
504 do
505 {
506 if ( (m_pXml->Name() == "Hubs") && m_pXml->FirstChild() )
507 {
508 count += ParseXmlHubs( cols );
509 m_pXml->Parent();
510 }
511 }
512 while ( m_pXml->NextNode() );
513 m_pXml->Parent();
514
515 cols->Clear();
516 delete cols;
517 }
518 }
519 while ( m_pXml->NextNode() );
520
521 printf("XML hublist: %d hubs\n", count);
522
523 return count;
524 }
525
526 /** */
ParseXmlHubs(CList<CXmlColumn> * cols)527 int CHubListManager::ParseXmlHubs( CList<CXmlColumn> * cols )
528 {
529 int count = 0;
530
531 do
532 {
533 if ( (m_pXml->Name() == "Hub") )
534 {
535 ParseXmlHub(cols);
536 count++;
537 }
538 }
539 while ( m_pXml->NextNode() );
540
541 return count;
542 }
543
544 /** */
FindAndParseXmlColumns()545 CList<CXmlColumn> * CHubListManager::FindAndParseXmlColumns()
546 {
547 CList<CXmlColumn> * cols = 0;
548
549 do
550 {
551 if ( (m_pXml->Name() == "Columns") && m_pXml->FirstChild() )
552 {
553 cols = new CList<CXmlColumn>;
554 do
555 {
556 if ( m_pXml->Name() == "Column" )
557 {
558 CXmlColumn * col = new CXmlColumn();
559 col->m_sName = m_pXml->Prop("Name");
560 col->m_sType = m_pXml->Prop("Type");
561 cols->Add(col);
562 }
563 }
564 while ( m_pXml->NextNode() );
565 break;
566 }
567
568 if ( m_pXml->FirstChild() )
569 {
570 do
571 {
572 if ( (m_pXml->Name() == "Columns") && m_pXml->FirstChild() )
573 {
574 cols = new CList<CXmlColumn>;
575 do
576 {
577 if ( m_pXml->Name() == "Column" )
578 {
579 CXmlColumn * col = new CXmlColumn();
580 col->m_sName = m_pXml->Prop("Name");
581 col->m_sType = m_pXml->Prop("Type");
582 cols->Add(col);
583 }
584 }
585 while ( m_pXml->NextNode() );
586 break;
587 }
588 }
589 while ( m_pXml->NextNode() );
590
591 if ( cols )
592 {
593 break;
594 }
595 }
596 }
597 while ( m_pXml->NextNode() );
598
599 /* no CXml::Parent() called since ParseXmlPublicHubList() just goes back to the start */
600
601 return cols;
602 }
603
604 /** */
ParseXmlHub(CList<CXmlColumn> * cols)605 void CHubListManager::ParseXmlHub( CList<CXmlColumn> * cols )
606 {
607 CXmlColumn * col = 0;
608 DCConfigHubItem * hubitem = new DCConfigHubItem();
609 CString port,namelc;
610
611 while ( (col = cols->Next(col)) != 0 )
612 {
613 col->m_sValue = m_pXml->Prop(col->m_sName);
614
615 namelc = col->m_sName.ToLower();
616 if (namelc == "name")
617 {
618 hubitem->m_sName = col->m_sValue;
619 }
620 else if (namelc == "address")
621 {
622 hubitem->m_sHost = col->m_sValue;
623 }
624 else if (namelc == "description")
625 {
626 hubitem->m_sDescription = col->m_sValue;
627 }
628 else if (namelc == "users")
629 {
630 hubitem->m_nUserCount = col->m_sValue.asULL();
631 }
632 else if (namelc == "port")
633 {
634 port = col->m_sValue;
635 }
636 else if (namelc == "country")
637 {
638 hubitem->m_sCountry = col->m_sValue;
639 }
640 else if (namelc == "minshare")
641 {
642 hubitem->m_nMinShare = col->m_sValue.asULL();
643 }
644 else if (namelc == "shared")
645 {
646 hubitem->m_nShared = col->m_sValue.asULL();
647 }
648 else
649 {
650 hubitem->m_sExtra += col->m_sName;
651 hubitem->m_sExtra += '=';
652 hubitem->m_sExtra += col->m_sValue;
653 hubitem->m_sExtra += ' ';
654 }
655
656 //printf("Name=%s Type=%s Value=%s\n", col->m_sName.Data(), col->m_sType.Data(), col->m_sValue.Data());
657 }
658
659 if ( (hubitem->m_sHost.Find(':') < 0) && (port.NotEmpty()) )
660 {
661 hubitem->m_sHost += ':';
662 hubitem->m_sHost += port;
663 }
664
665 if ( hubitem->m_sName.IsEmpty() || hubitem->m_sHost.IsEmpty() )
666 {
667 delete hubitem;
668 }
669 else
670 {
671 m_pXmlHubs->Add(hubitem);
672 }
673 }
674