OSDN Git Service

GUI終了時のエラー落ちを修正(?)
authoreru <eru01@users.sourceforge.jp>
Wed, 12 Dec 2007 05:03:54 +0000 (05:03 +0000)
committereru <eru01@users.sourceforge.jp>
Wed, 12 Dec 2007 05:03:54 +0000 (05:03 +0000)
原因:
backImageがNULLなのにGUIDataUpdateが更新を試みる事があった

対策:
backImageの破棄タイミングを調整

162 files changed:
PeerCast.root/PeerCast/core/common/asf.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/atom.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/channel.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/channel.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/common.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/cstream.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/gnutella.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/gnutella.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/html-xml.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/html.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/html.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/http.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/http.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/icy.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/icy.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/id.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/identify_encoding.c [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/identify_encoding.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/inifile.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/inifile.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/jis.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/jis.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/mms.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/mms.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/mp3.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/mp3.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/nsv.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/nsv.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/ogg.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/ogg.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/pcp.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/pcp.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/peercast.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/peercast.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/rtsp.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/rtsp.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/servent.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/servent.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/servhs.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/servmgr.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/servmgr.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/socket.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/socket.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/stats.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/stats.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/stream.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/stream.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/sys.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/sys.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/url.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/url.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/utf8.c [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/utf8.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/version2.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/xml.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/core/common/xml.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/win32/lib/corelib.vcproj [new file with mode: 0644]
PeerCast.root/PeerCast/core/win32/lib/corelib.vcproj.vspscc [new file with mode: 0644]
PeerCast.root/PeerCast/core/win32/wsocket.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/core/win32/wsocket.h [new file with mode: 0644]
PeerCast.root/PeerCast/core/win32/wsys.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/core/win32/wsys.h [new file with mode: 0644]
PeerCast.root/PeerCast/ui/win32/PeerCast.sln [new file with mode: 0644]
PeerCast.root/PeerCast/ui/win32/PeerCast.vsscc [new file with mode: 0644]
PeerCast.root/PeerCast/ui/win32/PeerCast.vssscc [new file with mode: 0644]
PeerCast.root/PeerCast/ui/win32/simple/SMALL.ICO [new file with mode: 0644]
PeerCast.root/PeerCast/ui/win32/simple/Simple.ICO [new file with mode: 0644]
PeerCast.root/PeerCast/ui/win32/simple/Simple.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/ui/win32/simple/Simple.h [new file with mode: 0644]
PeerCast.root/PeerCast/ui/win32/simple/Simple.rc [new file with mode: 0644]
PeerCast.root/PeerCast/ui/win32/simple/Simple.vcproj [new file with mode: 0644]
PeerCast.root/PeerCast/ui/win32/simple/Simple.vcproj.vspscc [new file with mode: 0644]
PeerCast.root/PeerCast/ui/win32/simple/StdAfx.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/ui/win32/simple/StdAfx.h [new file with mode: 0644]
PeerCast.root/PeerCast/ui/win32/simple/chkMemoryLeak.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/ui/win32/simple/chkMemoryLeak.h [new file with mode: 0644]
PeerCast.root/PeerCast/ui/win32/simple/gui.cpp [new file with mode: 0644]
PeerCast.root/PeerCast/ui/win32/simple/gui.h [new file with mode: 0644]
PeerCast.root/PeerCast/ui/win32/simple/resource.h [new file with mode: 0644]
PeerCast.root/PeerCast/ui/win32/simple/small1.ico [new file with mode: 0644]
PeerCast.root/PeerCast/ui/win32/simple/small3.ico [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/asf.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/atom.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/channel.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/channel.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/common.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/cstream.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/gnutella.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/gnutella.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/html-xml.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/html.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/html.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/http.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/http.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/icy.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/icy.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/id.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/identify_encoding.c [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/identify_encoding.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/inifile.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/inifile.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/jis.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/jis.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/mms.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/mms.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/mp3.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/mp3.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/nsv.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/nsv.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/ogg.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/ogg.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/pcp.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/pcp.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/peercast.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/peercast.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/rtsp.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/rtsp.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/servent.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/servent.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/servhs.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/servmgr.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/servmgr.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/socket.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/socket.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/stats.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/stats.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/stream.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/stream.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/sys.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/sys.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/url.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/url.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/utf8.c [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/utf8.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/version2.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/xml.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/common/xml.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/win32/lib/corelib.vcproj [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/win32/lib/corelib.vcproj.vspscc [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/win32/wsocket.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/win32/wsocket.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/win32/wsys.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/core/win32/wsys.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/ui/win32/PeerCast.sln [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/ui/win32/PeerCast.vsscc [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/ui/win32/PeerCast.vssscc [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/ui/win32/simple/SMALL.ICO [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.ICO [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.rc [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.vcproj [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.vcproj.vspscc [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/ui/win32/simple/StdAfx.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/ui/win32/simple/StdAfx.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/ui/win32/simple/chkMemoryLeak.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/ui/win32/simple/chkMemoryLeak.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/ui/win32/simple/gui.cpp [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/ui/win32/simple/gui.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/ui/win32/simple/resource.h [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/ui/win32/simple/small1.ico [new file with mode: 0644]
c:/Git/PeerCast.root/PeerCast/ui/win32/simple/small3.ico [new file with mode: 0644]

diff --git a/PeerCast.root/PeerCast/core/common/asf.h b/PeerCast.root/PeerCast/core/common/asf.h
new file mode 100644 (file)
index 0000000..fcd1e3d
--- /dev/null
@@ -0,0 +1,290 @@
+// ------------------------------------------------
+// File : asf.h
+// Date: 10-apr-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _ASF_H
+#define _ASF_H
+
+
+#include "stream.h"
+
+// -----------------------------------
+class MSID
+{
+public:
+
+       void read(Stream &in)
+       {
+               data1 = in.readLong();
+               data2 = in.readShort();
+               data3 = in.readShort();
+               in.read(data4,8);
+       }
+
+       void write(Stream &out)
+       {
+               out.writeLong(data1);
+               out.writeShort(data2);
+               out.writeShort(data3);
+               out.write(data4,8);
+       }
+       
+       
+       void toString(String &s)
+       {
+               sprintf(s.data,"%X-%X-%X-%02X%02X%02X%02X%02X%02X%02X%02X",
+                       data1,data2,data3,
+                       data4[0],data4[1],data4[2],data4[3],
+                       data4[4],data4[5],data4[6],data4[7]);
+       }
+
+    int operator==(const MSID& msid) const{return !memcmp(this, &msid, sizeof(MSID));}
+
+       unsigned int data1;
+       unsigned short data2,data3;
+       unsigned char data4[8];
+
+};
+
+
+
+
+// -----------------------------------
+const MSID headObjID=
+       {0x75B22630, 0x668E, 0x11CF, 0xA6,0xD9,0x00,0xAA,0x00,0x62,0xCE,0x6C};
+const MSID dataObjID=
+       {0x75B22636, 0x668E, 0x11CF, 0xA6,0xD9,0x00,0xAA,0x00,0x62,0xCE,0x6C};
+const MSID filePropObjID=
+       {0x8CABDCA1, 0xA947, 0x11CF, 0x8E,0xE4,0x00,0xC0,0x0C,0x20,0x53,0x65};
+const MSID streamPropObjID=
+       {0xB7DC0791, 0xA9B7, 0x11CF, 0x8E,0xE6,0x00,0xC0,0x0C,0x20,0x53,0x65};
+
+const MSID audioStreamObjID=
+       {0xF8699E40, 0x5B4D, 0x11CF, 0xA8,0xFD,0x00,0x80,0x5F,0x5C,0x44,0x2B};
+const MSID videoStreamObjID=
+       {0xBC19EFC0, 0x5B4D, 0x11CF, 0xA8,0xFD,0x00,0x80,0x5F,0x5C,0x44,0x2B};
+
+const MSID streamBitrateObjID=
+       {0x7BF875CE, 0x468D, 0x11D1, 0x8D,0x82,0x00,0x60,0x97,0xC9,0xA2,0xB2};
+
+
+// -----------------------------------
+class ASFObject
+{
+public:
+
+       enum TYPE
+       {
+               T_UNKNOWN,
+               T_HEAD_OBJECT,
+               T_DATA_OBJECT,
+               T_FILE_PROP,
+               T_STREAM_PROP,
+               T_STREAM_BITRATE
+       };
+
+       int getTotalLen()
+       {
+               return 24+dataLen;
+       }
+
+       unsigned int readHead(Stream &in)
+       {
+               id.read(in);
+
+               lenLo = in.readLong();
+               lenHi = in.readLong();
+
+               type = T_UNKNOWN;
+               if (id == headObjID)
+                       type = T_HEAD_OBJECT;
+               else if (id == dataObjID)
+                       type = T_DATA_OBJECT;
+               else if (id == filePropObjID)
+                       type = T_FILE_PROP;
+               else if (id == streamPropObjID)
+                       type = T_STREAM_PROP;
+               else if (id == streamBitrateObjID)
+                       type = T_STREAM_BITRATE;
+
+               String str;
+               id.toString(str);
+               LOG_DEBUG("ASF: %s (%s)= %d : %d\n",str.data,getTypeName(),lenLo,lenHi);
+
+
+               dataLen = 0;
+
+               return lenLo-24;
+       }
+
+       void readData(Stream &in,int len)
+       {
+               dataLen = len;
+
+               if ((dataLen > sizeof(data)) || (lenHi)) 
+                       throw StreamException("ASF object too big");
+
+               in.read(data,dataLen);
+       }
+
+
+       void write(Stream &out)
+       {
+               id.write(out);
+               out.writeLong(lenLo);
+               out.writeLong(lenHi);
+               if (dataLen)
+                       out.write(data,dataLen);
+       }
+
+       const char *getTypeName()
+       {
+               switch(type)
+               {
+                       case T_HEAD_OBJECT:
+                               return "ASF_Header_Object";
+                       case T_DATA_OBJECT:
+                               return "ASF_Data_Object";
+                       case T_FILE_PROP:
+                               return "ASF_File_Properties_Object";
+                       case T_STREAM_PROP:
+                               return "ASF_Stream_Properties_Object";
+                       case T_STREAM_BITRATE:
+                               return "ASF_Stream_Bitrate_Properties_Object";
+                       default:
+                               return "Unknown_Object";
+               }
+       }
+
+       char data[8192];
+       MSID    id;
+       unsigned int lenLo,lenHi,dataLen;
+       TYPE type;
+};
+// -----------------------------------
+class ASFStream
+{
+public:
+       enum TYPE
+       {
+               T_UNKNOWN,
+               T_AUDIO,
+               T_VIDEO
+       };
+
+       void read(Stream &in)
+       {
+               MSID sid;
+               sid.read(in);
+
+               if (sid == videoStreamObjID)
+                       type = T_VIDEO;
+               else if (sid == audioStreamObjID)
+                       type = T_AUDIO;
+               else 
+                       type = T_UNKNOWN;
+
+               in.skip(32);
+               id = in.readShort()&0x7f;
+       }
+
+
+       const char *getTypeName()
+       {
+               switch(type)
+               {
+                       case T_VIDEO:
+                               return "Video";
+                       case T_AUDIO:
+                               return "Audio";
+               }
+               return "Unknown";
+       }
+
+       void reset()
+       {
+               id = 0;
+               bitrate = 0;
+               type = T_UNKNOWN;
+       }
+
+       unsigned int id;
+       int bitrate;
+       TYPE type;
+};
+
+// -----------------------------------
+class ASFInfo
+{
+public:
+       enum
+       {
+               MAX_STREAMS = 128
+       };
+
+       ASFInfo()
+       {
+               numPackets = 0;
+               packetSize = 0;
+               flags = 0;
+               bitrate=0;
+               for(int i=0; i<MAX_STREAMS; i++)
+                       streams[i].reset();
+       }
+
+       unsigned int packetSize,numPackets,flags,bitrate;
+
+       ASFStream streams[MAX_STREAMS];
+};
+
+// -----------------------------------
+class ASFChunk
+{
+public:
+
+       void read(Stream &in)
+       {
+               type = in.readShort();
+               len = in.readShort();
+               seq = in.readLong();
+               v1 = in.readShort();
+               v2 = in.readShort();
+
+               dataLen = len-8;
+               if (dataLen > sizeof(data)) 
+                       throw StreamException("ASF chunk too big");
+               in.read(data,dataLen);
+       }
+
+       void write(Stream &out)
+       {
+               out.writeShort(type);
+               out.writeShort(len);
+               out.writeLong(seq);
+               out.writeShort(v1);
+               out.writeShort(v2);
+               out.write(data,dataLen);
+       }
+
+       unsigned int seq,dataLen;
+       unsigned short type,len,v1,v2;
+       unsigned char data[8192];
+};
+
+
+#endif
+
diff --git a/PeerCast.root/PeerCast/core/common/atom.h b/PeerCast.root/PeerCast/core/common/atom.h
new file mode 100644 (file)
index 0000000..94d8e46
--- /dev/null
@@ -0,0 +1,208 @@
+// ------------------------------------------------
+// File : atom.h
+// Date: 1-mar-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _ATOM_H
+#define _ATOM_H
+
+#include "stream.h"
+
+#include "id.h"
+
+// ------------------------------------------------
+class AtomStream
+{
+public:
+       AtomStream(Stream &s) : io(s),numChildren(0),numData(0)
+       {}
+
+       void checkData(int d)
+       {
+               if (numData != d)
+                       throw StreamException("Bad atom data");
+       }
+
+       void writeParent(ID4 id,int nc)
+       {
+               io.writeID4(id);
+               io.writeInt(nc|0x80000000);
+       }
+
+       void writeInt(ID4 id,int d)
+       {
+               io.writeID4(id);
+               io.writeInt(4);
+               io.writeInt(d);
+       }
+       
+       void writeID4(ID4 id,ID4 d)
+       {
+               io.writeID4(id);
+               io.writeInt(4);
+               io.writeID4(d);
+       }
+
+       void writeShort(ID4 id,short d)
+       {
+               io.writeID4(id);
+               io.writeInt(2);
+               io.writeShort(d);
+       }
+
+       void writeChar(ID4 id,char d)
+       {
+               io.writeID4(id);
+               io.writeInt(1);
+               io.writeChar(d);
+       }
+
+       void writeBytes(ID4 id,const void *p,int l)
+       {
+               io.writeID4(id);
+               io.writeInt(l);
+               io.write(p,l);
+       }
+
+
+       int writeStream(ID4 id,Stream &in,int l)
+       {
+               io.writeID4(id);
+               io.writeInt(l);
+               in.writeTo(io,l);
+               return (sizeof(int)*2)+l;
+
+       }
+
+       void writeString(ID4 id,const char *p)
+       {
+               writeBytes(id,p,strlen(p)+1);
+       }
+
+       ID4     read(int &numc,int &dlen)
+       {
+               ID4 id = io.readID4();
+
+               unsigned int v = io.readInt();
+               if (v & 0x80000000)
+               {
+                       numc = v&0x7fffffff;
+                       dlen = 0;
+               }else
+               {
+                       numc = 0;
+                       dlen = v;
+               }
+
+               numChildren = numc;
+               numData = dlen;
+
+               return id;
+       }
+
+       void skip(int c, int d)
+       {
+               if (d)
+                       io.skip(d);
+
+               for(int i=0; i<c; i++)
+               {
+                       int numc,data;
+                       read(numc,data);
+                       skip(numc,data);
+               }
+
+       }
+
+       int             readInt() 
+       {
+               checkData(4);
+               return io.readInt();
+       }
+       int             readID4() 
+       {
+               checkData(4);
+               return io.readID4();
+       }
+
+       int             readShort() 
+       {
+               checkData(2);
+               return io.readShort();
+       }
+       int             readChar() 
+       {
+               checkData(1);
+               return io.readChar();
+       }
+       int             readBytes(void *p,int l) 
+       {
+               checkData(l);
+               return io.read(p,l);
+       }
+
+       void    readString(char *s,int max,int dlen)
+       {
+               checkData(dlen);
+               readBytes(s,max,dlen);
+               s[max-1] = 0;
+
+       }
+
+       void    readBytes(void *s,int max,int dlen)
+       {
+               checkData(dlen);
+               if (max > dlen)
+                       readBytes(s,dlen);
+               else
+               {
+                       readBytes(s,max);
+                       io.skip(dlen-max);
+               }
+       }
+
+       int             writeAtoms(ID4 id, Stream &in, int cnt, int data)
+       {
+               int total=0;
+
+               if (cnt)
+               {
+                       writeParent(id,cnt);
+                       total+=sizeof(int)*2;
+
+                       for(int i=0; i<cnt; i++)
+                       {
+                               AtomStream ain(in);
+                               int c,d;
+                               ID4 cid = ain.read(c,d);
+                               total += writeAtoms(cid,in,c,d);
+                       }
+               }else
+               {
+                       total += writeStream(id,in,data);
+               }
+
+               return total;
+       }
+
+       bool    eof() {return io.eof();}        
+
+
+       int     numChildren,numData;
+       Stream &io;
+};
+
+#endif
diff --git a/PeerCast.root/PeerCast/core/common/channel.cpp b/PeerCast.root/PeerCast/core/common/channel.cpp
new file mode 100644 (file)
index 0000000..f80f0da
--- /dev/null
@@ -0,0 +1,4608 @@
+// ------------------------------------------------
+// File : channel.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             Channel streaming classes. These do the actual 
+//             streaming of media between clients. 
+//
+// (c) 2002 peercast.org
+// 
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include <string.h>
+#include <stdlib.h>
+#include "common.h"
+#include "socket.h"
+#include "channel.h"
+#include "gnutella.h"
+#include "servent.h"
+#include "servmgr.h"
+#include "sys.h"
+#include "xml.h"
+#include "http.h"
+#include "peercast.h"
+#include "atom.h"
+#include "pcp.h"
+
+#include "mp3.h"
+#include "ogg.h"
+#include "mms.h"
+#include "nsv.h"
+
+#include "icy.h"
+#include "url.h"
+
+#include "version2.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// -----------------------------------
+char *Channel::srcTypes[]=
+{
+       "NONE",
+       "PEERCAST",
+       "SHOUTCAST",
+       "ICECAST",
+       "URL"
+};
+// -----------------------------------
+char *Channel::statusMsgs[]=
+{
+       "NONE",
+       "WAIT",
+       "CONNECT",
+       "REQUEST",
+       "CLOSE",
+       "RECEIVE",
+       "BROADCAST",
+       "ABORT",
+       "SEARCH",
+       "NOHOSTS",
+       "IDLE",
+       "ERROR",
+       "NOTFOUND"
+};
+
+
+// for PCRaw start.
+bool isIndexTxt(ChanInfo *info)
+{
+       int len;
+
+       if(     info &&
+               info->contentType == ChanInfo::T_RAW &&
+               info->bitrate <= 32 &&
+               (len = strlen(info->name.cstr())) >= 9 &&
+               !memcmp(info->name.cstr(), "index", 5) &&
+               !memcmp(info->name.cstr()+len-4, ".txt", 4))
+       {
+               return true;
+       }
+       else
+       {
+               return false;
+       }
+}
+
+bool isIndexTxt(Channel *ch)
+{
+       if(ch && !ch->isBroadcasting() && isIndexTxt(&ch->info))
+               return true;
+       else
+               return false;
+}
+
+int numMaxRelaysIndexTxt(Channel *ch)
+{
+       return ((servMgr->maxRelaysIndexTxt < 1) ? 1 : servMgr->maxRelaysIndexTxt);
+}
+
+int canStreamIndexTxt(Channel *ch)
+{
+       int ret;
+
+       // \8e©\95ª\82ª\94z\90M\82µ\82Ä\82¢\82é\8fê\8d\87\82Í\8aÖ\8cW\82È\82¢
+       if(!ch || ch->isBroadcasting())
+               return -1;
+
+       ret = numMaxRelaysIndexTxt(ch) - ch->localRelays();
+       if(ret < 0)
+               ret = 0;
+
+       return ret;
+}
+// for PCRaw end.
+
+// -----------------------------------
+void readXMLString(String &str, XML::Node *n, const char *arg)
+{
+       char *p;
+       p = n->findAttr(arg);
+       if (p)
+       {
+               str.set(p,String::T_HTML);
+               str.convertTo(String::T_ASCII);
+       }
+}
+
+int channel_count=1;
+// -----------------------------------------------------------------------------
+// Initialise the channel to its default settings of unallocated and reset.
+// -----------------------------------------------------------------------------
+Channel::Channel()
+{
+       next = NULL;
+       reset();
+       channel_id = channel_count++;
+}
+// -----------------------------------------------------------------------------
+void Channel::endThread(bool flg)
+{
+       if (pushSock)
+       {
+               pushSock->close();
+               delete pushSock;
+               pushSock = NULL;
+       }
+
+       if (sock)
+       {
+               sock->close();
+               sock = NULL;
+       }
+
+       if (sourceData)
+       {
+               delete sourceData;
+               sourceData = NULL;
+       }
+
+       if (flg == true){
+               reset();
+
+               chanMgr->channellock.on();
+               chanMgr->deleteChannel(this);
+               chanMgr->channellock.off();
+
+               sys->endThread(&thread);
+       }
+}
+// -----------------------------------------------------------------------------
+void Channel::resetPlayTime()
+{
+       info.lastPlayStart = sys->getTime();
+}
+// -----------------------------------------------------------------------------
+void Channel::setStatus(STATUS s)
+{
+       if (s != status)
+       {
+               bool wasPlaying = isPlaying();
+
+               status = s;
+
+               if (isPlaying())
+               {
+                       info.status = ChanInfo::S_PLAY;
+                       resetPlayTime();
+               }else
+               {
+                       if (wasPlaying)
+                               info.lastPlayEnd = sys->getTime();
+                       info.status = ChanInfo::S_UNKNOWN;
+               }
+
+               if (isBroadcasting())
+               {
+                       ChanHitList *chl = chanMgr->findHitListByID(info.id);
+                       if (!chl)
+                               chanMgr->addHitList(info);
+               }
+
+               peercastApp->channelUpdate(&info);
+
+       }
+}
+       
+// -----------------------------------------------------------------------------
+// Reset channel and make it available 
+// -----------------------------------------------------------------------------
+void Channel::reset()
+{
+       sourceHost.init();
+       remoteID.clear();
+
+       streamIndex = 0;
+
+       lastIdleTime = 0;
+
+       info.init();
+
+       mount.clear();
+       bump = false;
+       stayConnected = false;
+
+       icyMetaInterval = 0;
+       streamPos = 0;
+       skipCount = 0; //JP-EX
+       lastSkipTime = 0;
+
+       insertMeta.init();
+
+       headPack.init();
+
+       sourceStream = NULL;
+
+       rawData.init();
+       rawData.accept = ChanPacket::T_HEAD|ChanPacket::T_DATA;
+
+       setStatus(S_NONE);
+       type = T_NONE;
+
+       readDelay = false;
+       sock = NULL;
+       pushSock = NULL;
+
+       sourceURL.clear();
+       sourceData = NULL;
+
+       lastTrackerUpdate = 0;
+       lastMetaUpdate = 0;
+
+       srcType = SRC_NONE;
+
+
+       startTime = 0;
+       syncTime = 0;
+
+       channel_id = 0;
+       finthread = NULL;
+
+       trackerHit.init();
+}
+
+// -----------------------------------
+void   Channel::newPacket(ChanPacket &pack)
+{
+       if (pack.type != ChanPacket::T_PCP)
+       {
+               rawData.writePacket(pack,true);
+       }
+}
+
+
+// -----------------------------------
+bool   Channel::checkIdle()
+{
+       return ( (info.getUptime() > chanMgr->prefetchTime) && (localListeners() == 0) && (!stayConnected) && (status != S_BROADCASTING));
+}
+
+// -----------------------------------
+bool   Channel::isFull()
+{
+       // for PCRaw (relay) start.
+       if(isIndexTxt(this))
+       {
+               int ret = canStreamIndexTxt(this);
+               
+               if(ret > 0)
+                       return false;
+               else if(ret == 0)
+                       return true;
+       }
+       // for PCRaw (relay) end.
+
+       return chanMgr->maxRelaysPerChannel ? localRelays() >= chanMgr->maxRelaysPerChannel : false;
+}
+// -----------------------------------
+int Channel::localRelays()
+{
+       return servMgr->numStreams(info.id,Servent::T_RELAY,true);
+}
+// -----------------------------------
+int Channel::localListeners()
+{
+       return servMgr->numStreams(info.id,Servent::T_DIRECT,true);
+}
+
+// -----------------------------------
+int Channel::totalRelays()
+{
+       int tot = 0;
+       ChanHitList *chl = chanMgr->findHitListByID(info.id);
+       if (chl)
+               tot += chl->numHits();
+       return tot;
+}
+// -----------------------------------
+int Channel::totalListeners()
+{
+       int tot = localListeners();
+       ChanHitList *chl = chanMgr->findHitListByID(info.id);
+       if (chl)
+               tot += chl->numListeners();
+       return tot;
+}
+
+
+
+
+// -----------------------------------
+void   Channel::startGet()
+{
+       srcType = SRC_PEERCAST;
+       type = T_RELAY;
+       info.srcProtocol = ChanInfo::SP_PCP;
+
+
+       sourceData = new PeercastSource();
+
+       startStream();
+}
+// -----------------------------------
+void   Channel::startURL(const char *u)
+{
+       sourceURL.set(u);
+
+       srcType = SRC_URL;
+       type = T_BROADCAST;
+       stayConnected = true;
+
+       resetPlayTime();
+
+       sourceData = new URLSource(u);
+
+       startStream();
+
+}
+// -----------------------------------
+void Channel::startStream()
+{
+       thread.data = this;
+       thread.func = stream;
+       if (!sys->startThread(&thread))
+               reset();
+}
+
+// -----------------------------------
+void Channel::sleepUntil(double time)
+{
+       double sleepTime = time - (sys->getDTime()-startTime);
+
+//     LOG("sleep %g",sleepTime);
+       if (sleepTime > 0)
+       {
+               if (sleepTime > 60) sleepTime = 60;
+
+               double sleepMS = sleepTime*1000;
+
+               sys->sleep((int)sleepMS);
+       }
+}
+
+
+// -----------------------------------
+void Channel::checkReadDelay(unsigned int len)
+{
+       if (readDelay)
+       {
+               unsigned int time = (len*1000)/((info.bitrate*1024)/8);
+               sys->sleep(time);
+       }
+
+
+}
+
+
+// -----------------------------------
+THREAD_PROC    Channel::stream(ThreadInfo *thread)
+{
+//     thread->lock();
+
+       Channel *ch = (Channel *)thread->data;
+
+       LOG_CHANNEL("Channel started");
+
+       while (thread->active && !peercastInst->isQuitting && !thread->finish)
+       {
+               ChanHitList *chl = chanMgr->findHitList(ch->info);
+               if (!chl)
+                       chanMgr->addHitList(ch->info);
+
+               ch->sourceData->stream(ch);
+
+               LOG_CHANNEL("Channel stopped");
+               ch->rawData.init();
+
+               if (!ch->stayConnected)
+               {
+                       thread->active = false;
+                       break;
+               }else
+               {
+                       if (!ch->info.lastPlayEnd)
+                               ch->info.lastPlayEnd = sys->getTime();
+
+                       unsigned int diff = (sys->getTime()-ch->info.lastPlayEnd) + 5;
+
+                       LOG_DEBUG("Channel sleeping for %d seconds",diff);
+                       for(unsigned int i=0; i<diff; i++)
+                       {
+                               if (!thread->active || peercastInst->isQuitting){
+                                       thread->active = false;
+                                       break;
+                               }
+                               sys->sleep(1000);       
+                       }
+               }
+       }
+
+       LOG_DEBUG("thread.active = %d, thread.finish = %d",
+               ch->thread.active, ch->thread.finish);
+
+       if (!thread->finish){
+               ch->endThread(false);
+
+               if (!ch->finthread){
+                       ch->finthread = new ThreadInfo();
+                       ch->finthread->func = waitFinish;
+                       ch->finthread->data = ch;
+                       sys->startThread(ch->finthread);
+               }
+       } else {
+               ch->endThread(true);
+       }
+       return 0;
+}      
+
+// -----------------------------------
+THREAD_PROC Channel::waitFinish(ThreadInfo *thread)
+{
+       Channel *ch = (Channel*)thread->data;
+       LOG_DEBUG("Wait channel finish");
+
+       while(!(ch->thread.finish) && !thread->finish){
+               sys->sleep(1000);
+       }
+
+       if (ch->thread.finish){
+               LOG_DEBUG("channel finish");
+               ch->endThread(true);
+       } else {
+               LOG_DEBUG("channel restart");
+       }
+
+       delete thread;
+       return 0;
+}
+
+// -----------------------------------
+bool Channel::acceptGIV(ClientSocket *givSock)
+{
+       if (!pushSock)
+       {
+               pushSock = givSock;
+               return true;
+       }else
+               return false;
+}
+// -----------------------------------
+void Channel::connectFetch()
+{
+       sock = sys->createSocket();
+       
+       if (!sock)
+               throw StreamException("Can`t create socket");
+
+       if (sourceHost.tracker || sourceHost.yp)
+       {
+               sock->setReadTimeout(30000);
+               sock->setWriteTimeout(30000);
+               LOG_CHANNEL("Channel using longer timeouts");
+       } else {
+               sock->setReadTimeout(5000);
+               sock->setWriteTimeout(5000);
+       }
+
+       sock->open(sourceHost.host);
+               
+       sock->connect();
+}
+
+// -----------------------------------
+int Channel::handshakeFetch()
+{
+       char idStr[64];
+       info.id.toStr(idStr);
+
+       char sidStr[64];
+       servMgr->sessionID.toStr(sidStr);
+
+       sock->writeLineF("GET /channel/%s HTTP/1.0",idStr);
+       sock->writeLineF("%s %d",PCX_HS_POS,streamPos);
+       sock->writeLineF("%s %d",PCX_HS_PCP,1);
+
+       sock->writeLine("");
+
+       HTTP http(*sock);
+
+       int r = http.readResponse();
+
+       LOG_CHANNEL("Got response: %d",r);
+
+       while (http.nextHeader())
+       {
+               char *arg = http.getArgStr();
+               if (!arg) 
+                       continue;
+
+               if (http.isHeader(PCX_HS_POS))
+                       streamPos = atoi(arg);
+               else
+                       Servent::readICYHeader(http, info, NULL);
+
+               LOG_CHANNEL("Channel fetch: %s",http.cmdLine);
+       }
+
+       if ((r != 200) && (r != 503))
+               return r;
+
+       if (!servMgr->keepDownstreams) {
+               if (rawData.getLatestPos() > streamPos)
+                       rawData.init();
+       }
+
+       AtomStream atom(*sock);
+
+       String agent;
+
+       Host rhost = sock->host;
+
+       if (info.srcProtocol == ChanInfo::SP_PCP)
+       {
+               // don`t need PCP_CONNECT here
+               Servent::handshakeOutgoingPCP(atom,rhost,remoteID,agent,sourceHost.yp|sourceHost.tracker);
+       }
+
+       if (r == 503) return 503;
+       return 0;
+
+}
+
+// -----------------------------------
+void PeercastSource::stream(Channel *ch)
+{
+       int numYPTries=0;
+       int numYPTries2=0;
+       bool next_yp = false;
+       bool tracker_check = (ch->trackerHit.host.ip != 0);
+       int connFailCnt = 0;
+
+       ch->lastStopTime = 0;
+       ch->bumped = false;
+
+       while (ch->thread.active)
+       {
+               ch->skipCount = 0; //JP-EX
+               ch->lastSkipTime = 0;
+               
+               ChanHitList *chl = NULL;
+
+               ch->sourceHost.init();
+
+               if (connFailCnt >= 3 && (ch->localListeners() == 0) && (!ch->stayConnected) && !ch->isBroadcasting()) {
+                       ch->lastIdleTime = sys->getTime();
+                       ch->setStatus(Channel::S_IDLE);
+                       ch->skipCount = 0;
+                       ch->lastSkipTime = 0;
+                       break;
+               }
+
+               if (!servMgr->keepDownstreams && !ch->bumped) {
+                       ch->trackerHit.lastContact = sys->getTime() - 30 + (rand() % 30);
+               }
+
+               ch->setStatus(Channel::S_SEARCHING);
+               LOG_CHANNEL("Channel searching for hit..");
+               do 
+               {
+       
+                       if (ch->pushSock)
+                       {
+                               ch->sock = ch->pushSock;
+                               ch->pushSock = NULL;
+                               ch->sourceHost.host = ch->sock->host;
+                               break;
+                       }
+
+                       chanMgr->hitlistlock.on();
+
+                       chl = chanMgr->findHitList(ch->info);
+                       if (chl)
+                       {
+                               ChanHitSearch chs;
+
+                               // find local hit 
+                               if (!ch->sourceHost.host.ip){
+                                       chs.init();
+                                       chs.matchHost = servMgr->serverHost;
+                                       chs.waitDelay = MIN_RELAY_RETRY;
+                                       chs.excludeID = servMgr->sessionID;
+                                       if (chl->pickSourceHits(chs)){
+                                               ch->sourceHost = chs.best[0];
+                                               LOG_DEBUG("use local hit");
+                                       }
+                               }
+                               
+                               // else find global hit
+                               if (!ch->sourceHost.host.ip)
+                               {
+                                       chs.init();
+                                       chs.waitDelay = MIN_RELAY_RETRY;
+                                       chs.excludeID = servMgr->sessionID;
+                                       if (chl->pickSourceHits(chs)){
+                                               ch->sourceHost = chs.best[0];
+                                               LOG_DEBUG("use global hit");
+                                       }
+                               }
+
+
+                               // else find local tracker
+                               if (!ch->sourceHost.host.ip)
+                               {
+                                       chs.init();
+                                       chs.matchHost = servMgr->serverHost;
+                                       chs.waitDelay = MIN_TRACKER_RETRY;
+                                       chs.excludeID = servMgr->sessionID;
+                                       chs.trackersOnly = true;
+                                       if (chl->pickSourceHits(chs)){
+                                               ch->sourceHost = chs.best[0];
+                                               LOG_DEBUG("use local tracker");
+                                       }
+                               }
+
+                               // find tracker
+                               unsigned int ctime = sys->getTime();
+                               if (!ch->sourceHost.host.ip && tracker_check && ch->trackerHit.host.ip){
+                                       if (ch->trackerHit.lastContact + 30 < ctime){
+                                               ch->sourceHost = ch->trackerHit;
+                                               ch->trackerHit.lastContact = ctime;
+                                               LOG_DEBUG("use saved tracker");
+                                       }
+                               }
+
+                               // else find global tracker
+                               if (!ch->sourceHost.host.ip)
+                               {
+                                       chs.init();
+                                       chs.waitDelay = MIN_TRACKER_RETRY;
+                                       chs.excludeID = servMgr->sessionID;
+                                       chs.trackersOnly = true;
+                                       if (chl->pickSourceHits(chs)){
+                                               ch->sourceHost = chs.best[0];
+                                               tracker_check = true;
+                                               ch->trackerHit = chs.best[0];
+                                               LOG_DEBUG("use global tracker");
+                                       }
+                               }
+                       }
+
+                       chanMgr->hitlistlock.off();
+
+                       if (servMgr->keepDownstreams && ch->lastStopTime && ch->lastStopTime < sys->getTime() - 7) {
+                               ch->lastStopTime = 0;
+                               LOG_DEBUG("------------ disconnect all downstreams");
+                               ChanPacket pack;
+                               MemoryStream mem(pack.data,sizeof(pack.data));
+                               AtomStream atom(mem);
+                               atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_OFFAIR);
+                               pack.len = mem.pos;
+                               pack.type = ChanPacket::T_PCP;
+                               GnuID noID;
+                               noID.clear();
+                               servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY);
+
+                               chanMgr->hitlistlock.on();
+                               ChanHitList *hl = chanMgr->findHitList(ch->info);
+                               if (hl){
+                                       hl->clearHits(false);
+                               }
+                               chanMgr->hitlistlock.off();
+                       }
+
+                       // no trackers found so contact YP
+                       if (!tracker_check && !ch->sourceHost.host.ip)
+                       {
+                               next_yp = false;
+                               if (servMgr->rootHost.isEmpty())
+                                       goto yp2;
+
+                               if (numYPTries >= 3)
+                                       goto yp2;
+
+                               if  ((!servMgr->rootHost2.isEmpty()) && (numYPTries > numYPTries2))
+                                       goto yp2;
+
+                               unsigned int ctime=sys->getTime();
+                               if ((ctime-chanMgr->lastYPConnect) > MIN_YP_RETRY)
+                               {
+                                       ch->sourceHost.host.fromStrName(servMgr->rootHost.cstr(),DEFAULT_PORT);
+                                       ch->sourceHost.yp = true;
+                                       chanMgr->lastYPConnect=ctime;
+                                       numYPTries++;
+                               }
+                               if (numYPTries < 3)
+                                       next_yp = true;
+                       }
+
+yp2:
+                       // no trackers found so contact YP2
+                       if (!tracker_check && !ch->sourceHost.host.ip)
+                       {
+//                             next_yp = false;
+                               if (servMgr->rootHost2.isEmpty())
+                                       goto yp0;
+
+                               if (numYPTries2 >= 3)
+                                       goto yp0;
+
+                               unsigned int ctime=sys->getTime();
+                               if ((ctime-chanMgr->lastYPConnect2) > MIN_YP_RETRY)
+                               {
+                                       ch->sourceHost.host.fromStrName(servMgr->rootHost2.cstr(),DEFAULT_PORT);
+                                       ch->sourceHost.yp = true;
+                                       chanMgr->lastYPConnect2=ctime;
+                                       numYPTries2++;
+                               }
+                               if (numYPTries2 < 3)
+                                       next_yp = true;
+                       }
+yp0:
+                       if (!tracker_check && !ch->sourceHost.host.ip && !next_yp) break;
+
+                       sys->sleepIdle();
+
+               }while((ch->sourceHost.host.ip==0) && (ch->thread.active));
+
+               if (!ch->sourceHost.host.ip)
+               {
+                       LOG_ERROR("Channel giving up");
+                       ch->setStatus(Channel::S_ERROR);                        
+                       break;
+               }
+
+               if (ch->sourceHost.yp)
+               {
+                       LOG_CHANNEL("Channel contacting YP, try %d",numYPTries);
+               }else
+               {
+                       LOG_CHANNEL("Channel found hit");
+                       numYPTries=0;
+                       numYPTries2=0;
+               }
+
+               if (ch->sourceHost.host.ip)
+               {
+                       bool isTrusted = ch->sourceHost.tracker | ch->sourceHost.yp;
+
+
+                       //if (ch->sourceHost.tracker)
+                       //      peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Contacting tracker, please wait...");
+                       
+                       char ipstr[64];
+                       ch->sourceHost.host.toStr(ipstr);
+
+                       char *type = "";
+                       if (ch->sourceHost.tracker)
+                               type = "(tracker)";
+                       else if (ch->sourceHost.yp)
+                               type = "(YP)";
+
+                       int error=-1;
+                       int got503 = 0;
+                       try
+                       {
+                               ch->setStatus(Channel::S_CONNECTING);
+                               ch->sourceHost.lastContact = sys->getTime();
+
+                               if (!ch->sock)
+                               {
+                                       LOG_CHANNEL("Channel connecting to %s %s",ipstr,type);
+                                       ch->connectFetch();
+                               }
+
+                               error = ch->handshakeFetch();
+                               if (error == 503) {
+                                       got503 = 1;
+                                       error = 0;
+                               }
+                               if (error)
+                                       throw StreamException("Handshake error");
+                               if (ch->sourceHost.tracker) connFailCnt = 0;
+
+                               if (servMgr->autoMaxRelaySetting) //JP-EX
+                               {       
+                                       double setMaxRelays = ch->info.bitrate?servMgr->maxBitrateOut/(ch->info.bitrate*1.3):0;
+                                       if ((unsigned int)setMaxRelays == 0)
+                                               servMgr->maxRelays = 1;
+                                       else if ((unsigned int)setMaxRelays > servMgr->autoMaxRelaySetting)
+                                               servMgr->maxRelays = servMgr->autoMaxRelaySetting;
+                                       else
+                                               servMgr->maxRelays = (unsigned int)setMaxRelays;
+                               }
+
+                               ch->sourceStream = ch->createSource();
+
+                               error = ch->readStream(*ch->sock,ch->sourceStream);
+                               if (error)
+                                       throw StreamException("Stream error");
+
+                               error = 0;              // no errors, closing normally.
+//                             ch->setStatus(Channel::S_CLOSING);                      
+                               ch->setStatus(Channel::S_IDLE);
+
+                               LOG_CHANNEL("Channel closed normally");
+                       }catch(StreamException &e)
+                       {
+                               ch->setStatus(Channel::S_ERROR);                        
+                               LOG_ERROR("Channel to %s %s : %s",ipstr,type,e.msg);
+                               if (!servMgr->allowConnectPCST) //JP-EX
+                               {
+                                       if (ch->info.srcProtocol == ChanInfo::SP_PEERCAST)
+                                               ch->thread.active = false;
+                               }
+                               //if (!ch->sourceHost.tracker || ((error != 503) && ch->sourceHost.tracker))
+                               if (!ch->sourceHost.tracker || (!got503 && ch->sourceHost.tracker))
+                                       chanMgr->deadHit(ch->sourceHost);
+                               if (ch->sourceHost.tracker && error == -1) {
+                                       LOG_ERROR("can't connect to tracker");
+                                       connFailCnt++;
+                               }
+                       }
+
+                       unsigned int ctime = sys->getTime();
+                       if (ch->rawData.lastWriteTime) {
+                               ch->lastStopTime = ch->rawData.lastWriteTime;
+                               if (isIndexTxt(ch) && ctime - ch->lastStopTime < 60)
+                                       ch->lastStopTime = ctime;
+                       }
+
+                       if (tracker_check && ch->sourceHost.tracker)
+                               ch->trackerHit.lastContact = ctime - 30 + (rand() % 30);
+
+                       // broadcast source host
+                       if (!error && ch->sourceHost.host.ip) { // if closed normally
+                               ChanPacket pack;
+                               MemoryStream mem(pack.data,sizeof(pack.data));
+                               AtomStream atom(mem);
+                               ch->sourceHost.writeAtoms(atom, ch->info.id);
+                               pack.len = mem.pos;
+                               pack.type = ChanPacket::T_PCP;
+                               GnuID noID;
+                               noID.clear();
+                               servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY);
+                               LOG_DEBUG("stream: broadcast sourceHost");
+                       }
+
+                       // broadcast quit to any connected downstream servents
+                       if (!servMgr->keepDownstreams || (ch->sourceHost.tracker && !got503) || !error) {
+                               ChanPacket pack;
+                               MemoryStream mem(pack.data,sizeof(pack.data));
+                               AtomStream atom(mem);
+                               atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_OFFAIR);
+                               pack.len = mem.pos;
+                               pack.type = ChanPacket::T_PCP;
+                               GnuID noID;
+                               noID.clear();
+                               servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY);
+                               LOG_DEBUG("------------ broadcast quit to all downstreams");
+
+                               chanMgr->hitlistlock.on();
+                               ChanHitList *hl = chanMgr->findHitList(ch->info);
+                               if (hl){
+                                       hl->clearHits(false);
+                               }
+                               chanMgr->hitlistlock.off();
+                       }
+
+
+                       if (ch->sourceStream)
+                       {
+                               try
+                               {
+                                       if (!error)
+                                       {
+                                               ch->sourceStream->updateStatus(ch);
+                                               ch->sourceStream->flush(*ch->sock);
+                                       }
+                               }catch(StreamException &)
+                               {}
+                               ChannelStream *cs = ch->sourceStream;
+                               ch->sourceStream = NULL;
+                               cs->kill();
+                               delete cs;
+                       }
+
+                       if (ch->sock)
+                       {
+                               ch->sock->close();
+                               delete ch->sock;
+                               ch->sock = NULL;
+                       }
+
+                       if (error == 404)
+                       {
+                               LOG_ERROR("Channel not found");
+                               //if (!next_yp){
+                               if ((ch->sourceHost.yp && !next_yp) || ch->sourceHost.tracker) {
+                                       chanMgr->hitlistlock.on();
+                                       ChanHitList *hl = chanMgr->findHitList(ch->info);
+                                       if (hl){
+                                               hl->clearHits(true);
+                                       }
+                                       chanMgr->hitlistlock.off();
+
+                                       if(!isIndexTxt(&ch->info))      // for PCRaw (popup)
+                                               peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Channel not found");
+                                       return;
+                               }
+                       }
+
+
+               }
+
+               ch->lastIdleTime = sys->getTime();
+               ch->setStatus(Channel::S_IDLE);
+               ch->skipCount = 0; //JP-EX
+               ch->lastSkipTime = 0;
+               while ((ch->checkIdle()) && (ch->thread.active))
+               {
+                       sys->sleepIdle();
+               }
+
+               sys->sleepIdle();
+       }
+
+}
+// -----------------------------------
+void   Channel::startICY(ClientSocket *cs, SRC_TYPE st)
+{
+       srcType = st;
+       type = T_BROADCAST;
+       cs->setReadTimeout(0);  // stay connected even when theres no data coming through
+       sock = cs;
+       info.srcProtocol = ChanInfo::SP_HTTP;
+
+       streamIndex = ++chanMgr->icyIndex;
+
+       sourceData = new ICYSource();
+       startStream();
+}
+
+// -----------------------------------
+static char *nextMetaPart(char *str,char delim)
+{
+       while (*str)
+       {
+               if (*str == delim)
+               {
+                       *str++ = 0;
+                       return str;
+               }
+               str++;
+       }
+       return NULL;
+}
+// -----------------------------------
+static void copyStr(char *to,char *from,int max)
+{
+       char c;
+       while ((c=*from++) && (--max))
+               if (c != '\'')
+                       *to++ = c;
+
+       *to = 0;
+}
+
+// -----------------------------------
+void Channel::processMp3Metadata(char *str)
+{
+       ChanInfo newInfo = info;
+       
+       char *cmd=str;
+       while (cmd)
+       {
+               char *arg = nextMetaPart(cmd,'=');
+               if (!arg)
+                       break;
+
+               char *next = nextMetaPart(arg,';');
+
+               if (strcmp(cmd,"StreamTitle")==0)
+               {
+                       newInfo.track.title.setUnquote(arg,String::T_ASCII);
+                       newInfo.track.title.convertTo(String::T_UNICODE);
+
+               }else if (strcmp(cmd,"StreamUrl")==0)
+               {
+                       newInfo.track.contact.setUnquote(arg,String::T_ASCII);
+                       newInfo.track.contact.convertTo(String::T_UNICODE);
+               }
+
+
+               cmd = next;
+       }
+
+       updateInfo(newInfo);
+}
+
+// -----------------------------------
+XML::Node *ChanHit::createXML()
+{
+       // IP
+       char ipStr[64];
+       host.toStr(ipStr);
+       
+       return new XML::Node("host ip=\"%s\" hops=\"%d\" listeners=\"%d\" relays=\"%d\" uptime=\"%d\" push=\"%d\" relay=\"%d\" direct=\"%d\" cin=\"%d\" stable=\"%d\" version=\"%d\" update=\"%d\" tracker=\"%d\"",
+               ipStr,
+               numHops,
+               numListeners,
+               numRelays,
+               upTime,
+               firewalled?1:0,
+               relay?1:0,
+               direct?1:0,
+               cin?1:0,
+               stable?1:0,
+               version,
+               sys->getTime()-time,
+               tracker
+               );
+
+}
+
+// -----------------------------------
+XML::Node *ChanHitList::createXML(bool addHits)
+{
+       XML::Node *hn = new XML::Node("hits hosts=\"%d\" listeners=\"%d\" relays=\"%d\" firewalled=\"%d\" closest=\"%d\" furthest=\"%d\" newest=\"%d\"",
+               numHits(),
+               numListeners(),
+               numRelays(),
+               numFirewalled(),
+               closestHit(),
+               furthestHit(),
+               sys->getTime()-newestHit()
+               );              
+
+       if (addHits)
+       {
+               ChanHit *h = hit;
+               while (h)
+               {
+                       if (h->host.ip)
+                               hn->add(h->createXML());
+                       h = h->next;
+               }
+       }
+
+       return hn;
+}
+
+// -----------------------------------
+XML::Node *Channel::createRelayXML(bool showStat)
+{
+       const char *ststr;
+       ststr = getStatusStr();
+       if (!showStat)
+               if ((status == S_RECEIVING) || (status == S_BROADCASTING))
+                       ststr = "OK";
+
+       ChanHitList *chl = chanMgr->findHitList(info);
+
+       return new XML::Node("relay listeners=\"%d\" relays=\"%d\" hosts=\"%d\" status=\"%s\"",
+               localListeners(),
+               localRelays(),
+               (chl!=NULL)?chl->numHits():0,
+               ststr
+               );      
+}
+
+// -----------------------------------
+void ChanMeta::fromXML(XML &xml)
+{
+       MemoryStream tout(data,MAX_DATALEN);
+       xml.write(tout);
+
+       len = tout.pos;
+}
+// -----------------------------------
+void ChanMeta::fromMem(void *p, int l)
+{
+       len = l;
+       memcpy(data,p,len);
+}
+// -----------------------------------
+void ChanMeta::addMem(void *p, int l)
+{
+       if ((len+l) <= MAX_DATALEN)
+       {
+               memcpy(data+len,p,l);
+               len += l;
+       }
+}
+// -----------------------------------
+void Channel::broadcastTrackerUpdate(GnuID &svID, bool force)
+{
+       unsigned int ctime = sys->getTime();
+
+       if (((ctime-lastTrackerUpdate) > 30) || (force))
+       {
+               ChanPacket pack;
+
+               MemoryStream mem(pack.data,sizeof(pack));
+
+               AtomStream atom(mem);
+                       
+               ChanHit hit;
+
+               ChanHitList *chl = chanMgr->findHitListByID(info.id);
+               if (!chl)
+                       throw StreamException("Broadcast channel has no hitlist");
+
+               int numListeners = totalListeners();
+               int numRelays = totalRelays();
+
+               unsigned int oldp = rawData.getOldestPos();
+               unsigned int newp = rawData.getLatestPos();
+
+               hit.initLocal(numListeners,numRelays,info.numSkips,info.getUptime(),isPlaying(), false, 0, this, oldp,newp);
+               hit.tracker = true;
+
+#ifndef VERSION_EX
+               atom.writeParent(PCP_BCST,8);
+#else
+               atom.writeParent(PCP_BCST,10);
+#endif
+                       atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_ROOT);
+                       atom.writeChar(PCP_BCST_HOPS,0);
+                       atom.writeChar(PCP_BCST_TTL,11);
+                       atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
+                       atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
+                       atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
+#ifdef VERSION_EX
+                       atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
+                       atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
+#endif
+                       atom.writeParent(PCP_CHAN,4);
+                               atom.writeBytes(PCP_CHAN_ID,info.id.id,16);
+                               atom.writeBytes(PCP_CHAN_BCID,chanMgr->broadcastID.id,16);
+                               info.writeInfoAtoms(atom);
+                               info.writeTrackAtoms(atom);
+                       hit.writeAtoms(atom,info.id);
+
+
+               pack.len = mem.pos;
+               pack.type = ChanPacket::T_PCP;
+
+               GnuID noID;
+               noID.clear();
+               int cnt = servMgr->broadcastPacket(pack,noID,servMgr->sessionID,svID,Servent::T_COUT);
+
+               if (cnt)
+               {
+                       LOG_DEBUG("Sent tracker update for %s to %d client(s)",info.name.cstr(),cnt);
+                       lastTrackerUpdate = ctime;
+               }
+       }
+}
+
+// -----------------------------------
+bool   Channel::sendPacketUp(ChanPacket &pack,GnuID &cid,GnuID &sid,GnuID &did)
+{
+       if ( isActive() 
+               && (!cid.isSet() || info.id.isSame(cid)) 
+               && (!sid.isSet() || !remoteID.isSame(sid))
+               && sourceStream 
+          )
+               return sourceStream->sendPacket(pack,did);
+
+       return false;
+}
+
+// -----------------------------------
+void Channel::updateInfo(ChanInfo &newInfo)
+{
+       if (info.update(newInfo))
+       {
+               if (isBroadcasting())
+               {
+                       unsigned int ctime = sys->getTime();
+                       if ((ctime-lastMetaUpdate) > 30)
+                       {
+                               lastMetaUpdate = ctime;
+
+                               ChanPacket pack;
+
+                               MemoryStream mem(pack.data,sizeof(pack));
+
+                               AtomStream atom(mem);
+
+#ifndef VERSION_EX
+                               atom.writeParent(PCP_BCST,8);
+#else
+                               atom.writeParent(PCP_BCST,10);
+#endif
+                                       atom.writeChar(PCP_BCST_HOPS,0);
+                                       atom.writeChar(PCP_BCST_TTL,7);
+                                       atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_RELAYS);
+                                       atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
+                                       atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
+                                       atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
+#ifdef VERSION_EX
+                                       atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
+                                       atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
+#endif
+                                       atom.writeBytes(PCP_BCST_CHANID,info.id.id,16);
+                                       atom.writeParent(PCP_CHAN,3);
+                                               atom.writeBytes(PCP_CHAN_ID,info.id.id,16);
+                                               info.writeInfoAtoms(atom);
+                                               info.writeTrackAtoms(atom);
+
+                               pack.len = mem.pos;
+                               pack.type = ChanPacket::T_PCP;
+                               GnuID noID;
+                               noID.clear();
+                               servMgr->broadcastPacket(pack,info.id,servMgr->sessionID,noID,Servent::T_RELAY);
+
+                               broadcastTrackerUpdate(noID);
+                       }
+               }
+
+               ChanHitList *chl = chanMgr->findHitList(info);
+               if (chl)
+                       chl->info = info;
+
+               peercastApp->channelUpdate(&info);
+
+       }
+
+}
+// -----------------------------------
+ChannelStream *Channel::createSource()
+{
+//     if (servMgr->relayBroadcast)
+//             chanMgr->broadcastRelays(NULL,chanMgr->minBroadcastTTL,chanMgr->maxBroadcastTTL);
+
+
+       ChannelStream *source=NULL;
+
+       if (info.srcProtocol == ChanInfo::SP_PEERCAST)
+       {
+               LOG_CHANNEL("Channel is Peercast");
+               if (servMgr->allowConnectPCST) //JP-EX
+                       source = new PeercastStream();
+               else
+                       throw StreamException("Channel is not allowed");
+       }
+       else if (info.srcProtocol == ChanInfo::SP_PCP)
+       {
+               LOG_CHANNEL("Channel is PCP");
+               PCPStream *pcp = new PCPStream(remoteID);
+               source = pcp;
+       }
+       else if (info.srcProtocol == ChanInfo::SP_MMS)
+       {
+               LOG_CHANNEL("Channel is MMS");
+               source = new MMSStream();
+       }else
+       {
+               switch(info.contentType)
+               {
+                       case ChanInfo::T_MP3:
+                               LOG_CHANNEL("Channel is MP3 - meta: %d",icyMetaInterval);
+                               source = new MP3Stream();
+                               break;
+                       case ChanInfo::T_NSV:
+                               LOG_CHANNEL("Channel is NSV");
+                               source = new NSVStream();
+                               break;
+                       case ChanInfo::T_WMA:
+                       case ChanInfo::T_WMV:
+                               throw StreamException("Channel is WMA/WMV - but not MMS");
+                               break;
+                       case ChanInfo::T_OGG:
+                       case ChanInfo::T_OGM:
+                               LOG_CHANNEL("Channel is OGG");
+                               source = new OGGStream();
+                               break;
+                       default:
+                               LOG_CHANNEL("Channel is Raw");
+                               source = new RawStream();
+                               break;
+               }
+       }
+
+       source->parent = this;
+
+       return source;
+}
+// ------------------------------------------
+void ChannelStream::updateStatus(Channel *ch)
+{
+       ChanPacket pack;
+       if (getStatus(ch,pack))
+       {
+               if (!ch->isBroadcasting())
+               {
+                       GnuID noID;
+                       noID.clear();
+                       int cnt = chanMgr->broadcastPacketUp(pack,ch->info.id,servMgr->sessionID,noID);
+                       LOG_CHANNEL("Sent channel status update to %d clients",cnt);
+               }
+       }
+}
+
+// ------------------------------------------
+bool ChannelStream::getStatus(Channel *ch,ChanPacket &pack)
+{
+       unsigned int ctime = sys->getTime();
+
+       ChanHitList *chl = chanMgr->findHitListByID(ch->info.id);
+
+       if (!chl)
+               return false;
+
+/*     int newLocalListeners = ch->localListeners();
+       int newLocalRelays = ch->localRelays();
+
+       if (
+               (
+               (numListeners != newLocalListeners) 
+               || (numRelays != newLocalRelays) 
+               || (ch->isPlaying() != isPlaying) 
+               || (servMgr->getFirewall() != fwState)
+               || (((ctime-lastUpdate)>chanMgr->hostUpdateInterval) && chanMgr->hostUpdateInterval)
+               )
+               && ((ctime-lastUpdate) > 10)
+          )
+       {
+
+               numListeners = newLocalListeners;
+               numRelays = newLocalRelays;
+               isPlaying = ch->isPlaying();
+               fwState = servMgr->getFirewall();
+               lastUpdate = ctime;
+
+               ChanHit hit;
+
+               hit.initLocal(ch->localListeners(),ch->localRelays(),ch->info.numSkips,ch->info.getUptime(),isPlaying, ch->isFull(), ch->info.bitrate, ch);
+               hit.tracker = ch->isBroadcasting();*/
+
+       int newLocalListeners = ch->localListeners();
+       int newLocalRelays = ch->localRelays();
+
+       if ((ch->isPlaying() == isPlaying)){
+               if ((ctime-lastUpdate) < 10){
+                       return false;
+               }
+
+               if ((ctime-lastCheckTime) < 10){
+                       return false;
+               }
+               lastCheckTime = ctime;
+       }
+
+       unsigned int oldp = ch->rawData.getOldestPos();
+       unsigned int newp = ch->rawData.getLatestPos();
+
+       ChanHit hit;
+
+//     LOG_DEBUG("isPlaying-------------------------------------- %d %d", ch->isPlaying(), isPlaying);
+
+       hit.initLocal(newLocalListeners,newLocalRelays,ch->info.numSkips,ch->info.getUptime(),ch->isPlaying(), ch->isFull(), ch->info.bitrate, ch, oldp, newp);
+       hit.tracker = ch->isBroadcasting();
+
+       if      (       (((ctime-lastUpdate)>chanMgr->hostUpdateInterval) && chanMgr->hostUpdateInterval)
+               ||      (newLocalListeners != numListeners)
+               ||      (newLocalRelays != numRelays)
+               ||      (ch->isPlaying() != isPlaying)
+               ||      (servMgr->getFirewall() != fwState)
+               ||      (ch->chDisp.relay != hit.relay)
+               ||      (ch->chDisp.relayfull != hit.relayfull)
+               ||      (ch->chDisp.chfull != hit.chfull)
+               ||      (ch->chDisp.ratefull != hit.ratefull)   
+       ){
+               numListeners = newLocalListeners;
+               numRelays = newLocalRelays;
+               isPlaying = ch->isPlaying();
+               fwState = servMgr->getFirewall();
+               lastUpdate = ctime;
+       
+               ch->chDisp = hit;
+
+               if ((numRelays) && ((servMgr->getFirewall() == ServMgr::FW_OFF) && (servMgr->autoRelayKeep!=0))) //JP-EX
+                       ch->stayConnected = true;
+
+               if ((!numRelays && !numListeners) && (servMgr->autoRelayKeep==2)) //JP-EX
+                       ch->stayConnected = false;
+
+               MemoryStream pmem(pack.data,sizeof(pack.data));
+               AtomStream atom(pmem);
+
+               GnuID noID;
+               noID.clear();
+
+#ifndef VERSION_EX
+                       atom.writeParent(PCP_BCST,8);
+#else
+                       atom.writeParent(PCP_BCST,10);
+#endif
+                       atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_TRACKERS);
+                       atom.writeChar(PCP_BCST_HOPS,0);
+                       atom.writeChar(PCP_BCST_TTL,11);
+                       atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
+                       atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
+                       atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
+#ifdef VERSION_EX
+                       atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
+                       atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
+#endif
+                       atom.writeBytes(PCP_BCST_CHANID,ch->info.id.id,16);
+                       hit.writeAtoms(atom,noID);
+
+               pack.len = pmem.pos;
+               pack.type = ChanPacket::T_PCP;
+               return true;
+       }else
+               return false;
+}
+// -----------------------------------
+bool   Channel::checkBump()
+{
+       if (!isBroadcasting() && (!sourceHost.tracker))
+               if (rawData.lastWriteTime && ((sys->getTime() - rawData.lastWriteTime) > 30))
+               {
+                       LOG_ERROR("Channel Auto bumped");
+                       bump = true;
+               }
+       
+       if (bump)
+       {
+               bump = false;
+               return true;
+       }else
+               return false;
+}
+
+// -----------------------------------
+int Channel::readStream(Stream &in,ChannelStream *source)
+{
+       //sys->sleep(300);
+
+       int error = 0;
+
+       info.numSkips = 0;
+
+       source->readHeader(in,this);
+
+       peercastApp->channelStart(&info);
+
+       rawData.lastWriteTime = 0;
+
+       bool wasBroadcasting=false;
+
+       unsigned int receiveStartTime = 0;
+
+       try
+       {
+               while (thread.active && !peercastInst->isQuitting)
+               {                       
+                       if (checkIdle())
+                       {
+                               LOG_DEBUG("Channel idle");
+                               break;
+                       }
+
+                       if (checkBump())
+                       {
+                               LOG_DEBUG("Channel bumped");
+                               error = -1;
+                               bumped = true;
+                               break;
+                       }
+
+                       if (in.eof())
+                       {
+                               LOG_DEBUG("Channel eof");
+                               break;
+                       }
+
+                       if (in.readReady())
+                       {
+                               error = source->readPacket(in,this);
+
+                               if (error)
+                                       break;
+
+                               //if (rawData.writePos > 0)
+                               if (rawData.lastWriteTime > 0)
+                               {
+                                       if (isBroadcasting())
+                                       {                                       
+                                               if ((sys->getTime()-lastTrackerUpdate) >= chanMgr->hostUpdateInterval)
+                                               {
+                                                       GnuID noID;
+                                                       noID.clear();
+                                                       broadcastTrackerUpdate(noID);
+                                               }
+                                               wasBroadcasting = true;
+
+                                       }else
+                                       {
+/*                                             if (status != Channel::S_RECEIVING){
+                                                       receiveStartTime = sys->getTime();
+                                               } else if (receiveStartTime && receiveStartTime + 10 > sys->getTime()){
+                                                       chanMgr->hitlistlock.on();
+                                                       ChanHitList *hl = chanMgr->findHitList(info);
+                                                       if (hl){
+                                                               hl->clearHits(true);
+                                                       }
+                                                       chanMgr->hitlistlock.off();
+                                                       receiveStartTime = 0;
+                                               }*/
+                                               setStatus(Channel::S_RECEIVING);
+                                               bumped = false;
+                                       }
+                                       source->updateStatus(this);
+                               }
+                       }
+
+                       source->flush(in);
+
+                       sys->sleepIdle();
+               }
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("readStream: %s",e.msg);
+               error = -1;
+       }
+
+       if (!servMgr->keepDownstreams) {
+               if (status == Channel::S_RECEIVING){
+                       chanMgr->hitlistlock.on();
+                       ChanHitList *hl = chanMgr->findHitList(info);
+                       if (hl){
+                               hl->clearHits(false);
+                       }
+                       chanMgr->hitlistlock.off();
+               }
+       }
+
+//     setStatus(S_CLOSING);
+       setStatus(S_IDLE);
+
+       if (wasBroadcasting)
+       {
+               GnuID noID;
+               noID.clear();
+               broadcastTrackerUpdate(noID,true);
+       }
+
+       peercastApp->channelStop(&info);
+
+       source->readEnd(in,this);
+
+       return error;
+}
+
+// -----------------------------------
+void PeercastStream::readHeader(Stream &in,Channel *ch)
+{
+       if (in.readTag() != 'PCST')
+               throw StreamException("Not PeerCast stream");
+
+}
+// -----------------------------------
+void PeercastStream::readEnd(Stream &,Channel *)
+{
+
+}
+// -----------------------------------
+int PeercastStream::readPacket(Stream &in,Channel *ch)
+{
+       ChanPacket pack;
+
+       {
+
+               pack.readPeercast(in);
+
+               MemoryStream mem(pack.data,pack.len);
+
+               switch(pack.type)
+               {
+                       case ChanPacket::T_HEAD:
+                               // update sync pos
+                               ch->headPack = pack;
+                               pack.pos = ch->streamPos;
+                               ch->newPacket(pack);
+                               ch->streamPos+=pack.len;
+                               break;
+                       case ChanPacket::T_DATA:
+                               pack.pos = ch->streamPos;
+                               ch->newPacket(pack);
+                               ch->streamPos+=pack.len;
+                               break;
+                       case ChanPacket::T_META:
+                               ch->insertMeta.fromMem(pack.data,pack.len);
+                               {
+                                       if (pack.len)
+                                       {
+                                               XML xml;
+                                               xml.read(mem);
+                                               XML::Node *n = xml.findNode("channel");                                 
+                                               if (n)
+                                               {
+                                                       ChanInfo newInfo = ch->info;
+                                                       newInfo.updateFromXML(n);
+                                                       ChanHitList *chl = chanMgr->findHitList(ch->info);
+                                                       if (chl)
+                                                               newInfo.updateFromXML(n);
+                                                       ch->updateInfo(newInfo);
+                                               }
+                                       }
+                               }
+                               break;
+#if 0
+                       case ChanPacket::T_SYNC:
+                               {
+                                       unsigned int s = mem.readLong();
+                                       if ((s-ch->syncPos) != 1)
+                                       {
+                                               LOG_CHANNEL("Ch.%d SKIP: %d to %d (%d)",ch->index,ch->syncPos,s,ch->info.numSkips);
+                                               if (ch->syncPos)
+                                               {
+                                                       ch->info.numSkips++;
+                                                       if (ch->info.numSkips>50)
+                                                               throw StreamException("Bumped - Too many skips");
+                                               }
+                                       }
+
+                                       ch->syncPos = s;
+                               }
+                               break;
+#endif
+
+               }
+
+       }
+       return 0;
+}
+
+// -----------------------------------
+void ChannelStream::readRaw(Stream &in, Channel *ch)
+{
+       ChanPacket pack;
+
+       const int readLen = 8192;
+
+       pack.init(ChanPacket::T_DATA,pack.data,readLen,ch->streamPos);
+       in.read(pack.data,pack.len);
+       ch->newPacket(pack);
+       ch->checkReadDelay(pack.len);
+
+       ch->streamPos+=pack.len;
+
+}
+// ------------------------------------------
+void RawStream::readHeader(Stream &,Channel *)
+{
+}
+
+// ------------------------------------------
+int RawStream::readPacket(Stream &in,Channel *ch)
+{
+       readRaw(in,ch);
+       return 0;
+}
+
+// ------------------------------------------
+void RawStream::readEnd(Stream &,Channel *)
+{
+}
+
+
+
+// -----------------------------------
+void ChanPacket::init(ChanPacketv &p)
+{
+       type = p.type;
+       len = p.len;
+       pos = p.pos;
+       sync = p.sync;
+       skip = p.skip;
+       memcpy(data, p.data, len);
+}
+// -----------------------------------
+void ChanPacket::init(TYPE t, const void *p, unsigned int l,unsigned int _pos)
+{
+       type = t;
+       if (l > MAX_DATALEN)
+               throw StreamException("Packet data too large");
+       len = l;
+       memcpy(data,p,len);
+       pos = _pos;
+       skip = false;
+}
+// -----------------------------------
+void ChanPacket::writeRaw(Stream &out)
+{
+       out.write(data,len);
+}
+// -----------------------------------
+void ChanPacket::writePeercast(Stream &out)
+{
+       unsigned int tp = 0;
+       switch (type)
+       {
+               case T_HEAD: tp = 'HEAD'; break;
+               case T_META: tp = 'META'; break;
+               case T_DATA: tp = 'DATA'; break;
+       }
+
+       if (type != T_UNKNOWN)
+       {
+               out.writeTag(tp);
+               out.writeShort(len);
+               out.writeShort(0);
+               out.write(data,len);
+       }
+}
+// -----------------------------------
+void ChanPacket::readPeercast(Stream &in)
+{
+       unsigned int tp = in.readTag();
+
+       switch (tp)
+       {
+               case 'HEAD':    type = T_HEAD; break;
+               case 'DATA':    type = T_DATA; break;
+               case 'META':    type = T_META; break;
+               default:                type = T_UNKNOWN;
+       }
+       len = in.readShort();
+       in.readShort();
+       if (len > MAX_DATALEN)
+               throw StreamException("Bad ChanPacket");
+       in.read(data,len);
+}
+// -----------------------------------
+int ChanPacketBuffer::copyFrom(ChanPacketBuffer &buf, unsigned int reqPos)
+{
+       lock.on();
+       buf.lock.on();
+
+       firstPos = 0;
+       lastPos = 0;
+       safePos = 0;
+       readPos = 0;
+
+       for(unsigned int i=buf.firstPos; i<=buf.lastPos; i++)
+       {
+               //ChanPacket *src = &buf.packets[i%MAX_PACKETS];
+               ChanPacketv *src = &buf.packets[i%MAX_PACKETS];
+               if (src->type & accept)
+               {
+                       if (src->pos >= reqPos)
+                       {
+                               lastPos = writePos;
+                               //packets[writePos++] = *src;
+                               packets[writePos++].init(*src);
+                       }
+               }
+
+       }
+
+
+       buf.lock.off();
+       lock.off();
+       return lastPos-firstPos;
+}
+
+// -----------------------------------
+bool ChanPacketBuffer::findPacket(unsigned int spos, ChanPacket &pack)
+{
+       if (writePos == 0)
+               return false;
+
+       lock.on();
+
+       unsigned int fpos = getStreamPos(firstPos);
+       if (spos < fpos)
+               spos = fpos;
+
+
+       for(unsigned int i=firstPos; i<=lastPos; i++)
+       {
+               //ChanPacket &p = packets[i%MAX_PACKETS];
+               ChanPacketv &p = packets[i%MAX_PACKETS];
+               if (p.pos >= spos)
+               {
+                       pack.init(p);
+                       lock.off();
+                       return true;
+               }
+       }
+
+       lock.off();
+       return false;
+}
+// -----------------------------------
+unsigned int   ChanPacketBuffer::getLatestPos()
+{
+       if (!writePos)
+               return 0;
+       else
+               return getStreamPos(lastPos);
+               
+}
+// -----------------------------------
+unsigned int   ChanPacketBuffer::getOldestPos()
+{
+       if (!writePos)
+               return 0;
+       else
+               return getStreamPos(firstPos);
+}
+
+// -----------------------------------
+unsigned int   ChanPacketBuffer::findOldestPos(unsigned int spos)
+{
+       unsigned int min = getStreamPos(safePos);
+       unsigned int max = getStreamPos(lastPos);
+
+       if (min > spos)
+               return min;
+
+       if (max < spos)
+               return max;
+
+       return spos;
+}
+
+// -----------------------------------
+unsigned int   ChanPacketBuffer::getStreamPos(unsigned int index)
+{
+       return packets[index%MAX_PACKETS].pos;
+}
+// -----------------------------------
+unsigned int   ChanPacketBuffer::getStreamPosEnd(unsigned int index)
+{
+       return packets[index%MAX_PACKETS].pos+packets[index%MAX_PACKETS].len;
+}
+// -----------------------------------
+bool ChanPacketBuffer::writePacket(ChanPacket &pack, bool updateReadPos)
+{
+       if (pack.len)
+       {
+               if (servMgr->keepDownstreams) {
+                       unsigned int lpos = getLatestPos();
+                       unsigned int diff = pack.pos - lpos;
+                       if (packets[lastPos%MAX_PACKETS].type == ChanPacket::T_HEAD) lpos = 0;
+                       if (lpos && (diff == 0 || diff > 0xfff00000)) {
+                               LOG_DEBUG("*   latest pos=%d, pack pos=%d", getLatestPos(), pack.pos);
+                               return false;
+                       }
+               }
+
+               if (willSkip()) // too far behind
+               {
+                       lastSkipTime = sys->getTime();
+                       return false;
+               }
+
+               lock.on();
+
+               pack.sync = writePos;
+               packets[writePos%MAX_PACKETS].init(pack);
+
+//             LOG_DEBUG("packet.len = %d",pack.len);
+
+
+               lastPos = writePos;
+               writePos++;
+
+               if (writePos >= MAX_PACKETS)
+                       firstPos = writePos-MAX_PACKETS;
+               else
+                       firstPos = 0;
+
+               if (writePos >= NUM_SAFEPACKETS)
+                       safePos = writePos - NUM_SAFEPACKETS;
+               else
+                       safePos = 0;
+
+               if (updateReadPos)
+                       readPos = writePos;
+
+               lastWriteTime = sys->getTime();
+
+               lock.off();
+               return true;
+       }
+
+       return false;
+}
+// -----------------------------------
+void   ChanPacketBuffer::readPacket(ChanPacket &pack)
+{
+
+       unsigned int tim = sys->getTime();
+
+       if (readPos < firstPos) 
+               throw StreamException("Read too far behind");
+
+       while (readPos >= writePos)
+       {
+               sys->sleepIdle();
+               if ((sys->getTime() - tim) > 30)
+                       throw TimeoutException();
+       }
+       lock.on();
+       pack.init(packets[readPos%MAX_PACKETS]);
+       readPos++;
+       lock.off();
+
+       sys->sleepIdle();
+
+}
+// -----------------------------------
+bool   ChanPacketBuffer::willSkip()
+{
+       return ((writePos-readPos) >= MAX_PACKETS);
+}
+
+// -----------------------------------
+void Channel::getStreamPath(char *str)
+{
+       char idStr[64];
+
+       getIDStr(idStr);
+
+       sprintf(str,"/stream/%s%s",idStr,info.getTypeExt(info.contentType));
+}
+
+
+
+// -----------------------------------
+void ChanMgr::startSearch(ChanInfo &info)
+{
+       searchInfo = info;
+       clearHitLists();
+       numFinds = 0;
+       lastHit = 0;
+//     lastSearch = 0;
+       searchActive = true;
+}
+// -----------------------------------
+void ChanMgr::quit()
+{
+       LOG_DEBUG("ChanMgr is quitting..");
+       closeAll();
+}
+// -----------------------------------
+int ChanMgr::numIdleChannels()
+{
+       int cnt=0;
+       Channel *ch = channel;
+       while (ch)
+       {
+               if (ch->isActive())
+                       if (ch->thread.active)
+                               if (ch->status == Channel::S_IDLE)
+                                       cnt++;
+               ch=ch->next;
+       }
+       return cnt;
+}
+// -----------------------------------
+void ChanMgr::closeOldestIdle()
+{
+       unsigned int idleTime = (unsigned int)-1;
+       Channel *ch = channel,*oldest=NULL;
+       while (ch)
+       {
+               if (ch->isActive())
+                       if (ch->thread.active)
+                               if (ch->status == Channel::S_IDLE)
+                                       if (ch->lastIdleTime < idleTime)
+                                       {
+                                               oldest = ch;
+                                               idleTime = ch->lastIdleTime;
+                                       }
+               ch=ch->next;
+       }
+
+       if (oldest)
+               oldest->thread.active = false;
+}
+
+// -----------------------------------
+void ChanMgr::closeAll()
+{
+       Channel *ch = channel;
+       while (ch)
+       {
+               if (ch->thread.active)
+                       ch->thread.shutdown();
+               ch=ch->next;
+       }
+}
+// -----------------------------------
+Channel *ChanMgr::findChannelByNameID(ChanInfo &info)
+{
+       Channel *ch = channel;
+       while (ch)
+       {
+               if (ch->isActive())
+                       if (ch->info.matchNameID(info))
+                               return ch;
+               ch=ch->next;
+       }
+       return NULL;
+}
+
+// -----------------------------------
+Channel *ChanMgr::findChannelByName(const char *n)
+{
+       Channel *ch = channel;
+       while (ch)
+       {
+               if (ch->isActive())
+                       if (stricmp(ch->info.name,n)==0)
+                               return ch;
+               ch=ch->next;
+       }
+
+       return NULL;
+}
+// -----------------------------------
+Channel *ChanMgr::findChannelByIndex(int index)
+{
+       int cnt=0;
+       Channel *ch = channel;
+       while (ch)
+       {
+               if (ch->isActive())
+               {
+                       if (cnt == index)
+                               return ch;
+                       cnt++;
+               }
+               ch=ch->next;
+       }
+       return NULL;
+}      
+// -----------------------------------
+Channel *ChanMgr::findChannelByMount(const char *str)
+{
+       Channel *ch = channel;
+       while (ch)
+       {
+               if (ch->isActive())
+                       if (strcmp(ch->mount,str)==0)
+                               return ch;
+               ch=ch->next;
+       }
+
+       return NULL;
+}      
+// -----------------------------------
+Channel *ChanMgr::findChannelByID(GnuID &id)
+{
+       Channel *ch = channel;
+       while (ch)
+       {
+               if (ch->isActive())
+                       if (ch->info.id.isSame(id))
+                               return ch;
+               ch=ch->next;
+       }
+       return NULL;
+}      
+// -----------------------------------
+Channel *ChanMgr::findChannelByChannelID(int id)
+{
+       int cnt=0;
+       Channel *ch = channel;
+       while (ch)
+       {
+               if (ch->isActive()){
+                       if (ch->channel_id == id){
+                               return ch;
+                       }
+               }
+               ch = ch->next;
+       }
+       return NULL;
+}
+// -----------------------------------
+int ChanMgr::findChannels(ChanInfo &info, Channel **chlist, int max)
+{
+       int cnt=0;
+       Channel *ch = channel;
+       while (ch)
+       {
+               if (ch->isActive())
+                       if (ch->info.match(info))
+                       {
+                               chlist[cnt++] = ch;
+                               if (cnt >= max)
+                                       break;
+                       }
+               ch=ch->next;
+       }
+       return cnt;
+}
+// -----------------------------------
+int ChanMgr::findChannelsByStatus(Channel **chlist, int max, Channel::STATUS status)
+{
+       int cnt=0;
+       Channel *ch = channel;
+       while (ch)
+       {
+               if (ch->isActive())
+                       if (ch->status == status)
+                       {
+                               chlist[cnt++] = ch;
+                               if (cnt >= max)
+                                       break;
+                       }
+               ch=ch->next;
+       }
+       return cnt;
+}
+// -----------------------------------
+Channel *ChanMgr::createRelay(ChanInfo &info, bool stayConnected)
+{
+       Channel *c = chanMgr->createChannel(info,NULL);
+       if (c)
+       {
+               c->stayConnected = stayConnected;
+               c->startGet();
+               return c;
+       }
+       return NULL;
+}
+// -----------------------------------
+Channel *ChanMgr::findAndRelay(ChanInfo &info)
+{
+       char idStr[64];
+       info.id.toStr(idStr);
+       LOG_CHANNEL("Searching for: %s (%s)",idStr,info.name.cstr());
+
+       if(!isIndexTxt(&info))  // for PCRaw (popup)
+               peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Finding channel...");
+
+
+       Channel *c = NULL;
+
+       WLockBlock wb(&(chanMgr->channellock));
+
+       wb.on();
+
+       c = findChannelByNameID(info);
+
+       if (!c)
+       {
+               c = chanMgr->createChannel(info,NULL);
+               if (c)
+               {
+                       c->setStatus(Channel::S_SEARCHING);                     
+                       c->startGet();
+               }
+       } else if (!(c->thread.active)){
+               c->thread.active = true;
+               c->thread.finish = false;
+               if (c->finthread){
+                       c->finthread->finish = true;
+                       c->finthread = NULL;
+               }
+               if (c->status != Channel::S_CONNECTING && c->status != Channel::S_SEARCHING){
+                       c->setStatus(Channel::S_SEARCHING);     
+                       c->startGet();
+               }
+       }
+
+       wb.off();
+
+       for(int i=0; i<600; i++)        // search for 1 minute.
+       {
+
+
+               wb.on();
+               c = findChannelByNameID(info);
+
+               if (!c)
+               {
+//                     peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Channel not found");
+                       return NULL;
+               }
+
+               
+               if (c->isPlaying() && (c->info.contentType!=ChanInfo::T_UNKNOWN))
+                       break;
+
+               wb.off();
+
+               sys->sleep(100);
+       }
+
+       return c;
+}
+// -----------------------------------
+ChanMgr::ChanMgr()
+{
+       channel = NULL;
+       
+       hitlist = NULL;
+
+       currFindAndPlayChannel.clear();
+
+       broadcastMsg.clear();
+       broadcastMsgInterval=10;
+
+       broadcastID.generate(PCP_BROADCAST_FLAGS);
+
+       deadHitAge = 600;
+
+       icyIndex = 0;
+       icyMetaInterval = 8192; 
+       maxRelaysPerChannel = 1;
+
+       searchInfo.init();
+
+       minBroadcastTTL = 1;
+       maxBroadcastTTL = 7;
+
+       pushTimeout = 60;       // 1 minute
+       pushTries = 5;          // 5 times
+       maxPushHops = 8;        // max 8 hops away
+       maxUptime = 0;          // 0 = none
+
+       prefetchTime = 10;      // n seconds
+
+       hostUpdateInterval = 120; // 2 minutes
+
+       bufferTime = 5;
+
+       autoQuery = 0;  
+       lastQuery = 0;
+
+       lastYPConnect = 0;
+       lastYPConnect2 = 0;
+
+}
+
+// -----------------------------------
+bool ChanMgr::writeVariable(Stream &out, const String &var, int index)
+{
+       char buf[1024];
+       if (var == "numHitLists")
+               sprintf(buf,"%d",numHitLists());
+       
+       else if (var == "numChannels")
+               sprintf(buf,"%d",numChannels());
+       else if (var == "djMessage")
+               strcpy(buf,broadcastMsg.cstr());
+       else if (var == "icyMetaInterval")
+               sprintf(buf,"%d",icyMetaInterval);
+       else if (var == "maxRelaysPerChannel")
+               sprintf(buf,"%d",maxRelaysPerChannel);
+       else if (var == "hostUpdateInterval")
+               sprintf(buf,"%d",hostUpdateInterval);
+       else if (var == "broadcastID")
+               broadcastID.toStr(buf);
+       else
+               return false;
+
+
+
+       out.writeString(buf);
+       return true;
+}
+
+// -----------------------------------
+bool Channel::writeVariable(Stream &out, const String &var, int index)
+{
+       char buf[1024];
+
+       buf[0]=0;
+
+       String utf8;
+
+       if (var == "name")
+       {
+               utf8 = info.name;
+               utf8.convertTo(String::T_UNICODESAFE);
+               strcpy(buf,utf8.cstr());
+
+       }else if (var == "bitrate")
+       {
+               sprintf(buf,"%d",info.bitrate);
+
+       }else if (var == "srcrate")
+       {
+               if (sourceData)
+               {
+                       unsigned int tot = sourceData->getSourceRate();
+                       sprintf(buf,"%.1f",BYTES_TO_KBPS(tot));
+               }else
+                       strcpy(buf,"0");
+
+       }else if (var == "genre")
+       {
+               utf8 = info.genre;
+               utf8.convertTo(String::T_UNICODESAFE);
+               strcpy(buf,utf8.cstr());
+       }else if (var == "desc")
+       {
+               utf8 = info.desc;
+               utf8.convertTo(String::T_UNICODESAFE);
+               strcpy(buf,utf8.cstr());
+       }else if (var == "comment")
+       {
+               utf8 = info.comment;
+               utf8.convertTo(String::T_UNICODESAFE);
+               strcpy(buf,utf8.cstr());
+       }else if (var == "uptime")
+       {
+               String uptime;
+               if (info.lastPlayStart)
+                       uptime.setFromStopwatch(sys->getTime()-info.lastPlayStart);
+               else
+                       uptime.set("-");
+               strcpy(buf,uptime.cstr());
+       }
+       else if (var == "type")
+               sprintf(buf,"%s",ChanInfo::getTypeStr(info.contentType));
+       else if (var == "ext")
+               sprintf(buf,"%s",ChanInfo::getTypeExt(info.contentType));
+       else if (var == "proto") {
+               switch(info.contentType) {
+               case ChanInfo::T_WMA:
+               case ChanInfo::T_WMV:
+                       sprintf(buf, "mms://");
+                       break;
+               default:
+                       sprintf(buf, "http://");
+               }
+       }
+       else if (var == "localRelays")
+               sprintf(buf,"%d",localRelays());
+       else if (var == "localListeners")
+               sprintf(buf,"%d",localListeners());
+
+       else if (var == "totalRelays")
+               sprintf(buf,"%d",totalRelays());
+       else if (var == "totalListeners")
+               sprintf(buf,"%d",totalListeners());
+
+       else if (var == "status")
+               sprintf(buf,"%s",getStatusStr());
+       else if (var == "keep")
+               sprintf(buf,"%s",stayConnected?"Yes":"No");
+       else if (var == "id")
+               info.id.toStr(buf);
+       else if (var.startsWith("track."))
+       {
+
+               if (var == "track.title")
+                       utf8 = info.track.title;
+               else if (var == "track.artist")
+                       utf8 = info.track.artist;
+               else if (var == "track.album")
+                       utf8 = info.track.album;
+               else if (var == "track.genre")
+                       utf8 = info.track.genre;
+               else if (var == "track.contactURL")
+                       utf8 = info.track.contact;
+
+               utf8.convertTo(String::T_UNICODESAFE);
+               strcpy(buf,utf8.cstr());
+
+       }else if (var == "contactURL")
+               sprintf(buf,"%s",info.url.cstr());
+       else if (var == "streamPos")
+               sprintf(buf,"%d",streamPos);
+       else if (var == "sourceType")
+               strcpy(buf,getSrcTypeStr());
+       else if (var == "sourceProtocol")
+               strcpy(buf,ChanInfo::getProtocolStr(info.srcProtocol));
+       else if (var == "sourceURL")
+       {
+               if (sourceURL.isEmpty())
+                       sourceHost.host.toStr(buf);
+               else
+                       strcpy(buf,sourceURL.cstr());
+       }
+       else if (var == "headPos")
+               sprintf(buf,"%d",headPack.pos);
+       else if (var == "headLen")
+               sprintf(buf,"%d",headPack.len);
+       else if (var == "numHits")
+       {
+               ChanHitList *chl = chanMgr->findHitListByID(info.id);
+               int numHits = 0;
+               if (chl){
+//                     numHits = chl->numHits();
+                       ChanHit *hit;
+                       hit = chl->hit;
+                       while(hit){
+                               numHits++;
+                               hit = hit->next;
+                       }
+               }
+               sprintf(buf,"%d",numHits);
+       } else if (var == "isBroadcast")
+               strcpy(buf, (type == T_BROADCAST) ? "1":"0");
+       else
+               return false;
+
+       out.writeString(buf);
+       return true;
+}
+
+// -----------------------------------
+void ChanMgr::broadcastTrackerUpdate(GnuID &svID, bool force)
+{
+       Channel *c = channel;
+       while(c)
+       {
+               if ( c->isActive() && c->isBroadcasting() )
+                       c->broadcastTrackerUpdate(svID,force);
+               c=c->next;
+       }
+}
+
+
+// -----------------------------------
+int ChanMgr::broadcastPacketUp(ChanPacket &pack,GnuID &chanID, GnuID &srcID, GnuID &destID)
+{
+       int cnt=0;
+
+       Channel *c = channel;
+       while(c)
+       {
+               if (c->sendPacketUp(pack,chanID,srcID,destID))
+                       cnt++;
+               c=c->next;
+       }
+
+       return cnt;
+}
+
+// -----------------------------------
+void ChanMgr::broadcastRelays(Servent *serv, int minTTL, int maxTTL)
+{
+       //if ((servMgr->getFirewall() == ServMgr::FW_OFF) || servMgr->serverHost.localIP())
+       {
+
+               Host sh = servMgr->serverHost;
+               bool push = (servMgr->getFirewall()!=ServMgr::FW_OFF);
+               bool busy = (servMgr->pubInFull() && servMgr->outFull()) || servMgr->relaysFull();
+               bool stable = servMgr->totalStreams>0;
+
+
+               GnuPacket hit;
+
+               int numChans=0;
+
+               Channel *c = channel;
+               while(c)
+               {
+                       if (c->isPlaying())
+                       {
+
+                               bool tracker = c->isBroadcasting();
+
+                               int ttl = (c->info.getUptime() / servMgr->relayBroadcast);      // 1 hop per N seconds
+
+                               if (ttl < minTTL)
+                                       ttl = minTTL;
+
+                               if (ttl > maxTTL)
+                                       ttl = maxTTL;
+
+                               if (hit.initHit(sh,c,NULL,push,busy,stable,tracker,ttl))
+                               {
+                                       int numOut=0;
+                                       numChans++;
+                                       if (serv)
+                                       {
+                                               serv->outputPacket(hit,false);
+                                               numOut++;
+                                       }
+
+                                       LOG_NETWORK("Sent channel to %d servents, TTL %d",numOut,ttl);          
+
+                               }
+                       }
+                       c=c->next;
+               }
+               //if (numChans)
+               //      LOG_NETWORK("Sent %d channels to %d servents",numChans,numOut);         
+       }
+}
+// -----------------------------------
+void ChanMgr::setUpdateInterval(unsigned int v)
+{
+       hostUpdateInterval = v;
+}
+
+
+// -----------------------------------
+// message check
+#if 0
+                               ChanPacket pack;
+                               MemoryStream mem(pack.data,sizeof(pack.data));
+                               AtomStream atom(mem);
+                               atom.writeParent(PCP_BCST,3);
+                                       atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_ALL);
+                                       atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
+                                       atom.writeParent(PCP_MESG,1);
+                                               atom.writeString(PCP_MESG_DATA,msg.cstr());
+
+                               mem.len = mem.pos;
+                               mem.rewind();
+                               pack.len = mem.len;
+
+                               GnuID noID;
+                               noID.clear();
+
+                               BroadcastState bcs;
+                               PCPStream::readAtom(atom,bcs);
+                               //int cnt = servMgr->broadcastPacketUp(pack,noID,servMgr->sessionID);
+                               //int cnt = servMgr->broadcastPacketDown(pack,noID,servMgr->sessionID);
+                               //int cnt = chanMgr->broadcastPacketUp(pack,noID,servMgr->sessionID);
+                               //LOG_DEBUG("Sent message to %d clients",cnt);
+#endif
+// -----------------------------------
+void ChanMgr::setBroadcastMsg(String &msg)
+{
+       if (!msg.isSame(broadcastMsg))
+       {
+               broadcastMsg = msg;
+
+               Channel *c = channel;
+               while(c)
+               {
+                       if (c->isActive() && c->isBroadcasting())
+                       {
+                               ChanInfo newInfo = c->info;
+                               newInfo.comment = broadcastMsg;
+                               c->updateInfo(newInfo);
+                       }
+                       c=c->next;
+               }
+
+       }
+}
+
+
+// -----------------------------------
+void ChanMgr::clearHitLists()
+{
+
+//     LOG_DEBUG("clearHitLists HITLISTLOCK ON-------------");
+       chanMgr->hitlistlock.on();
+       while (hitlist)
+       {
+               peercastApp->delChannel(&hitlist->info);
+       
+               ChanHitList *next = hitlist->next;
+
+               delete hitlist;
+
+               hitlist = next;
+       }
+//     LOG_DEBUG("clearHitLists HITLISTLOCK OFF-------------");
+       chanMgr->hitlistlock.off();
+}
+// -----------------------------------
+Channel *ChanMgr::deleteChannel(Channel *delchan)
+{
+       lock.on();
+
+       Channel *ch = channel,*prev=NULL,*next=NULL;
+
+       while (ch)
+       {
+               if (ch == delchan)
+               {
+                       Channel *next = ch->next;
+                       if (prev)
+                               prev->next = next;
+                       else
+                               channel = next;
+
+                       if (delchan->sourceStream){
+                               delchan->sourceStream->parent = NULL;
+                       }
+
+                       delete delchan;
+
+                       break;
+               }
+               prev = ch;
+               ch=ch->next;
+       }
+
+
+       lock.off();
+       return next;
+}
+
+// -----------------------------------
+Channel *ChanMgr::createChannel(ChanInfo &info, const char *mount)
+{
+       lock.on();
+
+       Channel *nc=NULL;
+
+       nc = new Channel();
+
+       nc->next = channel;
+       channel = nc;
+
+
+       nc->info = info;
+       nc->info.lastPlayStart = 0;
+       nc->info.lastPlayEnd = 0;
+       nc->info.status = ChanInfo::S_UNKNOWN;
+       if (mount)
+               nc->mount.set(mount);
+       nc->setStatus(Channel::S_WAIT);
+       nc->type = Channel::T_ALLOCATED;
+       nc->info.createdTime = sys->getTime();
+
+       LOG_CHANNEL("New channel created");
+
+       lock.off();
+       return nc;
+}
+// -----------------------------------
+int ChanMgr::pickHits(ChanHitSearch &chs)
+{
+       ChanHitList *chl = hitlist;
+       while(chl)
+       {
+               if (chl->isUsed())
+                       if (chl->pickHits(chs))
+                       {
+                               chl->info.id;
+                               return 1;
+                       }
+               chl = chl->next;
+       }
+       return 0;
+}
+
+// -----------------------------------
+ChanHitList *ChanMgr::findHitList(ChanInfo &info)
+{
+       ChanHitList *chl = hitlist;
+       while(chl)
+       {
+               if (chl->isUsed())
+                       if (chl->info.matchNameID(info))
+                               return chl;
+
+               chl = chl->next;
+       }
+       return NULL;
+}
+// -----------------------------------
+ChanHitList *ChanMgr::findHitListByID(GnuID &id)
+{
+       ChanHitList *chl = hitlist;
+       while(chl)
+       {
+               if (chl->isUsed())
+                       if (chl->info.id.isSame(id))
+                               return chl;
+               chl = chl->next;
+       }
+       return NULL;
+}
+// -----------------------------------
+int ChanMgr::numHitLists()
+{
+       int num=0;
+       ChanHitList *chl = hitlist;
+       while(chl)
+       {
+               if (chl->isUsed())
+                       num++;
+               chl = chl->next;
+       }
+       return num;
+}
+// -----------------------------------
+ChanHitList *ChanMgr::addHitList(ChanInfo &info)
+{      
+       ChanHitList *chl = new ChanHitList();   
+
+
+       chl->next = hitlist;
+       hitlist = chl;
+
+       chl->used = true;
+       chl->info = info;
+       chl->info.createdTime = sys->getTime();
+       peercastApp->addChannel(&chl->info);
+
+
+       return chl;
+}
+// -----------------------------------
+void ChanMgr::clearDeadHits(bool clearTrackers)
+{
+       unsigned int interval;
+       
+       if (servMgr->isRoot)
+               interval = 1200;                // mainly for old 0.119 clients
+       else
+               interval = hostUpdateInterval+120;
+
+       chanMgr->hitlistlock.on();
+       ChanHitList *chl = hitlist,*prev = NULL;
+       while (chl)
+       {
+               if (chl->isUsed())
+               {
+                       if (chl->clearDeadHits(interval,clearTrackers) == 0)
+                       {
+                               if (!isBroadcasting(chl->info.id))
+                               {
+                                       if (!chanMgr->findChannelByID(chl->info.id))
+                                       {
+                                               peercastApp->delChannel(&chl->info);
+
+                                               ChanHitList *next = chl->next;
+                                               if (prev)
+                                                       prev->next = next;
+                                               else
+                                                       hitlist = next;
+
+                                               delete chl;
+                                               chl = next;
+                                               continue;
+                                       }
+                               }
+                       }
+               }
+               prev = chl;
+               chl = chl->next;
+       }
+       chanMgr->hitlistlock.off();
+}
+// -----------------------------------
+bool   ChanMgr::isBroadcasting(GnuID &id)
+{
+       Channel *ch = findChannelByID(id);
+       if (ch)
+               return ch->isBroadcasting();
+
+       return false;
+}
+// -----------------------------------
+bool   ChanMgr::isBroadcasting()
+{
+       Channel *ch = channel;
+       while (ch)
+       {
+               if (ch->isActive())
+                       if (ch->isBroadcasting())
+                               return true;
+
+               ch = ch->next;
+       }
+       return false;
+}
+
+// -----------------------------------
+int ChanMgr::numChannels()
+{
+       int tot = 0;
+       Channel *ch = channel;
+       while (ch)
+       {
+               if (ch->isActive())
+                       tot++;
+               ch = ch->next;
+       }
+       return tot;
+}
+
+// -----------------------------------
+void ChanMgr::deadHit(ChanHit &hit)
+{
+       ChanHitList *chl = findHitListByID(hit.chanID);
+       if (chl)
+               chl->deadHit(hit);
+}
+// -----------------------------------
+void ChanMgr::delHit(ChanHit &hit)
+{
+       ChanHitList *chl = findHitListByID(hit.chanID);
+       if (chl)
+               chl->delHit(hit);
+}
+
+// -----------------------------------
+void ChanMgr::addHit(Host &h,GnuID &id,bool tracker)
+{
+       ChanHit hit;
+       hit.init();
+       hit.host = h; 
+       hit.rhost[0] = h;
+       hit.rhost[1].init();
+       hit.tracker = tracker;
+       hit.recv = true;
+       hit.chanID = id;
+       addHit(hit);
+}
+// -----------------------------------
+ChanHit *ChanMgr::addHit(ChanHit &h)
+{
+       if (searchActive)
+               lastHit = sys->getTime();
+
+       ChanHitList *hl=NULL;
+
+       hl = findHitListByID(h.chanID);
+
+       if (!hl)
+       {
+               ChanInfo info;
+               info.id = h.chanID;
+               hl = addHitList(info);
+       }
+
+       if (hl)
+       {
+               return hl->addHit(h);
+       }else
+               return NULL;
+}
+
+// -----------------------------------
+class ChanFindInfo : public ThreadInfo
+{
+public:
+       ChanInfo        info;
+       bool    keep;
+};
+// -----------------------------------
+THREAD_PROC findAndPlayChannelProc(ThreadInfo *th)
+{
+       ChanFindInfo *cfi = (ChanFindInfo *)th;
+
+       ChanInfo info;
+       info = cfi->info;
+
+
+       Channel *ch = chanMgr->findChannelByNameID(info);
+
+       chanMgr->currFindAndPlayChannel = info.id;
+
+       if (!ch)
+               ch = chanMgr->findAndRelay(info);
+
+       if (ch)
+       {
+               // check that a different channel hasn`t be selected already.
+               if (chanMgr->currFindAndPlayChannel.isSame(ch->info.id))
+                       chanMgr->playChannel(ch->info);
+
+               if (cfi->keep)
+                       ch->stayConnected = cfi->keep;
+       }
+
+       delete cfi;
+       return 0;
+}
+// -----------------------------------
+void ChanMgr::findAndPlayChannel(ChanInfo &info, bool keep)
+{
+       ChanFindInfo *cfi = new ChanFindInfo;
+       cfi->info = info;
+       cfi->keep = keep;
+       cfi->func = findAndPlayChannelProc;
+
+
+       sys->startThread(cfi);
+}
+// -----------------------------------
+void ChanMgr::playChannel(ChanInfo &info)
+{
+
+       char str[128],fname[256],idStr[128];
+
+       sprintf(str,"http://localhost:%d",servMgr->serverHost.port);
+       info.id.toStr(idStr);
+
+       PlayList::TYPE type;
+
+
+       if ((info.contentType == ChanInfo::T_WMA) || (info.contentType == ChanInfo::T_WMV))
+       {
+               type = PlayList::T_ASX;
+               // WMP seems to have a bug where it doesn`t re-read asx files if they have the same name
+               // so we prepend the channel id to make it unique - NOTE: should be deleted afterwards.
+               if (servMgr->getModulePath) //JP-EX
+               {
+                       peercastApp->getDirectory();
+                       sprintf(fname,"%s/%s.asx",servMgr->modulePath,idStr);   
+               }else
+                       sprintf(fname,"%s/%s.asx",peercastApp->getPath(),idStr);
+       }else if (info.contentType == ChanInfo::T_OGM)
+       {
+               type = PlayList::T_RAM;
+               if (servMgr->getModulePath) //JP-EX
+               {
+                       peercastApp->getDirectory();
+                       sprintf(fname,"%s/play.ram",servMgr->modulePath);
+               }else
+                       sprintf(fname,"%s/play.ram",peercastApp->getPath());
+
+       }else
+       {
+               type = PlayList::T_SCPLS;
+               if (servMgr->getModulePath) //JP-EX
+               {
+                       peercastApp->getDirectory();
+                       sprintf(fname,"%s/play.pls",servMgr->modulePath);
+               }else
+                       sprintf(fname,"%s/play.pls",peercastApp->getPath());
+       }
+
+
+       PlayList *pls = new PlayList(type,1);
+       pls->addChannel(str,info);
+
+
+       LOG_DEBUG("Writing %s",fname);
+       FileStream file;
+       file.openWriteReplace(fname);
+       pls->write(file);
+       file.close();
+
+
+       LOG_DEBUG("Executing: %s",fname);
+       sys->executeFile(fname);
+       delete pls;
+
+}
+
+// -----------------------------------
+ChanHitList::ChanHitList()
+{
+       info.init();
+       lastHitTime = 0;
+       used = false;
+       hit = NULL;
+}
+// -----------------------------------
+ChanHitList::~ChanHitList()
+{
+       chanMgr->hitlistlock.on();
+       while (hit)
+               hit = deleteHit(hit);
+       chanMgr->hitlistlock.off();
+}
+// -----------------------------------
+void ChanHit::pickNearestIP(Host &h)
+{
+       for(int i=0; i<2; i++)
+       {
+               if (h.classType() == rhost[i].classType())
+               {
+                       host = rhost[i];
+                       break;
+               }
+       }
+}
+
+// -----------------------------------
+void ChanHit::init()
+{
+       host.init();
+
+       rhost[0].init();
+       rhost[1].init();
+
+       next = NULL;
+
+       numListeners = 0;
+       numRelays = 0;
+
+       dead = tracker = firewalled = stable = yp = false;
+       recv = cin = direct = relay = true;
+       relayfull = chfull = ratefull = false;
+       direct = 0;
+       numHops = 0;
+       time = upTime = 0;
+       lastContact = 0;
+
+       version = 0;
+       version_vp = 0;
+
+       version_ex_prefix[0] = ' ';
+       version_ex_prefix[1] = ' ';
+       version_ex_number = 0;
+
+       status = 0;
+
+       sessionID.clear();
+       chanID.clear();
+
+
+       oldestPos = newestPos = 0;
+       uphost.init();
+       uphostHops = 0;
+}
+
+// -----------------------------------
+void ChanHit::initLocal(int numl,int numr,int,int uptm,bool connected,bool isFull,unsigned int bitrate, Channel* ch, unsigned int oldp,unsigned int newp)
+{
+       init();
+       firewalled = (servMgr->getFirewall() != ServMgr::FW_OFF);
+       numListeners = numl;
+       numRelays = numr;
+       upTime = uptm;
+       stable = servMgr->totalStreams>0;
+       sessionID = servMgr->sessionID;
+       recv = connected;
+
+       direct = !servMgr->directFull();
+//     relay = !servMgr->relaysFull();
+       cin = !servMgr->controlInFull();
+
+       relayfull = servMgr->relaysFull();
+       chfull = isFull;
+
+       Channel *c = chanMgr->channel;
+       int noRelay = 0;
+       unsigned int needRate = 0;
+       unsigned int allRate = 0;
+       while(c){
+               if (c->isPlaying()){
+                       allRate += c->info.bitrate * c->localRelays();
+                       if ((c != ch) && (c->localRelays() == 0)){
+                               if(!isIndexTxt(c))      // for PCRaw (relay)
+                                       noRelay++;
+                               needRate+=c->info.bitrate;
+                       }
+               }
+               c = c->next;
+       }
+       int diff = servMgr->maxRelays - servMgr->numStreams(Servent::T_RELAY,false);
+       if (ch->localRelays()){
+               if (noRelay > diff){
+                       noRelay = diff;
+               }
+       } else {
+               noRelay = 0;
+               needRate = 0;
+       }
+
+       // for PCRaw (relay) start.
+       bool force_off = false;
+
+       if(isIndexTxt(ch))
+               force_off = true;
+       // for PCRaw (relay) end.
+
+//     ratefull = servMgr->bitrateFull(needRate+bitrate);
+       ratefull = (servMgr->maxBitrateOut < allRate + needRate + ch->info.bitrate);
+
+       //relay =       (!relayfull) && (!chfull) && (!ratefull) && ((servMgr->numStreams(Servent::T_RELAY,false) + noRelay) < servMgr->maxRelays);
+       relay = (!relayfull || force_off) && (!chfull) && (!ratefull)
+               && (((servMgr->numStreams(Servent::T_RELAY,false) + noRelay) < servMgr->maxRelays) || force_off);       // for PCRaw (relay) (force_off)
+
+/*     if (relayfull){
+               LOG_DEBUG("Reject by relay full");
+       }
+       if (chfull){
+               LOG_DEBUG("Reject by channel full");
+       }
+       if (ratefull){
+               LOG_DEBUG("Reject by rate: Max=%d Now=%d Need=%d ch=%d", servMgr->maxBitrateOut, allRate, needRate, ch->info.bitrate);
+       }*/
+
+       host = servMgr->serverHost;
+
+       version = PCP_CLIENT_VERSION;
+       version_vp = PCP_CLIENT_VERSION_VP;
+#ifdef VERSION_EX
+       strncpy(version_ex_prefix, PCP_CLIENT_VERSION_EX_PREFIX,2);
+       version_ex_number = PCP_CLIENT_VERSION_EX_NUMBER;
+#else
+       version_ex_prefix[0] = ' ';
+       version_ex_prefix[1] = ' ';
+       version_ex_number = 0;
+#endif
+
+       status = ch->status;
+
+       rhost[0] = Host(host.ip,host.port);
+       rhost[1] = Host(ClientSocket::getIP(NULL),host.port);
+
+       if (firewalled)
+               rhost[0].port = 0;
+
+       oldestPos = oldp;
+       newestPos = newp;
+
+       uphost.ip = ch->sourceHost.host.ip;
+       uphost.port = ch->sourceHost.host.port;
+       uphostHops = 1;
+}
+
+// -----------------------------------
+void ChanHit::writeAtoms(AtomStream &atom,GnuID &chanID)
+{
+       bool addChan=chanID.isSet();
+       bool uphostdata=(uphost.ip != 0);
+
+       int fl1 = 0; 
+       if (recv) fl1 |= PCP_HOST_FLAGS1_RECV;
+       if (relay) fl1 |= PCP_HOST_FLAGS1_RELAY;
+       if (direct) fl1 |= PCP_HOST_FLAGS1_DIRECT;
+       if (cin) fl1 |= PCP_HOST_FLAGS1_CIN;
+       if (tracker) fl1 |= PCP_HOST_FLAGS1_TRACKER;
+       if (firewalled) fl1 |= PCP_HOST_FLAGS1_PUSH;
+
+       atom.writeParent(PCP_HOST,13  + (addChan?1:0) + (uphostdata?3:0) + (version_ex_number?2:0));
+
+               if (addChan)
+                       atom.writeBytes(PCP_HOST_CHANID,chanID.id,16);
+               atom.writeBytes(PCP_HOST_ID,sessionID.id,16);
+               atom.writeInt(PCP_HOST_IP,rhost[0].ip);
+               atom.writeShort(PCP_HOST_PORT,rhost[0].port);
+               atom.writeInt(PCP_HOST_IP,rhost[1].ip);
+               atom.writeShort(PCP_HOST_PORT,rhost[1].port);
+               atom.writeInt(PCP_HOST_NUML,numListeners);
+               atom.writeInt(PCP_HOST_NUMR,numRelays);
+               atom.writeInt(PCP_HOST_UPTIME,upTime);
+               atom.writeInt(PCP_HOST_VERSION,version);
+               atom.writeInt(PCP_HOST_VERSION_VP,version_vp);
+               if (version_ex_number){
+                       atom.writeBytes(PCP_HOST_VERSION_EX_PREFIX,version_ex_prefix,2);
+                       atom.writeShort(PCP_HOST_VERSION_EX_NUMBER,version_ex_number);
+               }
+               atom.writeChar(PCP_HOST_FLAGS1,fl1);
+               atom.writeInt(PCP_HOST_OLDPOS,oldestPos);
+               atom.writeInt(PCP_HOST_NEWPOS,newestPos);
+               if (uphostdata){
+                       atom.writeInt(PCP_HOST_UPHOST_IP,uphost.ip);
+                       atom.writeInt(PCP_HOST_UPHOST_PORT,uphost.port);
+                       atom.writeInt(PCP_HOST_UPHOST_HOPS,uphostHops);
+               }
+}
+// -----------------------------------
+bool   ChanHit::writeVariable(Stream &out, const String &var)
+{
+       char buf[1024];
+
+       if (var == "rhost0")
+       {
+               if (servMgr->enableGetName) //JP-EX s
+               {
+                       char buf2[256];
+                       if (firewalled) 
+                       {
+                               if (numRelays==0) 
+                                       strcpy(buf,"<font color=red>");
+                               else 
+                                       strcpy(buf,"<font color=orange>");
+                       }
+                       else {
+                               if (!relay){
+                                       if (numRelays==0){
+                                               strcpy(buf,"<font color=purple>");
+                                       } else {
+                                               strcpy(buf,"<font color=blue>");
+                                       }
+                               } else {
+                                       strcpy(buf,"<font color=green>");
+                               }
+                       }
+
+                       rhost[0].toStr(buf2);
+                       strcat(buf,buf2);
+
+                       char h_name[128];
+                       if (ClientSocket::getHostname(h_name,rhost[0].ip))
+                       {
+                               strcat(buf,"[");
+                               strcat(buf,h_name);
+                               strcat(buf,"]");
+                       }
+                       strcat(buf,"</font>");
+               } //JP-EX e
+               else
+                       rhost[0].toStr(buf);
+       }
+       else if (var == "rhost1")
+               rhost[1].toStr(buf);
+       else if (var == "numHops")
+               sprintf(buf,"%d",numHops);
+       else if (var == "numListeners")
+               sprintf(buf,"%d",numListeners);
+       else if (var == "numRelays")
+               sprintf(buf,"%d",numRelays);
+       else if (var == "uptime")
+       {
+               String timeStr;
+               timeStr.setFromStopwatch(upTime);
+               strcpy(buf,timeStr.cstr());
+       }else if (var == "update")
+       {
+               String timeStr;
+               if (timeStr)
+                       timeStr.setFromStopwatch(sys->getTime()-time);
+               else
+                       timeStr.set("-");
+               strcpy(buf,timeStr.cstr());
+       }else if (var == "isFirewalled"){
+               sprintf(buf,"%d",firewalled?1:0);
+       }else if (var == "version"){
+               sprintf(buf,"%d",version);
+       }else if (var == "agent"){
+               if (version){
+                       if (version_ex_number){
+                               sprintf(buf, "v0.%d(%c%c%04d)", version, version_ex_prefix[0], version_ex_prefix[1], version_ex_number);
+                       } else if (version_vp){
+                               sprintf(buf,"v0.%d(VP%04d)", version, version_vp);
+                       } else {
+                               sprintf(buf,"v0.%d", version);
+                       }
+               } else {
+                       strcpy(buf, "0");
+               }
+       }
+       else if (var == "check")
+       {
+               char buf2[256];
+               strcpy(buf, "<a href=\"#\" onclick=\"checkip('");
+               rhost[0].IPtoStr(buf2);
+               strcat(buf, buf2);
+               strcat(buf, "')\">_</a>");
+       }
+       else if (var == "uphost")               // tree
+               uphost.toStr(buf);
+       else if (var == "uphostHops")   // tree
+               sprintf(buf,"%d",uphostHops);
+       else if (var == "canRelay")             // tree
+               sprintf(buf, "%d",relay);
+       else
+               return false;
+
+       out.writeString(buf);
+       return true;
+}
+
+// -----------------------------------
+int ChanHitList::getTotalListeners()
+{
+       int cnt=0;
+       ChanHit *h = hit;
+       while (h)
+       {
+               if (h->host.ip)
+                       cnt+=h->numListeners;
+               h=h->next;
+       }
+       return cnt;
+}
+// -----------------------------------
+int ChanHitList::getTotalRelays()
+{
+       int cnt=0;
+       ChanHit *h = hit;
+       while (h)
+       {
+               if (h->host.ip)
+                       cnt+=h->numRelays;
+               h=h->next;
+       }
+       return cnt;
+}
+// -----------------------------------
+int ChanHitList::getTotalFirewalled()
+{
+       int cnt=0;
+       ChanHit *h = hit;
+       while (h)
+       {
+               if (h->host.ip)
+                       if (h->firewalled)
+                               cnt++;
+               h=h->next;
+       }
+       return cnt;
+}
+
+// -----------------------------------
+int ChanHitList::contactTrackers(bool connected, int numl, int nums, int uptm)
+{
+       return 0;
+}
+
+void ChanHitList::clearHits(bool flg)
+{
+       ChanHit *c = hit, *prev = NULL;
+
+       while(c){
+               if (flg || (c->numHops != 0)){
+                       ChanHit *next = c->next;
+                       if (prev)
+                               prev->next = next;
+                       else
+                               hit = next;
+
+                       delete c;
+                       c = next;
+               } else {
+                       prev = c;
+                       c = c->next;
+               }
+       }
+}
+
+// -----------------------------------
+ChanHit *ChanHitList::deleteHit(ChanHit *ch)
+{
+       ChanHit *c = hit,*prev=NULL;
+       while (c)
+       {
+               if (c == ch)
+               {
+                       ChanHit *next = c->next;
+                       if (prev)
+                               prev->next = next;
+                       else
+                               hit = next;
+
+                       delete c;
+
+                       return next;
+               }
+               prev=c;
+               c=c->next;
+       }
+
+       return NULL;
+}
+// -----------------------------------
+ChanHit *ChanHitList::addHit(ChanHit &h)
+{
+       char ip0str[64],ip1str[64];
+       h.rhost[0].toStr(ip0str);
+       h.rhost[1].toStr(ip1str);
+       char uphostStr[64];
+       h.uphost.toStr(uphostStr);
+       if (h.uphost.ip){
+               LOG_DEBUG("Add hit: F%dT%dR%d %s/%s <- %s(%d)",h.firewalled,h.tracker,h.relay,ip0str,ip1str,uphostStr, h.uphostHops);
+       } else {
+               LOG_DEBUG("Add hit: F%dT%dR%d %s/%s",h.firewalled,h.tracker,h.relay,ip0str,ip1str);
+       }
+
+       // dont add our own hits
+       if (servMgr->sessionID.isSame(h.sessionID))
+               return NULL;
+
+
+       lastHitTime = sys->getTime();
+       h.time = lastHitTime;
+
+       ChanHit *ch = hit;
+       while (ch)
+       {
+               if ((ch->rhost[0].ip == h.rhost[0].ip) && (ch->rhost[0].port == h.rhost[0].port))
+                       if (((ch->rhost[1].ip == h.rhost[1].ip) && (ch->rhost[1].port == h.rhost[1].port)) || (!ch->rhost[1].isValid()))
+                       {
+                               if (!ch->dead)
+                               {
+                                       if (ch->numHops > 0 && h.numHops == 0)
+                                               // downstream hit recieved as RelayHost
+                                               return ch;
+                                       ChanHit *next = ch->next;
+                                       *ch = h;
+                                       ch->next = next;
+                                       return ch;
+                               }
+                       }
+               ch=ch->next;
+       }
+
+       // clear hits with same session ID (IP may have changed)
+       if (h.sessionID.isSet())
+       {
+               ChanHit *ch = hit;
+               while (ch)
+               {
+                       if (ch->host.ip)
+                               if (ch->sessionID.isSame(h.sessionID))
+                               {
+                                       ch = deleteHit(ch);
+                                       continue;                                               
+                               }
+                       ch=ch->next;
+               }
+       }
+
+
+       // else add new hit
+       {
+               ChanHit *ch = new ChanHit();
+               *ch = h;
+               ch->chanID = info.id;
+               ch->next = hit;
+               hit = ch;
+               return ch;
+       }
+
+       return NULL;
+}
+
+
+// -----------------------------------
+int    ChanHitList::clearDeadHits(unsigned int timeout, bool clearTrackers)
+{
+       int cnt=0;
+       unsigned int ctime = sys->getTime();
+
+//     LOG_DEBUG("clearDeadHits HITLISTLOCK ON-------------");
+       chanMgr->hitlistlock.on();
+       ChanHit *ch = hit;
+       while (ch)
+       {
+               if (ch->host.ip)
+               {
+                       if (ch->dead || ((ctime-ch->time) > timeout) && (clearTrackers || (!clearTrackers & !ch->tracker)))
+                       {
+//                             ch = deleteHit(ch);
+
+                               if (ch->firewalled){
+//                                     LOG_DEBUG("kickKeepTime = %d, %d", servMgr->kickKeepTime, ctime-ch->time);
+                                       if ( (servMgr->kickKeepTime == 0) || ((ctime-ch->time) > servMgr->kickKeepTime) ){
+                                               ch = deleteHit(ch);
+                                       } else {
+                                               ch->numHops = 0;
+                                               ch->numListeners = 0;
+                                               ch = ch->next;
+                                       }
+                               } else {
+                                       ch = deleteHit(ch);
+                               }
+
+                               continue;
+                       }else
+                               cnt++;
+               }
+               ch = ch->next;
+       }
+//     LOG_DEBUG("clearDeadHits HITLISTLOCK OFF-------------");
+       chanMgr->hitlistlock.off();
+       return cnt;
+}
+
+
+// -----------------------------------
+void   ChanHitList::deadHit(ChanHit &h)
+{
+       char ip0str[64],ip1str[64];
+       h.rhost[0].toStr(ip0str);
+       h.rhost[1].toStr(ip1str);
+       LOG_DEBUG("Dead hit: %s/%s",ip0str,ip1str);
+
+       ChanHit *ch = hit;
+       while (ch)
+       {
+               if (ch->host.ip)
+                       if (ch->rhost[0].isSame(h.rhost[0]) && ch->rhost[1].isSame(h.rhost[1]))
+                       {
+                               ch->dead = true;
+                       }
+               ch = ch->next;
+       }
+}
+// -----------------------------------
+void   ChanHitList::delHit(ChanHit &h)
+{
+       char ip0str[64],ip1str[64];
+       h.rhost[0].toStr(ip0str);
+       h.rhost[1].toStr(ip1str);
+       LOG_DEBUG("Del hit: %s/%s",ip0str,ip1str);
+
+       ChanHit *ch = hit;
+       while (ch)
+       {
+               if (ch->host.ip)
+                       if (ch->rhost[0].isSame(h.rhost[0]) && ch->rhost[1].isSame(h.rhost[1]))
+                       {
+                               ch=deleteHit(ch);
+                               continue;
+                       }
+               ch = ch->next;
+       }
+}
+// -----------------------------------
+int    ChanHitList::numHits()
+{
+       int cnt=0;
+       ChanHit *ch = hit;
+       while (ch)
+       {
+               if (ch->host.ip && !ch->dead && ch->numHops)
+                       cnt++;
+               ch = ch->next;
+       }
+
+       return cnt;
+}
+// -----------------------------------
+int    ChanHitList::numListeners()
+{
+       int cnt=0;
+       ChanHit *ch = hit;
+       while (ch)
+       {
+               if (ch->host.ip && !ch->dead && ch->numHops)
+                       cnt += ch->numListeners;
+               ch=ch->next;
+       }
+
+       return cnt;
+}
+// -----------------------------------
+int    ChanHitList::numRelays()
+{
+       int cnt=0;
+       ChanHit *ch = hit;
+       while (ch)
+       {
+               if (ch->host.ip && !ch->dead)
+                       cnt += ch->numRelays;
+               ch=ch->next;
+       }
+
+       return cnt;
+}
+
+// -----------------------------------
+int    ChanHitList::numTrackers()
+{
+       int cnt=0;
+       ChanHit *ch = hit;
+       while (ch)
+       {
+               if ((ch->host.ip && !ch->dead) && (ch->tracker))
+                       cnt++;
+               ch=ch->next;
+       }
+       return cnt;
+}
+// -----------------------------------
+int    ChanHitList::numFirewalled()
+{
+       int cnt=0;
+       ChanHit *ch = hit;
+       while (ch)
+       {
+               if (ch->host.ip && !ch->dead)
+                       cnt += ch->firewalled?1:0;
+               ch=ch->next;
+       }
+       return cnt;
+}
+// -----------------------------------
+int    ChanHitList::closestHit()
+{
+       unsigned int hop=10000;
+       ChanHit *ch = hit;
+       while (ch)
+       {
+               if (ch->host.ip && !ch->dead)
+                       if (ch->numHops < hop)
+                               hop = ch->numHops;
+               ch=ch->next;
+       }
+
+       return hop;
+}
+// -----------------------------------
+int    ChanHitList::furthestHit()
+{
+       unsigned int hop=0;
+       ChanHit *ch = hit;
+       while (ch)
+       {
+               if (ch->host.ip && !ch->dead)
+                       if (ch->numHops > hop)
+                               hop = ch->numHops;
+               ch=ch->next;
+       }
+
+       return hop;
+}
+// -----------------------------------
+unsigned int   ChanHitList::newestHit()
+{
+       unsigned int time=0;
+       ChanHit *ch = hit;
+       while (ch)
+       {
+               if (ch->host.ip && !ch->dead)
+                       if (ch->time > time)
+                               time = ch->time;
+               ch=ch->next;
+       }
+
+       return time;
+}
+// -----------------------------------
+int ChanHitList::pickHits(ChanHitSearch &chs)
+{
+       ChanHit best,*bestP=NULL;
+       best.init();
+       best.numHops = 255;
+       best.time = 0;
+
+       unsigned int ctime = sys->getTime();
+
+       ChanHit *c = hit;
+       while (c)
+       {
+               if (c->host.ip && !c->dead)
+               {
+                       if (!chs.excludeID.isSame(c->sessionID))
+                       if ((chs.waitDelay==0) || ((ctime-c->lastContact) >= chs.waitDelay))
+                       if ((c->numHops<=best.numHops)) // (c->time>=best.time))
+                       if (c->relay || (!c->relay && chs.useBusyRelays))
+                       if (c->cin || (!c->cin && chs.useBusyControls))
+                       {
+
+                               if (chs.trackersOnly && c->tracker)
+                               {
+                                       if (chs.matchHost.ip)
+                                       {
+                                               if ((c->rhost[0].ip == chs.matchHost.ip) && c->rhost[1].isValid())
+                                               {
+                                                       bestP = c;
+                                                       best = *c;
+                                                       best.host = best.rhost[1];      // use lan ip
+                                               }
+                                       }else if (c->firewalled == chs.useFirewalled)
+                                       {
+                                               bestP = c;
+                                               best = *c;
+                                               best.host = best.rhost[0];                      // use wan ip
+                                       }
+                               }else if (!chs.trackersOnly && !c->tracker)
+                               {
+                                       if (chs.matchHost.ip)
+                                       {
+                                               if ((c->rhost[0].ip == chs.matchHost.ip) && c->rhost[1].isValid())
+                                               {
+                                                       bestP = c;
+                                                       best = *c;
+                                                       best.host = best.rhost[1];      // use lan ip
+                                               }
+                                       }else if (c->firewalled == chs.useFirewalled && (!bestP || !bestP->relay))
+                                       {
+                                               bestP = c;
+                                               best = *c;
+                                               best.host = best.rhost[0];                      // use wan ip
+                                       }
+                               }
+                       }
+               }
+               c=c->next;
+       }
+
+       if (bestP)
+       {
+               if (chs.numResults < ChanHitSearch::MAX_RESULTS)
+               {
+                       if (chs.waitDelay)
+                               bestP->lastContact = ctime;
+                       chs.best[chs.numResults++] = best;
+                       return 1;
+               }
+
+       }
+
+       return 0;
+}
+
+
+// -----------------------------------
+int ChanHitList::pickSourceHits(ChanHitSearch &chs)
+{
+       if (pickHits(chs) && chs.best[0].numHops == 0) return 1;
+       return 0;
+}
+
+
+// -----------------------------------
+const char *ChanInfo::getTypeStr(TYPE t)
+{
+       switch (t)
+       {
+               case T_RAW: return "RAW";
+
+               case T_MP3: return "MP3";
+               case T_OGG: return "OGG";
+               case T_OGM: return "OGM";
+               case T_WMA: return "WMA";
+
+               case T_MOV: return "MOV";
+               case T_MPG: return "MPG";
+               case T_NSV: return "NSV";
+               case T_WMV: return "WMV";
+
+               case T_PLS: return "PLS";
+               case T_ASX: return "ASX";
+
+               default: return "UNKNOWN";
+       }
+}
+// -----------------------------------
+const char *ChanInfo::getProtocolStr(PROTOCOL t)
+{
+       switch (t)
+       {
+               case SP_PEERCAST: return "PEERCAST";
+               case SP_HTTP: return "HTTP";
+               case SP_FILE: return "FILE";
+               case SP_MMS: return "MMS";
+               case SP_PCP: return "PCP";
+               default: return "UNKNOWN";
+       }
+}
+// -----------------------------------
+ChanInfo::PROTOCOL ChanInfo::getProtocolFromStr(const char *str)
+{
+       if (stricmp(str,"PEERCAST")==0)
+               return SP_PEERCAST;
+       else if (stricmp(str,"HTTP")==0)
+               return SP_HTTP;
+       else if (stricmp(str,"FILE")==0)
+               return SP_FILE;
+       else if (stricmp(str,"MMS")==0)
+               return SP_MMS;
+       else if (stricmp(str,"PCP")==0)
+               return SP_PCP;
+       else 
+               return SP_UNKNOWN;
+}
+
+// -----------------------------------
+const char *ChanInfo::getTypeExt(TYPE t)
+{
+       switch(t)
+       {
+               case ChanInfo::T_OGM:
+               case ChanInfo::T_OGG:
+                       return ".ogg";
+               case ChanInfo::T_MP3:
+                       return ".mp3";
+               case ChanInfo::T_MOV:
+                       return ".mov";
+               case ChanInfo::T_NSV:
+                       return ".nsv";
+               case ChanInfo::T_WMV:
+                       return ".wmv";
+               case ChanInfo::T_WMA:
+                       return ".wma";
+               default:
+                       return "";
+       }
+}
+// -----------------------------------
+ChanInfo::TYPE ChanInfo::getTypeFromStr(const char *str)
+{
+       if (stricmp(str,"MP3")==0)
+               return T_MP3;
+       else if (stricmp(str,"OGG")==0)
+               return T_OGG;
+       else if (stricmp(str,"OGM")==0)
+               return T_OGM;
+       else if (stricmp(str,"RAW")==0)
+               return T_RAW;
+       else if (stricmp(str,"NSV")==0)
+               return T_NSV;
+       else if (stricmp(str,"WMA")==0)
+               return T_WMA;
+       else if (stricmp(str,"WMV")==0)
+               return T_WMV;
+       else if (stricmp(str,"PLS")==0)
+               return T_PLS;
+       else if (stricmp(str,"M3U")==0)
+               return T_PLS;
+       else if (stricmp(str,"ASX")==0)
+               return T_ASX;
+       else 
+               return T_UNKNOWN;
+}
+// -----------------------------------
+bool   ChanInfo::matchNameID(ChanInfo &inf)
+{
+       if (inf.id.isSet())
+               if (id.isSame(inf.id))
+                       return true;
+
+       if (!inf.name.isEmpty())
+               if (name.contains(inf.name))
+                       return true;
+
+       return false;
+}
+// -----------------------------------
+bool   ChanInfo::match(ChanInfo &inf)
+{
+       bool matchAny=true;
+
+       if (inf.status != S_UNKNOWN)
+       {
+               if (status != inf.status)
+                       return false;
+       }
+
+       if (inf.bitrate != 0)
+       {
+               if (bitrate == inf.bitrate)
+                       return true;
+               matchAny = false;
+       }
+
+       if (inf.id.isSet())
+       {
+               if (id.isSame(inf.id))
+                       return true;
+               matchAny = false;
+       }
+
+       if (inf.contentType != T_UNKNOWN)
+       {
+               if (contentType == inf.contentType)
+                       return true;
+               matchAny = false;
+       }
+
+       if (!inf.name.isEmpty())
+       {
+               if (name.contains(inf.name))
+                       return true;
+               matchAny = false;
+       }
+
+       if (!inf.genre.isEmpty())
+       {
+               if (genre.contains(inf.genre))
+                       return true;
+               matchAny = false;
+       }
+
+       return matchAny;
+}
+// -----------------------------------
+bool TrackInfo::update(TrackInfo &inf)
+{
+       bool changed = false;
+
+       if (!contact.isSame(inf.contact))
+       {
+               contact = inf.contact;
+               changed = true;
+       }
+
+       if (!title.isSame(inf.title))
+       {
+               title = inf.title;
+               changed = true;
+       }
+
+       if (!artist.isSame(inf.artist))
+       {
+               artist = inf.artist;
+               changed = true;
+       }
+
+       if (!album.isSame(inf.album))
+       {
+               album = inf.album;
+               changed = true;
+       }
+
+       if (!genre.isSame(inf.genre))
+       {
+               genre = inf.genre;
+               changed = true;
+       }
+
+
+       return changed;
+}
+
+
+// -----------------------------------
+bool ChanInfo::update(ChanInfo &info)
+{
+       bool changed = false;
+
+
+
+       // check valid id
+       if (!info.id.isSet())
+               return false;
+
+       // only update from chaninfo that has full name etc..
+       if (info.name.isEmpty())
+               return false;
+
+       // check valid broadcaster key
+       if (bcID.isSet())
+       {
+               if (!bcID.isSame(info.bcID))
+               {
+                       LOG_ERROR("ChanInfo BC key not valid");
+                       return false;
+               }
+       }else
+       {
+               bcID = info.bcID;
+       }
+
+
+
+       if (bitrate != info.bitrate)
+       {
+               bitrate = info.bitrate;
+               changed = true;
+       }
+
+       if (contentType != info.contentType)
+       {
+               contentType = info.contentType;
+               changed = true;
+       }
+
+       if (!desc.isSame(info.desc)) //JP-EX
+       {
+               desc = info.desc;
+               changed = true;
+       }
+
+       if (!name.isSame(info.name))
+       {
+               name = info.name;
+               changed = true;
+       }
+
+       if (!comment.isSame(info.comment))
+       {
+               comment = info.comment;
+               changed = true;
+       }
+
+       if (!genre.isSame(info.genre))
+       {
+               genre = info.genre;
+               changed = true;
+       }
+       
+       if (!url.isSame(info.url))
+       {
+               url = info.url;
+               changed = true;
+       }
+
+       if (track.update(info.track))
+               changed = true;
+
+
+       return changed;
+}
+// -----------------------------------
+void ChanInfo::initNameID(const char *n)
+{
+       init();
+       id.fromStr(n);
+       if (!id.isSet())
+               name.set(n);
+}
+
+// -----------------------------------
+void ChanInfo::init()
+{
+       status = S_UNKNOWN;
+       name.clear();
+       bitrate = 0;
+       contentType = T_UNKNOWN;
+       srcProtocol = SP_UNKNOWN;
+       id.clear();
+       url.clear();
+       genre.clear();
+       comment.clear();
+       track.clear();
+       lastPlayStart = 0;
+       lastPlayEnd = 0;
+       numSkips = 0;
+       bcID.clear();
+       createdTime = 0;
+}
+// -----------------------------------
+void ChanInfo::readTrackXML(XML::Node *n)
+{
+       track.clear();
+       readXMLString(track.title,n,"title");
+       readXMLString(track.contact,n,"contact");
+       readXMLString(track.artist,n,"artist");
+       readXMLString(track.album,n,"album");
+       readXMLString(track.genre,n,"genre");
+}
+// -----------------------------------
+unsigned int ChanInfo::getUptime()
+{
+       // calculate uptime and cap if requested by settings.
+       unsigned int upt;
+       upt = lastPlayStart?(sys->getTime()-lastPlayStart):0;
+       if (chanMgr->maxUptime)
+               if (upt > chanMgr->maxUptime)
+                       upt = chanMgr->maxUptime;
+       return upt;
+}
+// -----------------------------------
+unsigned int ChanInfo::getAge()
+{
+       return sys->getTime()-createdTime;
+}
+
+// ------------------------------------------
+void ChanInfo::readTrackAtoms(AtomStream &atom,int numc)
+{
+       for(int i=0; i<numc; i++)
+       {
+               int c,d;
+               ID4 id = atom.read(c,d);
+               if (id == PCP_CHAN_TRACK_TITLE)
+               {
+                       atom.readString(track.title.data,sizeof(track.title.data),d);
+               }else if (id == PCP_CHAN_TRACK_CREATOR)
+               {
+                       atom.readString(track.artist.data,sizeof(track.artist.data),d);
+               }else if (id == PCP_CHAN_TRACK_URL)
+               {
+                       atom.readString(track.contact.data,sizeof(track.contact.data),d);
+               }else if (id == PCP_CHAN_TRACK_ALBUM)
+               {
+                       atom.readString(track.album.data,sizeof(track.album.data),d);
+               }else
+                       atom.skip(c,d);
+       }
+}
+// ------------------------------------------
+void ChanInfo::readInfoAtoms(AtomStream &atom,int numc)
+{
+       for(int i=0; i<numc; i++)
+       {
+               int c,d;
+               ID4 id = atom.read(c,d);
+               if (id == PCP_CHAN_INFO_NAME)
+               {
+                       atom.readString(name.data,sizeof(name.data),d);
+               }else if (id == PCP_CHAN_INFO_BITRATE)
+               {
+                       bitrate = atom.readInt();
+               }else if (id == PCP_CHAN_INFO_GENRE)
+               {
+                       atom.readString(genre.data,sizeof(genre.data),d);
+               }else if (id == PCP_CHAN_INFO_URL)
+               {
+                       atom.readString(url.data,sizeof(url.data),d);
+               }else if (id == PCP_CHAN_INFO_DESC)
+               {
+                       atom.readString(desc.data,sizeof(desc.data),d);
+               }else if (id == PCP_CHAN_INFO_COMMENT)
+               {
+                       atom.readString(comment.data,sizeof(comment.data),d);
+               }else if (id == PCP_CHAN_INFO_TYPE)
+               {
+                       char type[16];
+                       atom.readString(type,sizeof(type),d);
+                       contentType = ChanInfo::getTypeFromStr(type);
+               }else
+                       atom.skip(c,d);
+       }       
+}
+
+// -----------------------------------
+void ChanInfo::writeInfoAtoms(AtomStream &atom)
+{
+       atom.writeParent(PCP_CHAN_INFO,7);
+               atom.writeString(PCP_CHAN_INFO_NAME,name.cstr());
+               atom.writeInt(PCP_CHAN_INFO_BITRATE,bitrate);
+               atom.writeString(PCP_CHAN_INFO_GENRE,genre.cstr());
+               atom.writeString(PCP_CHAN_INFO_URL,url.cstr());
+               atom.writeString(PCP_CHAN_INFO_DESC,desc.cstr());
+               atom.writeString(PCP_CHAN_INFO_COMMENT,comment.cstr());
+               atom.writeString(PCP_CHAN_INFO_TYPE,getTypeStr(contentType));           
+
+}
+// -----------------------------------
+void ChanInfo::writeTrackAtoms(AtomStream &atom)
+{
+       atom.writeParent(PCP_CHAN_TRACK,4);
+               atom.writeString(PCP_CHAN_TRACK_TITLE,track.title.cstr());
+               atom.writeString(PCP_CHAN_TRACK_CREATOR,track.artist.cstr());
+               atom.writeString(PCP_CHAN_TRACK_URL,track.contact.cstr());
+               atom.writeString(PCP_CHAN_TRACK_ALBUM,track.album.cstr());
+}
+
+
+// -----------------------------------
+XML::Node *ChanInfo::createChannelXML()
+{
+       char idStr[64];
+
+       String nameUNI = name;
+       nameUNI.convertTo(String::T_UNICODESAFE);
+
+       String urlUNI = url;
+       urlUNI.convertTo(String::T_UNICODESAFE);
+
+       String genreUNI = genre;
+       genreUNI.convertTo(String::T_UNICODESAFE);
+
+       String descUNI = desc;
+       descUNI.convertTo(String::T_UNICODESAFE);
+
+       String commentUNI;
+       commentUNI = comment;
+       commentUNI.convertTo(String::T_UNICODESAFE);
+
+
+       id.toStr(idStr);
+
+
+       return new XML::Node("channel name=\"%s\" id=\"%s\" bitrate=\"%d\" type=\"%s\" genre=\"%s\" desc=\"%s\" url=\"%s\" uptime=\"%d\" comment=\"%s\" skips=\"%d\" age=\"%d\" bcflags=\"%d\"",
+               nameUNI.cstr(),
+               idStr,
+               bitrate,
+               getTypeStr(contentType),
+               genreUNI.cstr(),
+               descUNI.cstr(),
+               urlUNI.cstr(),
+               getUptime(),
+               commentUNI.cstr(),
+               numSkips,
+               getAge(),
+               bcID.getFlags()
+               );      
+}
+
+// -----------------------------------
+XML::Node *ChanInfo::createQueryXML()
+{
+       char buf[512];
+       char idStr[64];
+
+
+       String nameHTML = name;
+       nameHTML.convertTo(String::T_HTML);
+       String genreHTML = genre;
+       genreHTML.convertTo(String::T_HTML);
+
+       buf[0]=0;
+       if (!nameHTML.isEmpty())
+       {
+               strcat(buf," name=\"");
+               strcat(buf,nameHTML.cstr());
+               strcat(buf,"\"");
+       }
+
+       if (!genreHTML.isEmpty())
+       {
+               strcat(buf," genre=\"");
+               strcat(buf,genreHTML.cstr());
+               strcat(buf,"\"");
+       }
+
+       if (id.isSet())
+       {
+               id.toStr(idStr);
+               strcat(buf," id=\"");
+               strcat(buf,idStr);
+               strcat(buf,"\"");
+       }
+               
+
+       return new XML::Node("channel %s",buf);
+}
+
+// -----------------------------------
+XML::Node *ChanInfo::createRelayChannelXML()
+{
+       char idStr[64];
+
+       id.toStr(idStr);
+
+
+       return new XML::Node("channel id=\"%s\" uptime=\"%d\" skips=\"%d\" age=\"%d\"",
+               idStr,
+               getUptime(),
+               numSkips,
+               getAge()
+               );      
+}// -----------------------------------
+XML::Node *ChanInfo::createTrackXML()
+{
+       String titleUNI = track.title;
+       titleUNI.convertTo(String::T_UNICODESAFE);
+
+       String artistUNI = track.artist;
+       artistUNI.convertTo(String::T_UNICODESAFE);
+
+       String albumUNI = track.album;
+       albumUNI.convertTo(String::T_UNICODESAFE);
+
+       String genreUNI = track.genre;
+       genreUNI.convertTo(String::T_UNICODESAFE);
+
+       String contactUNI = track.contact;
+       contactUNI.convertTo(String::T_UNICODESAFE);
+       
+
+
+       return new XML::Node("track title=\"%s\" artist=\"%s\" album=\"%s\" genre=\"%s\" contact=\"%s\"",
+               titleUNI.cstr(),
+               artistUNI.cstr(),
+               albumUNI.cstr(),
+               genreUNI.cstr(),
+               contactUNI.cstr()
+               );
+}
+
+// -----------------------------------
+void ChanInfo::init(XML::Node *n)
+{
+       init();
+
+       updateFromXML(n);
+}
+// -----------------------------------
+void ChanInfo::updateFromXML(XML::Node *n)
+{
+       String typeStr,idStr;
+
+       readXMLString(name,n,"name");
+       readXMLString(genre,n,"genre");
+       readXMLString(url,n,"url");
+       readXMLString(desc,n,"desc");
+
+
+       int br = n->findAttrInt("bitrate");
+       if (br)
+               bitrate = br;
+
+       readXMLString(typeStr,n,"type");
+       if (!typeStr.isEmpty())
+               contentType = getTypeFromStr(typeStr.cstr());
+
+
+       readXMLString(idStr,n,"id");
+       if (!idStr.isEmpty())
+               id.fromStr(idStr.cstr());
+
+       readXMLString(comment,n,"comment");
+
+       XML::Node *tn = n->findNode("track");
+       if (tn)
+               readTrackXML(tn);
+
+}
+
+// -----------------------------------
+void ChanInfo::init(const char *n, GnuID &cid, TYPE tp, int br)
+{
+       init();
+
+       name.set(n);
+       bitrate = br;
+       contentType = tp;
+       id = cid;
+}
+
+// -----------------------------------
+void ChanInfo::init(const char *fn)
+{
+       init();
+
+       if (fn)
+               name.set(fn);
+}
+// -----------------------------------
+void PlayList::readASX(Stream &in)
+{
+       LOG_DEBUG("Reading ASX");
+       XML xml;
+
+       try
+       {
+               xml.read(in);
+       }catch(StreamException &) {} // TODO: eof is NOT handled properly in sockets - always get error at end
+
+       if (xml.root)
+       {
+               XML::Node *n = xml.root->child;
+               while (n)
+               {
+                       if (stricmp("entry",n->getName())==0)
+                       {
+                               XML::Node *rf = n->findNode("ref");
+                               if (rf)
+                               {
+                                       char *hr = rf->findAttr("href");
+                                       if (hr)
+                                       {
+                                               addURL(hr,"");
+                                               //LOG("asx url %s",hr);
+                                       }
+
+                               }
+                       }
+                       n=n->sibling;
+               }
+       }
+}
+// -----------------------------------
+void PlayList::readSCPLS(Stream &in)
+{
+       char tmp[256];
+       while (in.readLine(tmp,sizeof(tmp)))
+       {
+               if (strnicmp(tmp,"file",4)==0)
+               {
+                       char *p = strstr(tmp,"=");
+                       if (p)
+                               addURL(p+1,"");
+               }
+       }
+}
+// -----------------------------------
+void PlayList::readPLS(Stream &in)
+{
+       char tmp[256];
+       while (in.readLine(tmp,sizeof(tmp)))
+       {
+               if (tmp[0] != '#')
+                       addURL(tmp,"");
+       }
+}
+// -----------------------------------
+void PlayList::writeSCPLS(Stream &out)
+{
+       out.writeLine("[playlist]");
+       out.writeLine("");
+       out.writeLineF("NumberOfEntries=%d",numURLs);
+
+       for(int i=0; i<numURLs; i++)
+       {
+               out.writeLineF("File%d=%s",i+1,urls[i].cstr());
+               out.writeLineF("Title%d=%s",i+1,titles[i].cstr());
+               out.writeLineF("Length%d=-1",i+1);
+       }
+       out.writeLine("Version=2");
+}
+// -----------------------------------
+void PlayList::writePLS(Stream &out)
+{
+       for(int i=0; i<numURLs; i++)
+               out.writeLineF("%s",urls[i].cstr());
+}
+// -----------------------------------
+void PlayList::writeRAM(Stream &out)
+{
+       for(int i=0; i<numURLs; i++)
+               out.writeLineF("%s",urls[i].cstr());
+}
+
+// -----------------------------------
+void PlayList::writeASX(Stream &out)
+{
+       out.writeLine("<ASX Version=\"3.0\">");
+       for(int i=0; i<numURLs; i++)
+       {
+               out.writeLine("<ENTRY>");
+               out.writeLineF("<REF href = \"%s\" />",urls[i].cstr());
+               out.writeLine("</ENTRY>");
+       }
+       out.writeLine("</ASX>");
+}
+
+
+// -----------------------------------
+void PlayList::addChannel(const char *path, ChanInfo &info)
+{
+       String url;
+
+       char idStr[64];
+
+       info.id.toStr(idStr);
+       char *nid = info.id.isSet()?idStr:info.name.cstr();
+
+       sprintf(url.cstr(),"%s/stream/%s%s",path,nid,ChanInfo::getTypeExt(info.contentType));
+       addURL(url.cstr(),info.name);
+}
+
+// -----------------------------------
+void ChanHitSearch::init()
+{
+       matchHost.init();
+       waitDelay = 0;
+       useFirewalled = false;
+       trackersOnly = false;
+       useBusyRelays = true;
+       useBusyControls = true;
+       excludeID.clear();
+       numResults = 0;
+
+       //seed = sys->getTime();
+       //srand(seed);
+}
+
+int ChanHitSearch::getRelayHost(Host host1, Host host2, GnuID exID, ChanHitList *chl)
+{
+       int cnt = 0;
+       int loop = 1;
+       int index = 0;
+       int prob;
+       int rnd;
+       static int base = 0x400;
+       ChanHit tmpHit[MAX_RESULTS];
+       static WLock seqLock;
+       static unsigned int riSequence = 0;
+
+       //srand(seed);
+       //seed += 11;
+
+       unsigned int seq;
+       seqLock.on();
+       seq = riSequence++;
+       riSequence &= 0xffffff;
+       seqLock.off();
+
+       ChanHit *hit = chl->hit;
+
+       while(hit){
+               if (hit->host.ip && !hit->dead){
+                       if (
+                               (!exID.isSame(hit->sessionID))
+//                     &&      (hit->relay)
+                       &&      (!hit->tracker)
+                       &&      (!hit->firewalled)
+                       &&      (hit->numHops != 0)
+                       ){
+                               if (    (hit->rhost[0].ip == host1.ip)
+                                       &&      hit->rhost[1].isValid()
+                                       &&      (host2.ip != hit->rhost[1].ip)
+                               ){
+                                       best[0] = *hit;
+                                       best[0].host = hit->rhost[1];
+                                       index++;
+                               }
+                               if ((hit->rhost[0].ip == host2.ip) && hit->rhost[1].isValid()){
+                                       best[0] = *hit;
+                                       best[0].host = hit->rhost[1];
+                                       index++;
+                               }
+
+                               loop = (index / MAX_RESULTS) + 1;
+                               //prob = (float)1 / (float)loop;
+                               prob = base / loop;
+                               //rnd = (float)rand() / (float)RAND_MAX;
+                               rnd = rand() % base;
+                               if (hit->numHops == 1){
+                                       if (tmpHit[index % MAX_RESULTS].numHops == 1){
+                                               if (rnd < prob){
+                                                       tmpHit[index % MAX_RESULTS] = *hit;
+                                                       tmpHit[index % MAX_RESULTS].host = hit->rhost[0];
+                                                       index++;
+                                               }
+                                       } else {
+                                               tmpHit[index % MAX_RESULTS] = *hit;
+                                               tmpHit[index % MAX_RESULTS].host = hit->rhost[0];
+                                               index++;
+                                       }
+                               } else {
+                                       if ((tmpHit[index % MAX_RESULTS].numHops != 1) && (rnd < prob)){
+                                               tmpHit[index % MAX_RESULTS] = *hit;
+                                               tmpHit[index % MAX_RESULTS].host = hit->rhost[0];
+                                               index++;
+                                       }
+                               }
+
+//                             char tmp[50];
+//                             hit->host.toStr(tmp);
+//                             LOG_DEBUG("TEST %s: %f %f", tmp, rnd, prob);
+                       }
+               }
+               hit = hit->next;
+       }
+       
+       if (index > MAX_RESULTS){
+               cnt = MAX_RESULTS;
+       } else {
+               cnt = index;
+       }
+
+/*     int use[MAX_RESULTS];
+       memset(use, 0, sizeof(use));
+       int i;
+       for (i = 0; i < cnt; i++){
+               use[i] = -1;
+       }
+       int r;
+       for (i = 0; i < cnt; i++){
+               do {
+                       r = rand();
+//                     LOG_DEBUG("%d",r);
+                       r = r % cnt;
+                       if (use[r] == -1){
+                               use[r] = i;
+                               break;
+                       }
+               } while(1);
+       }
+       for (i = 0; i < cnt; i++){
+//             LOG_DEBUG("%d", use[i]);
+               best[use[i]] = tmpHit[i];
+       }*/
+
+       int use[MAX_RESULTS];
+       int i;
+       for (i = 0; i < cnt; i++) {
+               use[i] = (i + seq) % cnt;
+       }
+
+       for (i = 0; i < cnt; i++){
+//             LOG_DEBUG("%d", use[i]);
+               best[use[i]] = tmpHit[i];
+       }
+//     for (i = 0; i < cnt; i++){
+//             char tmp[50];
+//             best[i].host.toStr(tmp);
+//             LOG_DEBUG("Relay info: Hops = %d, %s", best[i].numHops, tmp);
+//     }
+
+       return cnt;
+}
diff --git a/PeerCast.root/PeerCast/core/common/channel.h b/PeerCast.root/PeerCast/core/common/channel.h
new file mode 100644 (file)
index 0000000..d1d00fb
--- /dev/null
@@ -0,0 +1,731 @@
+// ------------------------------------------------
+// File : channel.h
+// Date: 4-apr-2002
+// Author: giles
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _CHANNEL_H
+#define _CHANNEL_H
+
+#include "sys.h"
+#include "stream.h"
+#include "gnutella.h"
+#include "xml.h"
+#include "asf.h"
+#include "cstream.h"
+
+class AtomStream;
+class ChanHitSearch;
+
+// --------------------------------------------------
+struct MP3Header
+{
+       int lay;
+       int version;
+       int error_protection;
+       int bitrate_index;
+       int sampling_frequency;
+       int padding;
+       int extension;
+       int mode;
+       int mode_ext;
+       int copyright;
+       int original;
+       int emphasis;
+       int stereo;
+};
+
+// ----------------------------------
+class TrackInfo
+{
+public:
+       void    clear()
+       {
+               contact.clear();
+               title.clear();
+               artist.clear();
+               album.clear();
+               genre.clear();
+       }
+
+       void    convertTo(String::TYPE t)
+       {
+               contact.convertTo(t);
+               title.convertTo(t);
+               artist.convertTo(t);
+               album.convertTo(t);
+               genre.convertTo(t);
+       }
+
+       bool    update(TrackInfo &);
+
+       ::String        contact,title,artist,album,genre;
+};
+
+
+
+// ----------------------------------
+class ChanInfo
+{
+public:
+       enum TYPE
+       {
+               T_UNKNOWN,
+
+               T_RAW,
+               T_MP3,
+               T_OGG,
+               T_OGM,
+               T_MOV,
+               T_MPG,
+               T_NSV,
+
+               T_WMA,
+               T_WMV,
+
+               T_PLS,
+               T_ASX
+       };
+
+
+       enum PROTOCOL
+       {
+               SP_UNKNOWN,
+               SP_PEERCAST,
+               SP_HTTP,
+               SP_FILE,
+               SP_MMS,
+               SP_PCP
+       };
+
+
+       enum STATUS
+       {
+               S_UNKNOWN,
+               S_PLAY
+       };
+
+       ChanInfo() {init();}
+
+       void    init();
+       void    init(const char *);
+       void    init(const char *, GnuID &, TYPE, int);
+       void    init(XML::Node *);
+       void    initNameID(const char *);
+
+       void    updateFromXML(XML::Node *);
+
+       void    readTrackXML(XML::Node *);
+       void    readServentXML(XML::Node *);
+       bool    update(ChanInfo &);
+       XML::Node *createQueryXML();
+       XML::Node *createChannelXML();
+       XML::Node *createRelayChannelXML();
+       XML::Node *createTrackXML();
+       bool    match(XML::Node *);
+       bool    match(ChanInfo &);
+       bool    matchNameID(ChanInfo &);
+
+       void    writeInfoAtoms(AtomStream &atom);
+       void    writeTrackAtoms(AtomStream &atom);
+
+       void    readInfoAtoms(AtomStream &,int);
+       void    readTrackAtoms(AtomStream &,int);
+
+       unsigned int getUptime();
+       unsigned int getAge();
+       bool    isActive() {return id.isSet();}
+       bool    isPrivate() {return bcID.getFlags() & 1;}
+       static  const   char *getTypeStr(TYPE);
+       static  const   char *getProtocolStr(PROTOCOL);
+       static  const   char *getTypeExt(TYPE);
+       static  TYPE            getTypeFromStr(const char *str);
+       static  PROTOCOL        getProtocolFromStr(const char *str);
+
+       ::String        name;
+       GnuID   id,bcID;
+       int             bitrate;
+       TYPE    contentType;
+       PROTOCOL        srcProtocol;
+       unsigned int lastPlayStart,lastPlayEnd;
+       unsigned int numSkips;
+       unsigned int createdTime;
+
+       STATUS  status;
+
+       TrackInfo       track;
+       ::String        desc,genre,url,comment;
+
+};
+
+
+// ----------------------------------
+class ChanHit
+{
+public:
+       void    init();
+       void    initLocal(int numl,int numr,int nums,int uptm,bool,bool,unsigned int,Channel*,unsigned int,unsigned int);
+       XML::Node *createXML();
+
+       void    writeAtoms(AtomStream &,GnuID &);
+       bool    writeVariable(Stream &, const String &);
+
+       void    pickNearestIP(Host &);
+
+       Host                            host;
+       Host                            rhost[2];
+       unsigned int            numListeners,numRelays,numHops;
+       unsigned int            time,upTime,lastContact;
+       unsigned int            hitID;
+       GnuID                           sessionID,chanID;
+       unsigned int            version;
+       unsigned int            version_vp;
+
+       bool    firewalled:1,stable:1,tracker:1,recv:1,yp:1,dead:1,direct:1,relay:1,cin:1;
+       bool    relayfull:1,chfull:1,ratefull:1;
+
+       ChanHit *next;
+
+       int status;
+       int servent_id;
+
+       unsigned int            oldestPos,newestPos;
+       Host uphost;
+       unsigned int            uphostHops;
+
+       char                            version_ex_prefix[2];
+       unsigned int            version_ex_number;
+};
+// ----------------------------------
+class ChanHitList
+{
+public:
+       ChanHitList();
+       ~ChanHitList();
+
+       int             contactTrackers(bool,int,int,int);
+
+       ChanHit *addHit(ChanHit &);
+       void    delHit(ChanHit &);
+       void    deadHit(ChanHit &);
+       void    clearHits(bool);
+       int             numHits();
+       int             numListeners();
+       int             numRelays();
+       int             numFirewalled();
+       int             numTrackers();
+       int             closestHit();
+       int             furthestHit();
+       unsigned int            newestHit();
+
+       int                     pickHits(ChanHitSearch &);
+       int                     pickSourceHits(ChanHitSearch &);
+
+       bool    isUsed() {return used;}
+       int             clearDeadHits(unsigned int,bool);
+       XML::Node *createXML(bool addHits = true);
+
+       ChanHit *deleteHit(ChanHit *);
+
+       int             getTotalListeners();
+       int             getTotalRelays();
+       int             getTotalFirewalled();
+
+       bool    used;
+       ChanInfo        info;
+       ChanHit *hit;
+       unsigned int lastHitTime;
+       ChanHitList *next;
+
+
+};
+// ----------------------------------
+class ChanHitSearch
+{
+public:
+       enum
+       {
+               MAX_RESULTS = 8
+       };
+
+       ChanHitSearch() { init(); }
+       void init();
+
+       ChanHit best[MAX_RESULTS];
+       Host    matchHost;
+       unsigned int waitDelay;
+       bool    useFirewalled;
+       bool    trackersOnly;
+       bool    useBusyRelays,useBusyControls;
+       GnuID   excludeID;
+       int             numResults;
+       unsigned int seed;
+
+       int getRelayHost(Host host1, Host host2, GnuID exID, ChanHitList *chl);
+};
+
+// ----------------------------------
+class ChanMeta
+{
+public:
+       enum {
+               MAX_DATALEN = 65536
+       };
+
+       void    init()
+       {
+               len = 0;
+               cnt = 0;
+               startPos = 0;
+       }
+
+       void    fromXML(XML &);
+       void    fromMem(void *,int);
+       void    addMem(void *,int);
+
+       unsigned int len,cnt,startPos;
+       char    data[MAX_DATALEN];
+};
+
+
+
+// ------------------------------------------
+class RawStream : public ChannelStream
+{
+public:
+       virtual void readHeader(Stream &,Channel *);
+       virtual int readPacket(Stream &,Channel *);
+       virtual void readEnd(Stream &,Channel *);
+
+};
+
+// ------------------------------------------
+class PeercastStream : public ChannelStream
+{
+public:
+       virtual void readHeader(Stream &,Channel *);
+       virtual int  readPacket(Stream &,Channel *);
+       virtual void readEnd(Stream &,Channel *);
+};
+
+// ------------------------------------------
+class ChannelSource
+{
+public:
+       virtual ~ChannelSource() {}
+       virtual void stream(Channel *) = 0;
+
+       virtual int getSourceRate() {return 0;}
+
+};
+// ------------------------------------------
+class PeercastSource : public ChannelSource
+{
+public:
+
+
+       virtual void stream(Channel *);
+
+};
+
+
+// ----------------------------------
+class Channel
+{
+public:
+       
+       enum STATUS
+       {
+               S_NONE,
+               S_WAIT,
+               S_CONNECTING,
+               S_REQUESTING,
+               S_CLOSING,
+               S_RECEIVING,
+               S_BROADCASTING,
+               S_ABORT,
+               S_SEARCHING,
+               S_NOHOSTS,
+               S_IDLE,
+               S_ERROR,
+               S_NOTFOUND
+       };
+
+       enum TYPE
+       {
+               T_NONE,
+               T_ALLOCATED,
+               T_BROADCAST,
+               T_RELAY
+       };
+
+       enum SRC_TYPE
+       {
+               SRC_NONE,
+               SRC_PEERCAST,
+               SRC_SHOUTCAST,
+               SRC_ICECAST,
+               SRC_URL
+       };
+
+
+       Channel();
+       void    reset();
+       void    endThread(bool flg);
+
+       void    startMP3File(char *);
+       void    startGet();
+       void    startICY(ClientSocket *,SRC_TYPE);
+       void    startURL(const char *);
+
+
+       ChannelStream   *createSource();
+
+       void    resetPlayTime();
+
+       bool    notFound()
+       {
+               return (status == S_NOTFOUND);
+       }
+
+       bool    isPlaying()
+       {
+               return (status == S_RECEIVING) || (status == S_BROADCASTING);
+       }
+
+       bool    isReceiving()
+       {
+               return (status == S_RECEIVING);
+       }
+
+       bool    isBroadcasting()
+       {
+               return (status == S_BROADCASTING);
+       }
+
+       bool    isFull();
+
+       bool    checkBump();
+
+       bool    checkIdle();
+       void    sleepUntil(double);
+
+       bool    isActive()
+       {
+               return type != T_NONE;
+       }
+
+
+       void    connectFetch();
+       int             handshakeFetch();
+
+       bool    isIdle() {return isActive() && (status==S_IDLE);}
+
+       static THREAD_PROC      stream(ThreadInfo *);
+
+       static THREAD_PROC  waitFinish(ThreadInfo *);
+
+       void    setStatus(STATUS s);
+       const char  *getSrcTypeStr() {return srcTypes[srcType];}
+       const char      *getStatusStr() {return statusMsgs[status];}
+       const char      *getName() {return info.name.cstr();}
+       GnuID   getID() {return info.id;}
+       int             getBitrate() {return info.bitrate; }
+       void    getIDStr(char *s) {info.id.toStr(s);}
+       void    getStreamPath(char *);
+
+       void    broadcastTrackerUpdate(GnuID &,bool = false);
+       bool    sendPacketUp(ChanPacket &,GnuID &,GnuID &,GnuID &);
+
+       bool    writeVariable(Stream &, const String &,int);
+
+       bool    acceptGIV(ClientSocket *);
+
+       void    updateInfo(ChanInfo &);
+
+       int             readStream(Stream &,ChannelStream *);
+       
+       void    checkReadDelay(unsigned int);
+
+       void    processMp3Metadata(char *);
+
+       void    readHeader();
+
+       void    startStream();
+
+       XML::Node *createRelayXML(bool);
+
+       void    newPacket(ChanPacket &);
+
+       int             localListeners();
+       int             localRelays();
+
+       int             totalListeners();
+       int             totalRelays();
+
+       ::String mount;
+       ChanMeta        insertMeta;
+       ChanPacket      headPack;
+
+       ChanPacketBuffer        rawData;
+
+       ChannelStream *sourceStream;
+       unsigned int streamIndex;
+       
+
+       ChanInfo        info;
+       ChanHit         sourceHost;
+
+       GnuID           remoteID;
+
+
+       ::String  sourceURL;
+
+       bool    bump,stayConnected;
+       int             icyMetaInterval;
+       unsigned int streamPos;
+       unsigned int skipCount; //JP-EX
+       bool    readDelay;
+
+       TYPE    type;
+       ChannelSource *sourceData;
+
+       SRC_TYPE        srcType;
+
+       MP3Header mp3Head;
+       ThreadInfo      thread;
+       ThreadInfo  *finthread;
+
+       unsigned int lastIdleTime;
+       int             status;
+       static  char *statusMsgs[],*srcTypes[];
+
+       ClientSocket    *sock;
+       ClientSocket    *pushSock;
+
+       unsigned int lastTrackerUpdate;
+       unsigned int lastMetaUpdate;
+
+       double  startTime,syncTime;
+
+       WEvent  syncEvent;
+
+       Channel *next;
+
+       int channel_id;
+       ChanHit chDisp;
+       ChanHit trackerHit;
+       bool bumped;
+       unsigned int lastSkipTime;
+       unsigned int lastStopTime;
+};
+
+// ----------------------------------
+class ChanMgr
+{
+public:
+       enum {
+               MAX_IDLE_CHANNELS = 8,          // max. number of channels that can be left idle
+               MAX_METAINT = 8192                      // must be at least smaller than ChanPacket data len (ie. about half)
+               
+       };
+
+
+       ChanMgr();
+
+       Channel *deleteChannel(Channel *);
+
+       Channel *createChannel(ChanInfo &,const char *);
+       Channel *findChannelByName(const char *);
+       Channel *findChannelByIndex(int);
+       Channel *findChannelByMount(const char *);
+       Channel *findChannelByID(GnuID &);
+       Channel *findChannelByNameID(ChanInfo &);
+       Channel *findPushChannel(int);
+       Channel *findChannelByChannelID(int id);
+
+       void    broadcastTrackerSettings();
+       void    setUpdateInterval(unsigned int v);
+       void    broadcastRelays(Servent *,int,int);
+
+       int             broadcastPacketUp(ChanPacket &,GnuID &,GnuID &,GnuID &);
+       void    broadcastTrackerUpdate(GnuID &,bool = false);
+
+       bool    writeVariable(Stream &, const String &,int);
+
+       int             findChannels(ChanInfo &,Channel **,int);
+       int             findChannelsByStatus(Channel **,int,Channel::STATUS);
+       
+       int             numIdleChannels();
+       int             numChannels();
+
+       void    closeOldestIdle();
+       void    closeAll();
+       void    quit();
+
+       void    addHit(Host &,GnuID &,bool);
+       ChanHit *addHit(ChanHit &);
+       void    delHit(ChanHit &);
+       void    deadHit(ChanHit &);
+       void    setFirewalled(Host &);
+
+       ChanHitList *findHitList(ChanInfo &);
+       ChanHitList *findHitListByID(GnuID &);
+       ChanHitList     *addHitList(ChanInfo &);
+
+       void            clearHitLists();
+       void            clearDeadHits(bool);
+       int                     numHitLists();
+
+       void            setBroadcastMsg(::String &);
+
+       Channel         *createRelay(ChanInfo &,bool);
+       Channel         *findAndRelay(ChanInfo &);
+       void            startSearch(ChanInfo &);
+
+       void            playChannel(ChanInfo &);
+       void            findAndPlayChannel(ChanInfo &,bool);
+
+       bool            isBroadcasting(GnuID &);
+       bool            isBroadcasting();
+
+       int                     pickHits(ChanHitSearch &);
+
+
+
+       Channel         *channel;
+       ChanHitList     *hitlist;
+
+       GnuID   broadcastID;
+
+       ChanInfo        searchInfo;
+
+       int             numFinds;
+       ::String        broadcastMsg;
+       unsigned int            broadcastMsgInterval;
+       unsigned int lastHit,lastQuery;
+       unsigned int maxUptime;
+       bool    searchActive;
+       unsigned int            deadHitAge;
+       int             icyMetaInterval;
+       int             maxRelaysPerChannel;
+       WLock   lock;
+       int             minBroadcastTTL,maxBroadcastTTL;
+       int             pushTimeout,pushTries,maxPushHops;
+       unsigned int            autoQuery;
+       unsigned int    prefetchTime;
+       unsigned int    lastYPConnect;
+       unsigned int    lastYPConnect2;
+       unsigned int    icyIndex;
+
+       unsigned int    hostUpdateInterval;
+       unsigned int bufferTime;
+
+       GnuID   currFindAndPlayChannel;
+
+       WLock channellock;
+       WLock hitlistlock;
+};
+// ----------------------------------
+class PlayList
+{
+public:
+
+       enum TYPE
+       {
+               T_NONE,
+               T_SCPLS,
+               T_PLS,
+               T_ASX,
+               T_RAM,
+       };
+
+       PlayList(TYPE t, int max)
+       {
+               maxURLs = max;
+               numURLs = 0;
+               type = t;
+               urls = new ::String[max];
+               titles = new ::String[max];
+       }
+
+       ~PlayList()
+       {
+               delete [] urls;
+               delete [] titles;
+       }
+
+       void    addURL(const char *url, const char *tit)
+       {
+               if (numURLs < maxURLs)
+               {
+                       urls[numURLs].set(url);
+                       titles[numURLs].set(tit);
+                       numURLs++;
+               }
+       }
+       void    addChannels(const char *,Channel **,int);
+       void    addChannel(const char *,ChanInfo &);
+
+       void    writeSCPLS(Stream &);
+       void    writePLS(Stream &);
+       void    writeASX(Stream &);
+       void    writeRAM(Stream &);
+
+       void    readSCPLS(Stream &);
+       void    readPLS(Stream &);
+       void    readASX(Stream &);
+
+       void    read(Stream &s)
+       {
+               try
+               {
+                       switch (type)
+                       {
+                               case T_SCPLS: readSCPLS(s); break;
+                               case T_PLS: readPLS(s); break;
+                               case T_ASX: readASX(s); break;
+                       }
+               }catch(StreamException &) {}    // keep pls regardless of errors (eof isn`t handled properly in sockets)
+       }
+
+       void    write(Stream &s)
+       {
+               switch (type)
+               {
+                       case T_SCPLS: writeSCPLS(s); break;
+                       case T_PLS: writePLS(s); break;
+                       case T_ASX: writeASX(s); break;
+                       case T_RAM: writeRAM(s); break;
+               }
+       }
+
+       TYPE    type;
+       int             numURLs,maxURLs;
+       ::String        *urls,*titles;
+};
+
+// ----------------------------------
+
+extern ChanMgr *chanMgr;
+
+// for PCRaw start.
+bool isIndexTxt(ChanInfo *info);
+bool isIndexTxt(Channel *ch);
+int numMaxRelaysIndexTxt(Channel *ch);
+int canStreamIndexTxt(Channel *ch);
+// for PCRaw end
+
+#endif
diff --git a/PeerCast.root/PeerCast/core/common/common.h b/PeerCast.root/PeerCast/core/common/common.h
new file mode 100644 (file)
index 0000000..99a1c9b
--- /dev/null
@@ -0,0 +1,293 @@
+// ------------------------------------------------
+// File : common.h
+// Date: 4-apr-2002
+// Author: giles
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _COMMON_H
+#define _COMMON_H
+
+#pragma warning (disable: 4996)
+
+#include <stdio.h>
+#include <string.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+// ----------------------------------
+class GeneralException
+{
+public:
+    GeneralException(const char *m, int e = 0) 
+       {
+               strcpy(msg,m);
+               err=e;
+       }
+    char msg[128];
+       int err;
+};
+
+// -------------------------------------
+class StreamException : public GeneralException
+{
+public:
+       StreamException(const char *m) : GeneralException(m) {}
+       StreamException(const char *m,int e) : GeneralException(m,e) {}
+};
+
+// ----------------------------------
+class SockException : public StreamException
+{
+public:
+    SockException(const char *m="Socket") : StreamException(m) {}
+    SockException(const char *m, int e) : StreamException(m,e) {}
+};
+// ----------------------------------
+class EOFException : public StreamException
+{
+public:
+    EOFException(const char *m="EOF") : StreamException(m) {}
+    EOFException(const char *m, int e) : StreamException(m,e) {}
+};
+
+// ----------------------------------
+class CryptException : public StreamException
+{
+public:
+    CryptException(const char *m="Crypt") : StreamException(m) {}
+    CryptException(const char *m, int e) : StreamException(m,e) {}
+};
+
+
+// ----------------------------------
+class TimeoutException : public StreamException
+{
+public:
+    TimeoutException(const char *m="Timeout") : StreamException(m) {}
+};
+// --------------------------------
+class GnuID
+{
+public:
+       bool    isSame(GnuID &gid)
+       {
+               for(int i=0; i<16; i++)
+                       if (gid.id[i] != id[i])
+                               return false;
+               return true;
+       }
+
+
+       bool    isSet()
+       {
+               for(int i=0; i<16; i++)
+                       if (id[i] != 0)
+                               return true;
+               return false;
+       }
+
+       void    clear()
+       {
+               for(int i=0; i<16; i++)
+                       id[i] = 0;
+               storeTime = 0;
+       }
+
+
+       void    generate(unsigned char = 0);
+       void    encode(class Host *, const char *,const char *,unsigned char);
+
+       void    toStr(char *);
+       void    fromStr(const char *);
+
+       unsigned char   getFlags();
+
+       unsigned char id[16];
+       unsigned int storeTime;
+};
+// --------------------------------
+class GnuIDList 
+{
+public:
+       GnuIDList(int);
+       ~GnuIDList();
+       void    clear();
+       void    add(GnuID &);
+       bool    contains(GnuID &);
+       int             numUsed();
+       unsigned int getOldest();
+
+       GnuID   *ids;
+       int             maxID;
+};
+
+
+// ----------------------------------
+class Host
+{
+    inline unsigned int ip3()
+    {
+        return (ip>>24);
+    }
+    inline unsigned int ip2()
+    {
+        return (ip>>16)&0xff;
+    }
+    inline unsigned int ip1()
+    {
+        return (ip>>8)&0xff;
+    }
+    inline unsigned int ip0()
+    {
+        return ip&0xff;
+    }
+
+public:
+       Host(){init();}
+       Host(unsigned int i, unsigned short p)
+       {
+               ip = i;
+               port = p;
+               value = 0;
+       }
+
+       void    init()
+       {
+               ip = 0;
+               port = 0;
+               value = 0;
+       }
+
+
+       bool    isMemberOf(Host &);
+
+       bool    isSame(Host &h)
+       {
+               return (h.ip == ip) && (h.port == port);
+       }
+
+       bool classType() {return globalIP();}
+
+       bool    globalIP()
+       {
+               // local host
+               if ((ip3() == 127) && (ip2() == 0) && (ip1() == 0) && (ip0() == 1))
+                       return false;
+
+               // class A
+               if (ip3() == 10)
+                       return false;
+
+               // class B
+               if ((ip3() == 172) && (ip2() >= 16) && (ip2() <= 31))
+                       return false;
+
+               // class C
+               if ((ip3() == 192) && (ip2() == 168))
+                       return false;
+
+               return true;
+       }
+       bool    localIP()
+       {
+               return !globalIP();
+       }
+
+       bool    loopbackIP()
+       {
+//             return ((ipByte[3] == 127) && (ipByte[2] == 0) && (ipByte[1] == 0) && (ipByte[0] == 1));
+               return ((ip3() == 127) && (ip2() == 0) && (ip1() == 0) && (ip0() == 1));
+       }
+
+       bool    isValid()
+       {
+               return (ip != 0);
+       }
+
+
+       bool    isSameType(Host &h)
+       {
+                       return ( (globalIP() && h.globalIP()) ||
+                                (!globalIP() && !h.globalIP()) ); 
+       }
+
+       void    IPtoStr(char *str)
+       {
+               sprintf(str,"%d.%d.%d.%d",(ip>>24)&0xff,(ip>>16)&0xff,(ip>>8)&0xff,(ip)&0xff);
+       }
+
+       void    toStr(char *str)
+       {
+               sprintf(str,"%d.%d.%d.%d:%d",(ip>>24)&0xff,(ip>>16)&0xff,(ip>>8)&0xff,(ip)&0xff,port);
+       }
+
+       void    fromStrIP(const char *,int);
+       void    fromStrName(const char *,int);
+
+       bool    isLocalhost();
+
+
+       union
+       {
+               unsigned int ip;
+//             unsigned char ipByte[4];
+       };
+
+    unsigned short port;
+       unsigned int value;
+};
+// ----------------------------------
+#define SWAP2(v) ( ((v&0xff)<<8) | ((v&0xff00)>>8) )
+#define SWAP3(v) (((v&0xff)<<16) | ((v&0xff00)) | ((v&0xff0000)>>16) )
+#define SWAP4(v) (((v&0xff)<<24) | ((v&0xff00)<<8) | ((v&0xff0000)>>8) | ((v&0xff000000)>>24))
+#define TOUPPER(c) ((((c) >= 'a') && ((c) <= 'z')) ? (c)+'A'-'a' : (c))
+#define TONIBBLE(c) ((((c) >= 'A')&&((c) <= 'F')) ? (((c)-'A')+10) : ((c)-'0'))
+#define BYTES_TO_KBPS(n) (float)(((((float)n)*8.0f)/1024.0f))
+
+// ----------------------------------
+inline bool isWhiteSpace(char c)
+{
+       return (c == ' ') || (c == '\r') || (c == '\n') || (c == '\t');
+}
+
+// ----------------------------------
+inline int strToID(char *str)
+{
+       union {
+       int i;
+        char s[8];
+    };
+    strncpy(s,str,4);
+    return i;
+}
+
+// -----------------------------------
+char *getCGIarg(const char *str, const char *arg);
+bool cmpCGIarg(char *str, char *arg, char *value);
+bool hasCGIarg(char *str, char *arg);
+
+// ----------------------------------
+extern void LOG(const char *fmt,...);
+
+extern void LOG_ERROR(const char *fmt,...);
+extern void LOG_DEBUG(const char *fmt,...);
+extern void LOG_NETWORK(const char *fmt,...);
+extern void LOG_CHANNEL(const char *fmt,...);
+
+
+#endif
+
diff --git a/PeerCast.root/PeerCast/core/common/cstream.h b/PeerCast.root/PeerCast/core/common/cstream.h
new file mode 100644 (file)
index 0000000..f1a228b
--- /dev/null
@@ -0,0 +1,241 @@
+// ------------------------------------------------
+// File : cstream.h
+// Date: 12-mar-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _CSTREAM_H
+#define _CSTREAM_H
+
+// ----------------------------------
+
+class Channel;
+class ChanPacket;
+class ChanPacketv;
+class Stream;
+
+
+// ----------------------------------
+class ChanPacket
+{
+public:
+       enum 
+       {
+               MAX_DATALEN = 16384
+       };
+
+       enum TYPE
+       {
+               T_UNKNOWN       = 0,
+               T_HEAD          = 1,
+               T_DATA          = 2,
+               T_META          = 4,
+               T_PCP           = 16,
+               T_ALL           = 0xff
+       };
+
+       ChanPacket() 
+       {
+               init();
+       }
+
+       void    init()
+       {
+               type = T_UNKNOWN;
+               len = 0;
+               pos = 0;
+               sync = 0;
+               skip = false;
+       }
+       void    init(ChanPacketv &p);
+       void    init(TYPE t, const void *, unsigned int , unsigned int );
+
+       void    writeRaw(Stream &);
+       void    writePeercast(Stream &);
+       void    readPeercast(Stream &);
+
+
+       unsigned int sync;
+       unsigned int pos;
+       TYPE type;
+       unsigned int len;
+       char data[MAX_DATALEN];
+       bool skip;
+
+};
+// ----------------------------------
+class ChanPacketv
+{
+public:
+       enum {BSIZE = 0x100};
+       ChanPacketv() 
+       {
+               init();
+       }
+       ~ChanPacketv()
+       {
+               free();
+       }
+
+       void free()
+       {
+               if (data) {
+                       delete [] data;
+                       data = NULL;
+                       datasize = 0;
+               }
+       }
+       void reset()
+       {
+               free();
+               init();
+       }
+       void    init()
+       {
+               type = ChanPacket::T_UNKNOWN;
+               len = 0;
+               pos = 0;
+               sync = 0;
+               skip = false;
+               data = NULL;
+               datasize = 0;
+       }
+       void init(ChanPacket &p)
+       {
+               if (data && (datasize < p.len || datasize > p.len + BSIZE * 4)) {
+                       free();
+                       data = NULL;
+                       datasize = 0;
+               }
+               type = p.type;
+               len = p.len;
+               pos = p.pos;
+               sync = p.sync;
+               skip = p.skip;
+               if (!data) {
+                       datasize = (len & ~(BSIZE - 1)) + BSIZE;
+                       data = new char[datasize];
+               }
+               memcpy(data, p.data, len);
+       }
+       void init(ChanPacketv &p)
+       {
+               ChanPacket tp;
+               tp.init(p);
+               init(tp);
+       }
+
+       void    writeRaw(Stream &);
+       void    writePeercast(Stream &);
+       void    readPeercast(Stream &);
+
+       unsigned int sync;
+       unsigned int pos;
+       ChanPacket::TYPE type;
+       unsigned int len;
+       char *data;
+       unsigned int datasize;
+       bool skip;
+
+};
+// ----------------------------------
+class ChanPacketBuffer 
+{
+public:
+       enum {
+               MAX_PACKETS = 64,
+               NUM_SAFEPACKETS = 60 
+       };
+
+       void    init()
+       {
+               lock.on();
+               lastPos = firstPos = safePos = 0;
+               readPos = writePos = 0;
+               accept = 0;
+               lastWriteTime = 0;
+               for (int i = 0; i < MAX_PACKETS; i++) packets[i].reset();
+               lock.off();
+
+               lastSkipTime = 0;
+       }
+
+       int copyFrom(ChanPacketBuffer &,unsigned in);
+
+       bool    writePacket(ChanPacket &,bool = false);
+       void    readPacket(ChanPacket &);
+
+       bool    willSkip();
+
+       int             numPending() {return writePos-readPos;}
+
+       unsigned int    getLatestPos();
+       unsigned int    getOldestPos();
+       unsigned int    findOldestPos(unsigned int);
+       bool    findPacket(unsigned int,ChanPacket &);
+       unsigned int    getStreamPos(unsigned int);
+       unsigned int    getStreamPosEnd(unsigned int);
+       unsigned int    getLastSync();
+
+       //ChanPacket    packets[MAX_PACKETS];
+       ChanPacketv     packets[MAX_PACKETS];
+       volatile unsigned int lastPos,firstPos,safePos;
+       volatile unsigned int readPos,writePos;
+       unsigned int accept;
+       unsigned int lastWriteTime;
+       WLock lock;
+
+       unsigned int lastSkipTime;
+};
+
+// ----------------------------------
+class ChannelStream
+{
+public:
+       ChannelStream()
+       :numListeners(0)
+       ,numRelays(0) 
+       ,isPlaying(false)
+       ,fwState(0)
+       ,lastUpdate(0)
+       ,lastCheckTime(0)
+       ,parent(NULL)
+       {}
+       virtual ~ChannelStream() {}
+
+       void updateStatus(Channel *);
+       bool getStatus(Channel *,ChanPacket &);
+
+       virtual void kill() {}
+       virtual bool sendPacket(ChanPacket &,GnuID &) {return false;}
+       virtual void flush(Stream &) {}
+       virtual void readHeader(Stream &,Channel *)=0;
+       virtual int  readPacket(Stream &,Channel *)=0;
+       virtual void readEnd(Stream &,Channel *)=0;
+
+       void    readRaw(Stream &,Channel *);
+
+       int             numRelays;
+       int             numListeners;
+       bool    isPlaying;
+       int     fwState;
+       unsigned int lastUpdate;
+       unsigned int lastCheckTime;
+
+       Channel *parent;
+};
+
+#endif 
+
diff --git a/PeerCast.root/PeerCast/core/common/gnutella.cpp b/PeerCast.root/PeerCast/core/common/gnutella.cpp
new file mode 100644 (file)
index 0000000..bff67fd
--- /dev/null
@@ -0,0 +1,751 @@
+// ------------------------------------------------
+// File : gnutella.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             GnuPacket is a Gnutella protocol packet.
+//             GnuStream is a Stream that reads/writes GnuPackets
+//
+//
+// (c) 2002 peercast.org
+// 
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "gnutella.h"
+#include "stream.h"
+#include "common.h"
+#include "servent.h"
+#include "servmgr.h"
+#include "stats.h"
+#include <stdlib.h>
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ---------------------------
+const char *GNU_FUNC_STR(int func)
+{
+       switch (func)
+       {
+               case GNU_FUNC_PING: return "PING"; break;
+               case GNU_FUNC_PONG: return "PONG"; break;
+               case GNU_FUNC_QUERY: return "QUERY"; break;
+               case GNU_FUNC_HIT: return "HIT"; break;
+               case GNU_FUNC_PUSH: return "PUSH"; break;
+               default: return "UNKNOWN"; break;
+       }
+}
+
+// ---------------------------
+const char *GnuStream::getRouteStr(R_TYPE r)
+{
+       switch(r)
+       {
+               case R_PROCESS: return "PROCESS"; break;
+               case R_DEAD: return "DEAD"; break;
+               case R_DISCARD: return "DISCARD"; break;
+               case R_ACCEPTED: return "ACCEPTED"; break;
+               case R_BROADCAST: return "BROADCAST"; break;
+               case R_ROUTE: return "ROUTE"; break;
+               case R_DUPLICATE: return "DUPLICATE"; break;
+               case R_BADVERSION: return "BADVERSION"; break;
+               case R_DROP: return "DROP"; break;
+               default: return "UNKNOWN"; break;
+       }
+}
+// ---------------------------
+void GnuPacket::makeChecksumID()
+{
+       for(unsigned int i=0; i<len; i++)
+               id.id[i%16] += data[i]; 
+}
+
+// ---------------------------
+void GnuPacket::initPing(int t)
+{
+       func = GNU_FUNC_PING;
+       ttl = t;
+       hops = 0;
+       len = 0;
+
+       id.generate();
+}
+// ---------------------------
+void GnuPacket::initPong(Host &h, bool ownPong, GnuPacket &ping)
+{
+       func = GNU_FUNC_PONG;
+       ttl = ping.hops;
+       hops = 0;
+       len = 14;
+       id = ping.id;
+
+       MemoryStream pk(data,len);
+
+       pk.writeShort(h.port);          // port
+       pk.writeLong(SWAP4(h.ip));      // ip
+       if (ownPong)
+       {
+               pk.writeLong(chanMgr->numChannels());   // cnt
+               pk.writeLong(servMgr->totalOutput(false));      // total
+       }else{
+               pk.writeLong(0);                                // cnt
+               pk.writeLong(0);                                // total
+       }
+
+
+}
+// ---------------------------
+void GnuPacket::initPush(ChanHit &ch, Host &sh)
+{
+#if 0
+       func = GNU_FUNC_PUSH;
+       ttl = ch.numHops;
+       hops = 0;
+       len = 26;
+       id.generate();
+
+       MemoryStream data(data,len);
+
+       // ID of Hit packet
+       data.write(ch.packetID.id,16);
+
+       // index of channel
+       data.writeLong(ch.index);
+
+       data.writeLong(SWAP4(sh.ip));   // ip
+       data.writeShort(sh.port);               // port
+#endif
+}
+
+
+// ---------------------------
+bool GnuPacket::initHit(Host &h, Channel *ch, GnuPacket *query, bool push, bool busy, bool stable, bool tracker, int maxttl)
+{
+       if (!ch)
+               return false;
+
+       func = GNU_FUNC_HIT;
+       hops = 0;
+       id.generate();
+
+       ttl = maxttl;
+
+
+       MemoryStream mem(data,MAX_DATA);
+
+       mem.writeChar(1);                       // num hits
+       mem.writeShort(h.port);         // port
+       mem.writeLong(SWAP4(h.ip));     // ip
+
+       if (query)
+               mem.writeLong(0);                       // speed - route
+       else
+               mem.writeLong(1);                       // broadcast
+
+       
+       //mem.writeLong(ch->index);                             // index
+       mem.writeLong(0);                               // index
+       mem.writeShort(ch->getBitrate());       // bitrate
+       mem.writeShort(ch->localListeners());           // num listeners
+
+       mem.writeChar(0);       // no name
+
+       XML xml;
+       XML::Node *cn = ch->info.createChannelXML();
+       cn->add(ch->info.createTrackXML());
+       xml.setRoot(cn);
+       xml.writeCompact(mem);
+
+       mem.writeChar(0);                                                       // extra null 
+
+
+       // QHD
+       mem.writeLong('PCST');                          // vendor ID            
+       mem.writeChar(2);                                       // public sector length 
+
+       int f1 = 0, f2 = 0;
+
+       f1 = 1 | 4 | 8 | 32 | 64;       // use push | busy | stable | broadcast | tracker 
+
+       if (push) f2 |= 1;                      
+       if (busy) f2 |= 4;
+       if (stable) f2 |= 8;
+       if (!query) f2 |= 32;
+       if (tracker) f2 |= 64;
+       
+       mem.writeChar(f1);
+       mem.writeChar(f2);
+
+       {
+               // write private sector
+               char pbuf[256];
+               MemoryStream pmem(pbuf,sizeof(pbuf));
+               XML xml;
+               XML::Node *pn = servMgr->createServentXML();
+               xml.setRoot(pn);
+               xml.writeCompact(pmem);
+               pmem.writeChar(0);                      // add null terminator
+               if (pmem.pos <= 255)
+               {
+                       mem.writeChar(pmem.pos);
+                       mem.write(pmem.buf,pmem.pos);
+               }else
+                       mem.writeChar(0);
+       }
+
+
+       // queryID/not used
+       if (query)
+               mem.write(query->id.id,16);                                     
+       else
+               mem.write(id.id,16);                                    
+
+       len = mem.pos;
+
+       LOG_NETWORK("Created Hit packet: %d bytes",len);
+
+       if (len >= MAX_DATA)
+               return false;
+
+//     servMgr->addReplyID(id);
+       return true;
+}
+
+
+// ---------------------------
+void GnuPacket::initFind(const char *str, XML *xml, int maxTTL)
+{
+
+       func = GNU_FUNC_QUERY;
+       ttl = maxTTL;
+       hops = 0;
+       id.generate();
+
+       MemoryStream mem(data,MAX_DATA);
+
+       mem.writeShort(0);              // min speed
+
+       if (str)
+       {
+               int slen = strlen(str);
+               mem.write((void *)str,slen+1);  // string
+       }else
+               mem.writeChar(0);               // null string
+
+       
+       if (xml)
+               xml->writeCompact(mem);
+
+       len = mem.pos;
+}
+
+// ---------------------------
+void GnuStream::ping(int ttl)
+{
+       GnuPacket ping;
+       ping.initPing(ttl);
+//     servMgr->addReplyID(ping.id);
+       sendPacket(ping);
+       LOG_NETWORK("ping out %02x%02x%02x%02x",ping.id.id[0],ping.id.id[1],ping.id.id[2],ping.id.id[3]);
+}
+
+// ---------------------------
+void GnuStream::sendPacket(GnuPacket &p)
+{
+       try 
+       {
+               lock.on();
+               packetsOut++;
+               stats.add(Stats::NUMPACKETSOUT);
+
+               switch(p.func)
+               {
+                       case GNU_FUNC_PING: stats.add(Stats::NUMPINGOUT); break;
+                       case GNU_FUNC_PONG: stats.add(Stats::NUMPONGOUT); break;
+                       case GNU_FUNC_QUERY: stats.add(Stats::NUMQUERYOUT); break;
+                       case GNU_FUNC_HIT: stats.add(Stats::NUMHITOUT); break;
+                       case GNU_FUNC_PUSH: stats.add(Stats::NUMPUSHOUT); break;
+                       default: stats.add(Stats::NUMOTHEROUT); break;
+               }
+
+
+               write(p.id.id,16);
+               writeChar(p.func);      // ping func
+               writeChar(p.ttl);       // ttl
+               writeChar(p.hops);      // hops
+               writeLong(p.len);       // len
+
+               if (p.len)
+                       write(p.data,p.len);
+
+               stats.add(Stats::PACKETDATAOUT,23+p.len);
+
+               lock.off();
+       }catch(StreamException &e)
+       {               
+               lock.off();
+               throw e;
+       }
+}
+// ---------------------------
+bool GnuStream::readPacket(GnuPacket &p)
+{
+       try 
+       {
+               lock.on();
+               packetsIn++;
+               stats.add(Stats::NUMPACKETSIN);
+
+               read(p.id.id,16);
+               p.func = readChar();
+               p.ttl = readChar();
+               p.hops = readChar();
+               p.len = readLong();
+
+
+               if ((p.hops >= 1) && (p.hops <= 10))
+                       stats.add((Stats::STAT)((int)Stats::NUMHOPS1+p.hops-1));
+
+               stats.add(Stats::PACKETDATAIN,23+p.len);
+
+               switch(p.func)
+               {
+                       case GNU_FUNC_PING: stats.add(Stats::NUMPINGIN); break;
+                       case GNU_FUNC_PONG: stats.add(Stats::NUMPONGIN); break;
+                       case GNU_FUNC_QUERY: stats.add(Stats::NUMQUERYIN); break;
+                       case GNU_FUNC_HIT: stats.add(Stats::NUMHITIN); break;
+                       case GNU_FUNC_PUSH: stats.add(Stats::NUMPUSHIN); break;
+                       default: stats.add(Stats::NUMOTHERIN); break;
+               }
+
+
+               if (p.len)
+               {
+                       if (p.len > GnuPacket::MAX_DATA)
+                       {
+                               while (p.len--)
+                                       readChar();
+                               lock.off();
+                               return false;
+                       }
+                       read(p.data,p.len);
+               }
+
+               lock.off();
+               return true;
+       }catch(StreamException &e)
+       {               
+               lock.off();
+               throw e;
+       }
+}
+
+// ---------------------------
+GnuStream::R_TYPE GnuStream::processPacket(GnuPacket &in, Servent *serv, GnuID &routeID)
+{
+
+       R_TYPE ret = R_DISCARD;
+
+       MemoryStream data(in.data,in.len);
+
+       Host remoteHost = serv->getHost();
+
+       in.ttl--;
+       in.hops++;
+
+       routeID = in.id;
+
+
+
+       switch(in.func)
+       {
+               case GNU_FUNC_PING: // ping
+                       {
+                               LOG_NETWORK("ping: from %d.%d.%d.%d : %02x%02x%02x%02x",
+                                                       remoteHost.ip>>24&0xff,remoteHost.ip>>16&0xff,remoteHost.ip>>8&0xff,remoteHost.ip&0xff,
+                                                       in.id.id[0],in.id.id[1],in.id.id[2],in.id.id[3]
+                                       );
+                               Host sh = servMgr->serverHost;
+                               if (sh.isValid())
+                               {
+                                       if ((servMgr->getFirewall() != ServMgr::FW_ON) && (!servMgr->pubInFull()))
+                                       {
+                                               GnuPacket pong;
+                                               pong.initPong(sh,true,in);
+                                               if (serv->outputPacket(pong,true))
+                                                       LOG_NETWORK("pong out");
+                                       }
+                                       ret = R_BROADCAST;                      
+                               }
+                       }
+                       break;
+               case GNU_FUNC_PONG: // pong
+                       {
+                               {
+                                       int ip,port,cnt,total;
+                                       port = data.readShort();
+                                       ip = data.readLong();
+                                       cnt = data.readLong();
+                                       total = data.readLong();
+
+                                       ip = SWAP4(ip);
+
+
+                                       Host h;
+                                       h.ip = ip;
+                                       h.port = port;
+
+                                       char sIP[64],rIP[64];
+                                       h.toStr(sIP);
+                                       remoteHost.toStr(rIP);
+                                       
+                                       LOG_NETWORK("pong: %s via %s : %02x%02x%02x%02x",sIP,ip,rIP,in.id.id[0],in.id.id[1],in.id.id[2],in.id.id[3]);
+
+
+                                       ret = R_DISCARD;
+
+                                       if (h.isValid())
+                                       {
+
+                                               #if 0
+                                               // accept if this pong is a reply from one of our own pings, otherwise route back
+                                               if (servMgr->isReplyID(in.id))
+                                               {
+                                                       servMgr->addHost(h,ServHost::T_SERVENT,sys->getTime());
+                                                       ret = R_ACCEPTED;
+                                               }else
+                                                       ret = R_ROUTE;
+                                               #endif
+                                       }
+
+                               }
+                       }
+                       break;
+               case GNU_FUNC_QUERY: // query
+                       ret = R_BROADCAST;
+
+                       {
+                               Host sh = servMgr->serverHost;
+                               if (!sh.isValid())
+                                       sh.ip = 127<<24|1;
+
+                               char words[256];
+                               short spd = data.readShort();
+                               data.readString(words,sizeof(words));
+                               words[sizeof(words)-1] = 0;
+
+                               MemoryStream xm(&data.buf[data.pos],data.len-data.pos);
+                               xm.buf[xm.len] = 0;
+
+                               Channel *hits[16];
+                               int numHits=0;
+
+                               if (strncmp(xm.buf,"<?xml",5)==0)
+                               {
+                                       XML xml;
+                                       xml.read(xm);
+                                       XML::Node *cn = xml.findNode("channel");
+                                       if (cn)
+                                       {
+                                               ChanInfo info;
+                                               info.init(cn);
+                                               info.status = ChanInfo::S_PLAY;
+                                               numHits = chanMgr->findChannels(info,hits,16);
+                                       }
+                                       LOG_NETWORK("query XML: %s : found %d",xm.buf,numHits);
+                               }else{
+                                       ChanInfo info;
+                                       info.name.set(words);
+                                       info.genre.set(words);
+                                       info.id.fromStr(words);
+                                       info.status = ChanInfo::S_PLAY;
+                                       numHits = chanMgr->findChannels(info,hits,16);
+                                       LOG_NETWORK("query STR: %s : found %d",words,numHits);
+                               }
+
+                       
+
+                               for(int i=0; i<numHits; i++)
+                               {
+                                       bool push = (servMgr->getFirewall()!=ServMgr::FW_OFF);
+                                       bool busy = (servMgr->pubInFull() && servMgr->outFull()) || servMgr->relaysFull();
+                                       bool stable = servMgr->totalStreams>0;
+                                       bool tracker =  hits[i]->isBroadcasting();
+
+                                       GnuPacket hit;
+                                       if (hit.initHit(sh,hits[i],&in,push,busy,stable,tracker,in.hops))
+                                               serv->outputPacket(hit,true);
+                               }
+                       }
+                       break;
+               case GNU_FUNC_PUSH:     // push
+                       {
+
+                               GnuID pid;
+                               data.read(pid.id,16);
+                               
+                               //LOG("push serv= %02x%02x%02x%02x",servMgr->id[0],servMgr->id[1],servMgr->id[2],servMgr->id[3]);
+                               //LOG("pack = %02x%02x%02x%02x",id[0],id[1],id[2],id[3]);
+
+
+                               int index = data.readLong();
+                               int ip = data.readLong();
+                               int port = data.readShort();
+
+                       
+                               ip = SWAP4(ip);
+
+                               Host h(ip,port);
+                               char hostName[64];
+                               h.toStr(hostName);
+
+#if 0
+                               if (servMgr->isReplyID(pid))
+                               {
+#if 0
+                                       Channel *c = chanMgr->findChannelByIndex(index);
+
+                                       if (!c)
+                                       {
+                                               LOG_NETWORK("push 0x%x to %s: Not found",index,hostName);
+                                       }else
+                                       {
+                                               if (!c->isFull() && !servMgr->streamFull())
+                                               {
+                                                       LOG_NETWORK("push: 0x%x to %s: OK",index,hostName);
+
+                                                       Servent *s = servMgr->allocServent();
+                                                       if (s)
+                                                               s->initGIV(h,c->info.id);
+                                               }else
+                                                       LOG_NETWORK("push: 0x%x to %s: FULL",index,hostName);
+                                       }
+#endif
+                                       ret = R_ACCEPTED;
+                               }else{
+                                       LOG_NETWORK("push: 0x%x to %s: ROUTE",index,hostName);
+                                       routeID = pid;
+                                       ret = R_ROUTE;
+                               }
+#endif         
+                       }
+                       break;
+               case GNU_FUNC_HIT: // hit
+                       {
+                               ret = R_DISCARD;
+
+                               ChanHit hit;
+                               if (readHit(data,hit,in.hops,in.id))
+                               {
+
+                                       char flstr[64];
+                                       flstr[0]=0;
+                                       if (hit.firewalled) strcat(flstr,"Push,");
+                                       if (hit.tracker) strcat(flstr,"Tracker,");
+                                       
+#if 0
+                                       if ((spd == 0) && (!isBroadcastHit))
+                                       {
+                                               if (servMgr->isReplyID(queryID))
+                                               {
+                                                       ret = R_ACCEPTED;
+                                                       LOG_NETWORK("self-hit: %s 0x%02x %s %d chan",hostName,f2,flstr,num);
+                                               }else
+                                               {
+                                                       routeID = queryID;
+                                                       ret = R_ROUTE;
+                                                       LOG_NETWORK("route-hit: %s 0x%02x %s %d chan",hostName,f2,flstr,num);
+                                               }
+                                       }else
+                                       {
+                                               ret = R_BROADCAST;
+                                               LOG_NETWORK("broadcast-hit: %s 0x%02x %s %d chan",hostName,f2,flstr,num);
+                                       }
+#else
+                                       ret = R_BROADCAST;
+                                       LOG_NETWORK("broadcast-hit: %s",flstr);
+#endif
+                               }
+                       }
+                       break;
+               default:
+                       LOG_NETWORK("packet: %d",in.func);
+                       break;
+       }
+
+       
+       if ((in.ttl > 10) || (in.hops > 10) || (in.ttl==0))
+               if ((ret == R_BROADCAST) || (ret == R_ROUTE))
+                       ret = R_DEAD;
+
+       return ret;
+}
+
+// ---------------------------
+bool GnuStream::readHit(Stream &data, ChanHit &ch,int hops,GnuID &id)
+{
+       int i;
+       int num = data.readChar();      // hits
+       int port = data.readShort();            // port
+       int ip = data.readLong();               // ip
+       ip = SWAP4(ip);
+       int spd = data.readLong();              // speed/broadcast
+
+       Host h(ip,port);
+       char hostName[64];
+
+       h.IPtoStr(hostName);
+
+       bool dataValid=true;
+
+       ChanHit *hits[100];
+       int numHits=0;
+
+       for(i=0; i<num; i++)
+       {
+               int index,bitrate,listeners;
+
+
+               index = data.readLong();                // index
+               bitrate = data.readShort();             // bitrate
+               listeners = data.readShort();   // listeners
+
+               // read name .. not used.
+               char fname[256];
+               data.readString(fname,sizeof(fname));
+               fname[sizeof(fname)-1] = 0;
+
+               ch.init();
+               ch.firewalled = false;          // default to NO as we dont get the info until the next section.
+               ch.host = h;
+               ch.numListeners = listeners;
+               ch.numHops = hops;
+               ch.rhost[0] = ch.host;
+
+               ChanInfo info;
+
+
+               {
+                       char xmlData[4000];
+                       int xlen = data.readString(xmlData,sizeof(xmlData));
+
+                       if ((strncmp(xmlData,"<?xml",5)==0) && (xlen < GnuPacket::MAX_DATA))
+                       {
+                               //LOG_NETWORK("Hit XML: %s",xmlData);
+
+                               MemoryStream xm(xmlData,xlen);
+                               XML xml;
+                               xml.read(xm);
+                               XML::Node *n = xml.findNode("channel");
+                               if (n)
+                               {
+                                       info.init(n);
+                                       char idStr[64];
+                                       info.id.toStr(idStr);
+                                       LOG_NETWORK("got hit %s %s",idStr,info.name.cstr());
+
+                                       ch.upTime = n->findAttrInt("uptime");
+
+                               }else
+                                       LOG_NETWORK("Missing Channel node");
+                       }else
+                       {
+                               LOG_NETWORK("Missing XML data");
+                               //LOG_NETWORK("%s",xmlData);
+                               dataValid = false;
+                       }
+               }
+
+               if (info.id.isSet())
+               {
+                       if (!chanMgr->findHitList(info))
+                               chanMgr->addHitList(info);
+
+                       ch.recv = true;
+                       ch.chanID = info.id;
+                       ChanHit *chp = chanMgr->addHit(ch);             
+
+                       if ((chp) && (numHits<100))
+                               hits[numHits++] = chp;
+               }
+
+       }
+
+
+       int vendor = data.readLong();   // vendor ID
+
+       int pubLen = data.readChar();   // public sec length - should be 2
+
+       int f1 = data.readChar() & 0xff; // flags 1
+       int f2 = data.readChar() & 0xff; // flags 2
+
+       pubLen -= 2;
+       while (pubLen-->0)
+               data.readChar();
+
+
+       char agentStr[16];
+       agentStr[0]=0;
+       int maxPreviewTime=0;
+
+       // read private sector with peercast servant specific info
+       int privLen = data.readChar();  
+
+       if (privLen)
+       {
+               char privData[256];
+               data.read(privData,privLen);
+               if (strncmp(privData,"<?xml",5)==0)
+               {
+                       MemoryStream xm(privData,privLen);
+                       XML xml;
+                       xml.read(xm);
+                       XML::Node *sn = xml.findNode("servent");
+                       if (sn)
+                       {
+                               char *ag = sn->findAttr("agent");
+                               if (ag)
+                               {
+                                       strncpy(agentStr,ag,16);
+                                       agentStr[15]=0;
+                               }
+                               maxPreviewTime = sn->findAttrInt("preview");
+                       }
+
+               }
+       }
+
+
+       // not used anymore
+       GnuID queryID;
+       data.read(queryID.id,16);
+
+       bool isBroadcastHit=false;
+       if (f1 & 32)
+               isBroadcastHit = (f2 & 32)!=0;
+
+       for(i=0; i<numHits; i++)
+       {
+               if (f1 & 1)
+                       hits[i]->firewalled = (f2 & 1)!=0;
+
+               if (f1 & 64)
+                       hits[i]->tracker = (f2 & 64)!=0;
+
+       }
+
+       return dataValid;
+}
+
diff --git a/PeerCast.root/PeerCast/core/common/gnutella.h b/PeerCast.root/PeerCast/core/common/gnutella.h
new file mode 100644 (file)
index 0000000..d31c580
--- /dev/null
@@ -0,0 +1,295 @@
+// ------------------------------------------------
+// File : gnutella.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _GNUTELLA_H
+#define _GNUTELLA_H
+
+// --------------------------------
+#include "stream.h"
+#include "sys.h"
+
+
+
+#define GNUTELLA_SETUP 0
+
+
+// --------------------------------
+static const int GNU_FUNC_PING = 0;
+static const int GNU_FUNC_PONG = 1;
+static const int GNU_FUNC_QUERY = 128;
+static const int GNU_FUNC_HIT  = 129;
+static const int GNU_FUNC_PUSH = 64;
+
+extern const char *GNU_FUNC_STR(int);
+
+// --------------------------------
+static const char *GNU_PEERCONN                = "PEERCAST CONNECT/0.1";
+static const char *GNU_CONNECT                 = "GNUTELLA CONNECT/0.6";
+static const char *GNU_OK                      = "GNUTELLA/0.6 200 OK";
+static const char *PCX_PCP_CONNECT     = "pcp";
+
+static const char *PCX_HS_OS           = "x-peercast-os:";
+static const char *PCX_HS_DL           = "x-peercast-download:"; 
+static const char *PCX_HS_ID           = "x-peercast-id:"; 
+static const char *PCX_HS_CHANNELID    = "x-peercast-channelid:"; 
+static const char *PCX_HS_NETWORKID    = "x-peercast-networkid:"; 
+static const char *PCX_HS_MSG          = "x-peercast-msg:"; 
+static const char *PCX_HS_SUBNET       = "x-peercast-subnet:"; 
+static const char *PCX_HS_FULLHIT      = "x-peercast-fullhit:"; 
+static const char *PCX_HS_MINBCTTL     = "x-peercast-minbcttl:"; 
+static const char *PCX_HS_MAXBCTTL     = "x-peercast-maxbcttl:"; 
+static const char *PCX_HS_RELAYBC      = "x-peercast-relaybc:"; 
+static const char *PCX_HS_PRIORITY     = "x-peercast-priority:"; 
+static const char *PCX_HS_FLOWCTL      = "x-peercast-flowctl:"; 
+static const char *PCX_HS_PCP          = "x-peercast-pcp:"; 
+static const char *PCX_HS_PINGME       = "x-peercast-pingme:"; 
+static const char *PCX_HS_PORT         = "x-peercast-port:"; 
+static const char *PCX_HS_REMOTEIP     = "x-peercast-remoteip:"; 
+static const char *PCX_HS_POS          = "x-peercast-pos:"; 
+static const char *PCX_HS_SESSIONID    = "x-peercast-sessionid:"; 
+
+// official version number sent to relay to check for updates 
+static const char *PCX_OS_WIN32        = "Win32";
+static const char *PCX_OS_LINUX        = "Linux";
+static const char *PCX_OS_MACOSX       = "Apple-OSX";
+static const char *PCX_OS_WINAMP2      = "Win32-WinAmp2";
+static const char *PCX_OS_ACTIVEX      = "Win32-ActiveX";
+
+static const char *PCX_DL_URL          = "http://www.peercast.org/download.php"; 
+
+// version number sent to other clients
+static const char *PCX_OLDAGENT        = "PeerCast/0.119E";
+
+
+
+
+
+// version number used inside packets GUIDs
+static const int PEERCAST_PACKETID     = 0x0000119E;
+
+static const char *MIN_ROOTVER         = "0.119E";
+
+static const char *MIN_CONNECTVER      = "0.119D";
+static const int MIN_PACKETVER     = 0x0000119D;
+
+static const char *ICY_OK      = "ICY 200 OK";
+
+// --------------------------------
+
+static const int DEFAULT_PORT  = 7144;
+
+// --------------------------------
+
+class Servent;
+class Channel;
+class ChanHit;
+
+
+// --------------------------------
+class GnuPacket
+{
+public:
+
+
+       // --------------------------------
+       class Hash
+       {
+       public:
+
+               bool    isSame(Hash &h)
+               {
+                       return (idChecksum == h.idChecksum) && (dataChecksum == h.dataChecksum);
+               }
+
+               bool    isSameID(Hash &h)
+               {
+                       return (idChecksum == h.idChecksum);
+               }
+
+               unsigned int idChecksum;
+               unsigned int dataChecksum;
+
+       };
+       // --------------------------------
+
+       enum {
+               MAX_DATA = 2000
+       };
+
+       void    initPing(int);
+       void    initPong(Host &, bool, GnuPacket &);
+       void    initFind(const char *, class XML *,int);
+       bool    initHit(Host &, Channel *, GnuPacket *,bool,bool,bool,bool,int);
+       void    initPush(ChanHit &, Host &);
+
+
+       void makeChecksumID();
+
+       unsigned char func;
+       unsigned char ttl;
+       unsigned char hops;
+       unsigned int    len;
+       Hash    hash;
+       GnuID   id;
+
+       char data[MAX_DATA];
+};
+// --------------------------------
+class GnuPacketBuffer
+{
+public:
+       GnuPacketBuffer(int s) 
+       :size(s)
+       ,packets(new GnuPacket[size])
+       {
+               reset();
+       }
+       ~GnuPacketBuffer()
+       {
+               delete [] packets;
+       }
+
+       void    reset()
+       {
+               readPtr = writePtr = 0;
+       }
+
+       GnuPacket *curr()
+       {
+               if (numPending())
+                       return &packets[readPtr%size];
+               else
+                       return NULL;
+
+       }
+       void    next()
+       {
+               readPtr++;
+       }
+
+       int findMinHop()
+       {
+               int min=100;
+               int n = numPending();
+               for(int i=0; i<n; i++)
+               {
+                       int idx = (readPtr+i)%size;
+                       if (packets[idx].hops < min)
+                               min = packets[idx].hops;
+               }
+               return min;
+       }
+       int findMaxHop()
+       {
+               int max=0;
+               int n = numPending();
+               for(int i=0; i<n; i++)
+               {
+                       int idx = (readPtr+i)%size;
+                       if (packets[idx].hops > max)
+                               max = packets[idx].hops;
+               }
+               return max;
+       }
+
+       int percentFull()
+       {
+               return (numPending()*100) / size;
+       }
+
+       
+       int sizeOfPending()
+       {
+               int tot=0;
+               int n = numPending();
+               for(int i=0; i<n; i++)
+                       tot+=packets[(readPtr+i)%size].len;
+               return tot;
+       }
+
+       int     numPending()
+       {
+               return writePtr-readPtr;
+       }
+
+       bool    write(GnuPacket &p) 
+       {
+               if ((writePtr-readPtr) >= size)
+                       return false;
+               else
+               {
+                       packets[writePtr%size] = p;
+                       writePtr++;
+                       return true;
+               }
+       }
+
+       int     size;
+       GnuPacket *packets;
+       int     readPtr,writePtr;
+};
+
+
+
+// --------------------------------
+class GnuStream : public IndirectStream
+{
+public:
+
+       enum R_TYPE
+       {
+               R_PROCESS,
+               R_DEAD,
+               R_DISCARD,
+               R_ACCEPTED,
+               R_BROADCAST,
+               R_ROUTE,
+               R_DUPLICATE,
+               R_BADVERSION,
+               R_DROP
+       };
+
+       GnuStream()
+       {
+               init(NULL);
+       }
+
+       void    init(Stream *s)  
+       {
+               IndirectStream::init(s);
+               packetsIn = packetsOut = 0;
+       }
+
+       bool    readPacket(GnuPacket &);
+       void    sendPacket(GnuPacket &);
+       R_TYPE  processPacket(GnuPacket &, Servent *, GnuID &);
+
+       static const char *getRouteStr(R_TYPE);
+       bool    readHit(Stream &data, ChanHit &ch,int,GnuID &);
+
+
+       
+       void    ping(int);
+
+       int             packetsIn,packetsOut;
+       WLock   lock;
+};
+
+
+#endif
diff --git a/PeerCast.root/PeerCast/core/common/html-xml.h b/PeerCast.root/PeerCast/core/common/html-xml.h
new file mode 100644 (file)
index 0000000..ae1d93a
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef _HTML_H
+#define _HTML_H
+
+// ---------------------------------------
+#include "xml.h"
+
+// ---------------------------------------
+class HTML : public XML
+{
+public:
+       HTML(const char *);
+
+       
+       void    startNode(XML::Node *, const char * = NULL);
+       void    addLink(const char *, const char *);
+       void    addArgLink(const char *, const char *);
+       XML::Node *startTag(const char *, const char * = NULL,...);
+       XML::Node *startTagEnd(const char *, const char * = NULL,...);
+       void    startSingleTagEnd(const char *,...);
+       void    startTableRow(int);
+       void    end();
+       void    addRefresh(int);
+
+       char    defArgs[128];
+       XML::Node       *currNode,*headNode,*htmlNode;
+};
+
+#endif
diff --git a/PeerCast.root/PeerCast/core/common/html.cpp b/PeerCast.root/PeerCast/core/common/html.cpp
new file mode 100644 (file)
index 0000000..ff659ac
--- /dev/null
@@ -0,0 +1,558 @@
+// ------------------------------------------------
+// File : html.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             HTML protocol handling
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include "html.h"
+#include "http.h"
+#include "stream.h"
+#include "gnutella.h"
+#include "servmgr.h"
+#include "channel.h"
+#include "stats.h"
+#include "version2.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+// --------------------------------------
+HTML::HTML(const char *t, Stream &o)
+{
+       o.writeCRLF = false;
+       out = new WriteBufferStream(8192, &o);
+       out->writeCRLF = false;
+
+       title.set(t);
+       tagLevel = 0;
+       refresh = 0;
+}
+
+HTML::~HTML()
+{
+       try {
+               out->flush();
+       } catch (StreamException &) {}
+       delete out;
+}
+
+// --------------------------------------
+void HTML::writeOK(const char *content)
+{
+       out->writeLine(HTTP_SC_OK);
+       out->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT);
+       //out->writeLine("%s %s",HTTP_HS_CACHE,"no-cache");
+       out->writeLineF("%s %s",HTTP_HS_CONNECTION,"close");
+    out->writeLineF("%s %s",HTTP_HS_CONTENT,content);
+       out->writeLine("");
+}
+// --------------------------------------
+void HTML::writeVariable(Stream &s,const String &varName, int loop)
+{
+       bool r=false;
+       if (varName.startsWith("servMgr."))
+               r=servMgr->writeVariable(s,varName+8);
+       else if (varName.startsWith("chanMgr."))
+               r=chanMgr->writeVariable(s,varName+8,loop);
+       else if (varName.startsWith("stats."))
+               r=stats.writeVariable(s,varName+6);
+       else if (varName.startsWith("sys."))
+       {
+               if (varName == "sys.log.dumpHTML")
+               {
+                       sys->logBuf->dumpHTML(s);
+                       r=true;
+               }
+       }
+       else if (varName.startsWith("loop."))
+       {
+               if (varName.startsWith("loop.channel."))
+               {
+                       Channel *ch = chanMgr->findChannelByIndex(loop);
+                       if (ch)
+                               r = ch->writeVariable(s,varName+13,loop);
+               }else if (varName.startsWith("loop.servent."))
+               {
+                       Servent *sv = servMgr->findServentByIndex(loop);
+                       if (sv)
+                               r = sv->writeVariable(s,varName+13);
+               }else if (varName.startsWith("loop.filter."))
+               {
+                       ServFilter *sf = &servMgr->filters[loop];
+                       r = sf->writeVariable(s,varName+12);
+
+               }else if (varName.startsWith("loop.bcid."))
+               {
+                       BCID *bcid = servMgr->findValidBCID(loop);
+                       if (bcid)
+                               r = bcid->writeVariable(s,varName+10);
+               
+               }else if (varName == "loop.indexEven")
+               {
+                       s.writeStringF("%d",(loop&1)==0);
+                       r = true;
+               }else if (varName == "loop.index")
+               {
+                       s.writeStringF("%d",loop);
+                       r = true;
+               }else if (varName.startsWith("loop.hit."))
+               {
+                       char *idstr = getCGIarg(tmplArgs,"id=");
+                       if (idstr)
+                       {
+                               GnuID id;
+                               id.fromStr(idstr);
+                               ChanHitList *chl = chanMgr->findHitListByID(id);
+                               if (chl)
+                               {
+                                       int cnt=0;
+                                       ChanHit *ch = chl->hit;
+                                       while (ch)
+                                       {
+                                               if (ch->host.ip && !ch->dead)
+                                               {
+                                                       if (cnt == loop)
+                                                       {
+                                                               r = ch->writeVariable(s,varName+9);
+                                                               break;
+                                                       }
+                                                       cnt++;
+                                               }
+                                               ch=ch->next;
+                                       }
+
+                               }
+                       }
+               }
+
+       }
+       else if (varName.startsWith("page."))
+       {
+               if (varName.startsWith("page.channel."))
+               {
+                       char *idstr = getCGIarg(tmplArgs,"id=");
+                       if (idstr)
+                       {
+                               GnuID id;
+                               id.fromStr(idstr);
+                               Channel *ch = chanMgr->findChannelByID(id);
+                               if (ch)
+                                       r = ch->writeVariable(s,varName+13,loop);
+                       }
+               }else
+               {
+
+                       String v = varName+5;
+                       v.append('=');
+                       char *a = getCGIarg(tmplArgs,v);
+                       if (a)
+                       {
+                               s.writeString(a);               
+                               r=true;
+                       }
+               }
+       }
+
+
+       if (!r)
+               s.writeString(varName);
+}
+// --------------------------------------
+int HTML::getIntVariable(const String &varName,int loop)
+{
+       String val;
+       MemoryStream mem(val.cstr(),String::MAX_LEN);
+
+       writeVariable(mem,varName,loop);
+
+       return atoi(val.cstr());
+}
+// --------------------------------------
+bool HTML::getBoolVariable(const String &varName,int loop)
+{
+       String val;
+       MemoryStream mem(val.cstr(),String::MAX_LEN);
+
+       writeVariable(mem,varName,loop);
+
+       // integer
+       if ((val[0] >= '0') && (val[0] <= '9'))
+               return atoi(val.cstr()) != 0;   
+
+       // string
+       if (val[0]!=0)
+               return true;    
+
+       return false;
+}
+
+// --------------------------------------
+void   HTML::readIf(Stream &in,Stream *outp,int loop)
+{
+       String var;
+       bool varCond=true;
+
+       while (!in.eof())
+       {
+               char c = in.readChar();
+
+               if (c == '}')
+               {
+                       if (getBoolVariable(var,loop)==varCond)
+                       {
+                               if (readTemplate(in,outp,loop))
+                                       readTemplate(in,NULL,loop);
+                       }else{
+                               if (readTemplate(in,NULL,loop))
+                                       readTemplate(in,outp,loop);
+                       }
+                       return;
+               }else if (c == '!')
+               {
+                       varCond = !varCond;
+               }else
+               {
+                       var.append(c);
+               }
+       }
+
+}
+
+// --------------------------------------
+void   HTML::readLoop(Stream &in,Stream *outp,int loop)
+{
+       String var;
+       while (!in.eof())
+       {
+               char c = in.readChar();
+
+               if (c == '}')
+               {
+                       int cnt = getIntVariable(var,loop);
+
+                       if (cnt)
+                       {
+                               int spos = in.getPosition();
+                               for(int i=0; i<cnt; i++)
+                               {
+                                       in.seekTo(spos);
+                                       readTemplate(in,outp,i);
+                               }
+                       }else
+                       {
+                               readTemplate(in,NULL,0);
+                       }
+                       return;
+
+               }else
+               {
+                       var.append(c);
+               }
+       }
+
+}
+
+// --------------------------------------
+int HTML::readCmd(Stream &in,Stream *outp,int loop)
+{
+       String cmd;
+
+       int tmpl = TMPL_UNKNOWN;
+
+       while (!in.eof())
+       {
+               char c = in.readChar();
+
+               if (String::isWhitespace(c) || (c=='}'))
+               {
+                       if (cmd == "loop")
+                       {
+                               readLoop(in,outp,loop);
+                               tmpl = TMPL_LOOP;
+                       }else if (cmd == "if")
+                       {
+                               readIf(in,outp,loop);
+                               tmpl = TMPL_IF;
+                       }else if (cmd == "end")
+                       {
+                               tmpl = TMPL_END;
+                       }
+                       else if (cmd == "else")
+                       {
+                               tmpl = TMPL_ELSE;
+                       }
+                       break;
+               }else
+               {
+                       cmd.append(c);
+               }
+       }
+       return tmpl;
+}
+
+// --------------------------------------
+void   HTML::readVariable(Stream &in,Stream *outp,int loop)
+{
+       String var;
+       while (!in.eof())
+       {
+               char c = in.readChar();
+               if (c == '}')
+               {
+                       if (outp)
+                               writeVariable(*outp,var,loop);
+                       return;
+               }else
+               {
+                       var.append(c);
+               }
+       }
+
+}
+// --------------------------------------
+bool HTML::readTemplate(Stream &in,Stream *outp,int loop)
+{
+       while (!in.eof())
+       {
+               char c = in.readChar();
+
+               if (c == '{')
+               {
+                       c = in.readChar();
+                       if (c == '$')
+                       {
+                               readVariable(in,outp,loop);
+                       }
+                       else if (c == '@')
+                       {
+                               int t = readCmd(in,outp,loop);
+                               if (t == TMPL_END)
+                                       return false;
+                               else if (t == TMPL_ELSE)
+                                       return true;
+                       }
+                       else if (c == '{')
+                       {
+                               if (outp)
+                                       outp->writeChar(c);
+                       }
+                       else
+                               throw StreamException("Unknown template escape");
+               }else
+               {
+                       if (outp)
+                               outp->writeChar(c);
+               }
+       }
+       return false;
+}
+
+// --------------------------------------
+void HTML::writeTemplate(const char *fileName, const char *args)
+{
+       FileStream file;
+       MemoryStream mm;
+       try
+       {
+               file.openReadOnly(fileName);
+               mm.readFromFile(file);
+
+               tmplArgs = args;
+               readTemplate(mm,out,0);
+
+       }catch(StreamException &e)
+       {
+               out->writeString(e.msg);
+               out->writeString(" : ");
+               out->writeString(fileName);
+       }
+
+       mm.free2();
+       file.close();
+}
+// --------------------------------------
+void HTML::writeRawFile(const char *fileName)
+{
+       FileStream file;
+       try
+       {
+               file.openReadOnly(fileName);
+
+               file.writeTo(*out,file.length());
+
+       }catch(StreamException &)
+       {
+       }
+
+       file.close();
+}
+
+// --------------------------------------
+void HTML::locateTo(const char *url)
+{
+       out->writeLine(HTTP_SC_FOUND);
+       out->writeLineF("Location: %s",url);
+       out->writeLine("");
+}
+// --------------------------------------
+void HTML::startHTML()
+{
+       startNode("html");
+}
+// --------------------------------------
+void HTML::startBody()
+{
+       startNode("body");
+}
+// --------------------------------------
+void HTML::addHead()
+{
+       char buf[512];
+               startNode("head");
+                       startTagEnd("title",title.cstr());
+                       startTagEnd("meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\"");
+
+                       if (!refreshURL.isEmpty())
+                       {
+                               sprintf(buf,"meta http-equiv=\"refresh\" content=\"%d;URL=%s\"",refresh,refreshURL.cstr());
+                               startTagEnd(buf);
+                       }else if (refresh)
+                       {
+                               sprintf(buf,"meta http-equiv=\"refresh\" content=\"%d\"",refresh);
+                               startTagEnd(buf);
+                       }
+
+
+               end();
+}
+// --------------------------------------
+void HTML::addContent(const char *s)
+{
+       out->writeString(s);
+}
+// --------------------------------------
+void HTML::startNode(const char *tag, const char *data)
+{
+       const char *p = tag;
+       char *o = &currTag[tagLevel][0];
+
+       int i;
+       for(i=0; i<MAX_TAGLEN-1; i++)
+       {
+               char c = *p++;
+               if ((c==0) || (c==' '))
+                       break;
+               else
+                       *o++ = c;
+       }
+       *o = 0;
+
+       out->writeString("<");
+       out->writeString(tag);
+       out->writeString(">");
+       if (data)
+               out->writeString(data);
+
+       tagLevel++;
+       if (tagLevel >= MAX_TAGLEVEL)
+               throw StreamException("HTML too deep!");
+}
+// --------------------------------------
+void HTML::end()
+{
+       tagLevel--;
+       if (tagLevel < 0)
+               throw StreamException("HTML premature end!");
+
+       out->writeString("</");
+       out->writeString(&currTag[tagLevel][0]);
+       out->writeString(">");
+}
+// --------------------------------------
+void HTML::addLink(const char *url, const char *text, bool toblank)
+{
+       char buf[1024];
+
+       sprintf(buf,"a href=\"%s\" %s",url,toblank?"target=\"_blank\"":"");
+       startNode(buf,text);
+       end();
+}
+// --------------------------------------
+void HTML::startTag(const char *tag, const char *fmt,...)
+{
+       if (fmt)
+       {
+
+               va_list ap;
+               va_start(ap, fmt);
+
+               char tmp[512];
+               vsprintf(tmp,fmt,ap);
+               startNode(tag,tmp);
+
+               va_end(ap);     
+       }else{
+               startNode(tag,NULL);
+       }
+}
+// --------------------------------------
+void HTML::startTagEnd(const char *tag, const char *fmt,...)
+{
+       if (fmt)
+       {
+
+               va_list ap;
+               va_start(ap, fmt);
+
+               char tmp[512];
+               vsprintf(tmp,fmt,ap);
+               startNode(tag,tmp);
+
+               va_end(ap);     
+       }else{
+               startNode(tag,NULL);
+       }
+       end();
+}
+// --------------------------------------
+void HTML::startSingleTagEnd(const char *fmt,...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+
+       char tmp[512];
+       vsprintf(tmp,fmt,ap);
+       startNode(tmp);
+
+       va_end(ap);     
+       end();
+}
+
+// --------------------------------------
+void HTML::startTableRow(int i)
+{
+       if (i & 1)
+               startTag("tr bgcolor=\"#dddddd\" align=\"left\"");
+       else
+               startTag("tr bgcolor=\"#eeeeee\" align=\"left\"");
+}
diff --git a/PeerCast.root/PeerCast/core/common/html.h b/PeerCast.root/PeerCast/core/common/html.h
new file mode 100644 (file)
index 0000000..7f05c43
--- /dev/null
@@ -0,0 +1,91 @@
+// ------------------------------------------------
+// File : html.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _HTML_H
+#define _HTML_H
+
+// ---------------------------------------
+#include "xml.h"
+#include "sys.h"
+
+class FileStream;
+class WriteBufferStream;
+
+// ---------------------------------------
+class HTML 
+{
+public:
+       enum 
+       {
+               MAX_TAGLEVEL = 64,
+               MAX_TAGLEN = 64
+       };
+
+       enum
+       {
+               TMPL_UNKNOWN,
+               TMPL_LOOP,
+               TMPL_IF,
+               TMPL_ELSE,
+               TMPL_END
+       };
+
+       HTML(const char *,Stream &);
+       ~HTML();
+
+       void    startNode(const char *, const char * = NULL);
+       void    addLink(const char *, const char *, bool = false);
+       void    startTag(const char *, const char * = NULL,...);
+       void    startTagEnd(const char *, const char * = NULL,...);
+       void    startSingleTagEnd(const char *,...);
+       void    startTableRow(int);
+       void    end();
+       void    setRefresh(int sec) {refresh = sec;}
+       void    setRefreshURL(const char *u){refreshURL.set(u);}
+       void    addHead();
+       void    startHTML();
+       void    startBody();
+
+       void    locateTo(const char *);
+       void    addContent(const char *);
+
+       void    writeOK(const char *);
+       void    writeTemplate(const char *, const char *);
+       void    writeRawFile(const char *);
+       void    writeVariable(Stream &,const String &,int);
+       int             getIntVariable(const String &,int);
+       bool    getBoolVariable(const String &,int);
+
+
+       void    readIf(Stream &,Stream *,int);
+       void    readLoop(Stream &,Stream *,int);
+       void    readVariable(Stream &,Stream *,int);
+       bool    readTemplate(Stream &,Stream *,int);
+       int             readCmd(Stream &,Stream *,int);
+
+
+       const char *tmplArgs;
+       String  title,refreshURL;
+       char    currTag[MAX_TAGLEVEL][MAX_TAGLEN];
+       int             tagLevel;
+       int             refresh;
+       WriteBufferStream *out;
+};
+
+#endif
diff --git a/PeerCast.root/PeerCast/core/common/http.cpp b/PeerCast.root/PeerCast/core/common/http.cpp
new file mode 100644 (file)
index 0000000..95f4df4
--- /dev/null
@@ -0,0 +1,192 @@
+// ------------------------------------------------
+// File : http.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             HTTP protocol handling
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+#include <stdlib.h>
+#include "http.h"
+#include "sys.h"
+#include "common.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+//-----------------------------------------
+bool HTTP::checkResponse(int r)
+{
+       if (readResponse()!=r)
+       {
+               LOG_ERROR("Unexpected HTTP: %s",cmdLine);
+               throw StreamException("Unexpected HTTP response");
+               return false;
+       }
+       
+       return true;
+}
+//-----------------------------------------
+void HTTP::readRequest()
+{
+       readLine(cmdLine,sizeof(cmdLine));
+}
+//-----------------------------------------
+int HTTP::readResponse()
+{
+       readLine(cmdLine,sizeof(cmdLine));
+
+       char *cp = cmdLine;
+
+       while (*cp)     if (*++cp == ' ') break;
+       while (*cp) if (*++cp != ' ') break;
+
+       char *scp = cp;
+
+       while (*cp)     if (*++cp == ' ') break;
+       *cp = 0;
+
+       return atoi(scp);
+}
+       
+//-----------------------------------------
+bool   HTTP::nextHeader()
+{
+       if (readLine(cmdLine,sizeof(cmdLine)))
+       {
+               char *ap = strstr(cmdLine,":");
+               if (ap)
+                       while (*++ap)
+                               if (*ap!=' ')
+                                       break;
+               arg = ap;
+               return true;
+       }else
+       {
+               arg = NULL;
+               return false;
+       }
+
+}
+//-----------------------------------------
+bool   HTTP::isHeader(const char *hs)
+{
+       return stristr(cmdLine,hs) != NULL;
+}
+//-----------------------------------------
+bool   HTTP::isRequest(const char *rq)
+{
+       return strncmp(cmdLine,rq,strlen(rq)) == 0;
+}
+//-----------------------------------------
+char *HTTP::getArgStr()
+{
+       return arg;
+}
+//-----------------------------------------
+int    HTTP::getArgInt()
+{
+       if (arg) 
+               return atoi(arg);
+       else 
+               return 0;
+}
+//-----------------------------------------
+void HTTP::getAuthUserPass(char *user, char *pass)
+{
+       if (arg)
+       {
+               char *s = stristr(arg,"Basic");
+               if (s)
+               {
+                       while (*s)
+                               if (*s++ == ' ')
+                                       break;
+                       String str;
+                       str.set(s,String::T_BASE64);
+                       str.convertTo(String::T_ASCII);
+                       s = strstr(str.cstr(),":");
+                       if (s)
+                       {
+                               *s = 0;
+                               if (user)
+                                       strcpy(user,str.cstr());
+                               if (pass)
+                                       strcpy(pass,s+1);
+                       }                       
+               }
+       }
+}
+// -----------------------------------
+void   CookieList::init()
+{
+       for(int i=0; i<MAX_COOKIES; i++)
+               list[i].clear();
+
+       neverExpire = false;
+}
+
+// -----------------------------------
+bool   CookieList::contains(Cookie &c)
+{
+       if ((c.id[0]) && (c.ip))
+               for(int i=0; i<MAX_COOKIES; i++)
+                       if (list[i].compare(c))
+                               return true;
+
+       return false;
+}
+// -----------------------------------
+void   Cookie::logDebug(const char *str, int ind)
+{
+       char ipstr[64];
+       Host h;
+       h.ip = ip;
+       h.IPtoStr(ipstr);
+
+       LOG_DEBUG("%s %d: %s - %s",str,ind,ipstr,id);
+}
+
+// -----------------------------------
+bool   CookieList::add(Cookie &c)
+{
+       if (contains(c))
+               return false;
+
+       unsigned int oldestTime=(unsigned int)-1; 
+       int oldestIndex=0;
+
+       for(int i=0; i<MAX_COOKIES; i++)
+               if (list[i].time <= oldestTime)
+               {
+                       oldestIndex = i;
+                       oldestTime = list[i].time;
+               }
+
+       c.logDebug("Added cookie",oldestIndex);
+       c.time = sys->getTime();
+       list[oldestIndex]=c;
+       return true;
+}
+// -----------------------------------
+void   CookieList::remove(Cookie &c)
+{
+       for(int i=0; i<MAX_COOKIES; i++)
+               if (list[i].compare(c))
+                       list[i].clear();
+}
diff --git a/PeerCast.root/PeerCast/core/common/http.h b/PeerCast.root/PeerCast/core/common/http.h
new file mode 100644 (file)
index 0000000..2627d3d
--- /dev/null
@@ -0,0 +1,185 @@
+// ------------------------------------------------
+// File : http.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _HTTP_H
+#define _HTTP_H
+
+#include "stream.h"
+
+// -------------------------------------
+class HTTPException : public StreamException
+{
+public:
+       HTTPException(const char *m, int c) : StreamException(m) {code=c;}
+       int code;
+};
+
+// --------------------------------------------
+static const char *HTTP_SC_OK                  = "HTTP/1.0 200 OK";
+static const char *HTTP_SC_NOTFOUND            = "HTTP/1.0 404 Not Found";
+static const char *HTTP_SC_UNAVAILABLE = "HTTP/1.0 503 Service Unavailable";
+static const char *HTTP_SC_UNAUTHORIZED        = "HTTP/1.0 401 Unauthorized";
+static const char *HTTP_SC_FOUND               = "HTTP/1.0 302 Found";
+static const char *HTTP_SC_BADREQUEST  = "HTTP/1.0 400 Bad Request";
+static const char *HTTP_SC_FORBIDDEN   = "HTTP/1.0 403 Forbidden";
+static const char *HTTP_SC_SWITCH              = "HTTP/1.0 101 Switch protocols";
+
+static const char *RTSP_SC_OK                  = "RTSP/1.0 200 OK";
+
+
+static const char *HTTP_PROTO1         = "HTTP/1.";
+static const char *RTSP_PROTO1         = "RTSP/1.";
+
+static const char *HTTP_HS_SERVER              = "Server:";
+static const char *HTTP_HS_AGENT               = "User-Agent:"; 
+static const char *HTTP_HS_CONTENT             = "Content-Type:"; 
+static const char *HTTP_HS_CACHE               = "Cache-Control:"; 
+static const char *HTTP_HS_CONNECTION  = "Connection:"; 
+static const char *HTTP_HS_SETCOOKIE   = "Set-Cookie:";
+static const char *HTTP_HS_COOKIE              = "Cookie:";
+static const char *HTTP_HS_HOST                        = "Host:";
+static const char *HTTP_HS_ACCEPT              = "Accept:";
+static const char *HTTP_HS_LENGTH              = "Content-Length:";
+
+static const char *MIME_MP3                    = "audio/mpeg";
+static const char *MIME_XMP3           = "audio/x-mpeg";
+static const char *MIME_OGG                    = "application/ogg";
+static const char *MIME_XOGG           = "application/x-ogg";
+static const char *MIME_MOV                    = "video/quicktime";
+static const char *MIME_MPG                    = "video/mpeg";
+static const char *MIME_NSV                    = "video/nsv";
+static const char *MIME_ASF                    = "video/x-ms-asf";
+static const char *MIME_ASX                    = "video/x-ms-asf";     // same as ASF
+static const char *MIME_MMS                    = "application/x-mms-framed";
+
+static const char *MIME_RAM                    = "audio/x-pn-realaudio";
+
+
+static const char *MIME_WMA                    = "audio/x-ms-wma";
+static const char *MIME_WMV                    = "video/x-ms-wmv";
+
+static const char *MIME_HTML           = "text/html";
+static const char *MIME_XML                    = "text/xml";
+static const char *MIME_CSS                    = "text/css";
+static const char *MIME_TEXT           = "text/plain";
+static const char *MIME_PLS                    = "audio/mpegurl";
+static const char *MIME_XPLS           = "audio/x-mpegurl";
+static const char *MIME_XSCPLS         = "audio/x-scpls";
+static const char *MIME_SDP                    = "application/sdp";
+static const char *MIME_M3U                    = "audio/m3u";
+static const char *MIME_MPEGURL                = "audio/mpegurl";
+static const char *MIME_XM3U           = "audio/x-mpegurl";
+static const char *MIME_XPEERCAST      = "application/x-peercast";
+static const char *MIME_XPCP           = "application/x-peercast-pcp";
+static const char *MIME_RAW                    = "application/binary";
+static const char *MIME_JPEG           = "image/jpeg";
+static const char *MIME_GIF                    = "image/gif";
+static const char *MIME_PNG                    = "image/png";
+
+
+// --------------------------------------------
+class Cookie
+{
+public:
+       Cookie()
+       {
+               clear();
+       }
+
+       void    clear()
+       {
+               time = 0;
+               ip = 0;
+               id[0]=0;
+       }
+
+       void    set(const char *i, unsigned int nip)
+       {
+               strncpy(id,i,sizeof(id)-1);
+               id[sizeof(id)-1]=0;
+               ip = nip;
+       }
+       bool    compare(Cookie &c)
+       {
+               if (c.ip == ip)
+                       if (strcmp(c.id,id)==0)
+                               return true;
+
+               return false;
+       }
+
+       void    logDebug(const char *,int);
+
+       unsigned int ip;
+       char    id[64];
+       unsigned int time;
+};
+
+// --------------------------------------------
+class CookieList
+{
+public:
+       enum {
+               MAX_COOKIES = 32
+       };
+
+
+
+       void    init();
+       bool    add(Cookie &);
+       void    remove(Cookie &);
+       bool    contains(Cookie &);
+
+
+       Cookie list[MAX_COOKIES];
+       bool    neverExpire;
+
+};
+
+// --------------------------------------------
+class HTTP : public IndirectStream
+{
+public:
+       HTTP(Stream &s)
+       {
+               init(&s);
+       }
+
+       void    initRequest(const char *r)
+       {
+               strcpy(cmdLine,r);
+       }
+       void    readRequest();
+       bool    isRequest(const char *);
+
+       int             readResponse();
+       bool    checkResponse(int);
+
+       bool    nextHeader();
+       bool    isHeader(const char *);
+       char    *getArgStr();
+       int             getArgInt();
+
+       void    getAuthUserPass(char *, char *);
+
+       char    cmdLine[8192],*arg;
+
+};
+
+#endif
diff --git a/PeerCast.root/PeerCast/core/common/icy.cpp b/PeerCast.root/PeerCast/core/common/icy.cpp
new file mode 100644 (file)
index 0000000..954be02
--- /dev/null
@@ -0,0 +1,43 @@
+#include "icy.h"
+#include "socket.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ------------------------------------------------
+void ICYSource::stream(Channel *ch)
+{
+       ChannelStream *source=NULL;
+       try 
+       {
+
+               if (!ch->sock)
+                       throw StreamException("ICY channel has no socket");
+
+               ch->resetPlayTime();
+
+               ch->setStatus(Channel::S_BROADCASTING);
+               source = ch->createSource();
+               ch->readStream(*ch->sock,source);
+
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("Channel aborted: %s",e.msg);
+       }
+
+
+       ch->setStatus(Channel::S_CLOSING);
+
+       if (ch->sock)
+       {
+               ch->sock->close();
+               delete ch->sock;
+               ch->sock = NULL;
+       }
+
+       if (source)
+               delete source;
+
+}
diff --git a/PeerCast.root/PeerCast/core/common/icy.h b/PeerCast.root/PeerCast/core/common/icy.h
new file mode 100644 (file)
index 0000000..aec507d
--- /dev/null
@@ -0,0 +1,35 @@
+// ------------------------------------------------
+// File : icy.h
+// Date: 20-feb-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _ICY_H
+#define _ICY_H
+
+#include "channel.h"
+
+// ------------------------------------------------
+class ICYSource : public ChannelSource
+{
+public:
+       virtual void stream(Channel *);
+
+};
+
+
+
+
+#endif
diff --git a/PeerCast.root/PeerCast/core/common/id.h b/PeerCast.root/PeerCast/core/common/id.h
new file mode 100644 (file)
index 0000000..8052820
--- /dev/null
@@ -0,0 +1,101 @@
+#ifndef _ID_H
+#define _ID_H
+
+#include <string.h>
+
+// ---------------------------------------------------
+class IDString
+{
+private:
+       enum
+       {
+               LENGTH = 31
+       };
+
+       char data[LENGTH+1];
+public:
+       IDString(const char *id,int cnt)
+       {
+               if (cnt >= LENGTH)
+                       cnt=LENGTH;
+               int i;
+               for(i=0; i<cnt; i++)
+                       data[i]=id[i];
+               data[i]=0;
+       }
+
+       operator const char *()
+       {
+               return str();
+       }
+       
+       const char *str() {return data;}
+       
+};
+
+
+
+
+// ---------------------------------------------------
+class ID4
+{
+private:
+       union 
+       {
+               int     iv;
+               char cv[4];
+       };
+
+public:
+
+       ID4()
+       : iv( 0 )
+       {
+       }
+       
+       ID4(int i)
+       :iv(i)
+       {
+       }
+
+       ID4(const char *id)
+       :iv(0)
+       {
+               if (id)
+                       for(int i=0; i<4; i++)
+                               if ((cv[i]=id[i])==0)
+                                       break;
+       }
+
+       void clear()
+       {
+               iv = 0;
+       }
+
+       operator int() const
+       {
+               return iv;
+       }
+
+       int operator == (ID4 id) const
+       {
+               return iv==id.iv;
+       }
+       int operator != (ID4 id) const
+       {
+               return iv!=id.iv;
+       }
+       
+       bool    isSet() const {return iv!=0;}
+
+
+       int getValue() const {return iv;}
+       IDString getString() const {return IDString(cv,4);}
+       void *getData() {return cv;}
+
+};
+
+
+
+
+#endif
diff --git a/PeerCast.root/PeerCast/core/common/identify_encoding.c b/PeerCast.root/PeerCast/core/common/identify_encoding.c
new file mode 100644 (file)
index 0000000..fb9cfbb
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ *
+ * \8a¿\8e\9a\83R\81[\83h\82Ì\94»\95Ê\82µ\81Aiconv \97p\82Ì\95\8e\9a\83G\83\93\83R\81[\83f\83B\83\93\83O\95\8e\9a\97ñ\82ð\95Ô\82·
+ *
+ * 2001/10/24  Remove static variables
+ *             Kazuhiko Iwama <iwama@ymc.ne.jp>
+ * 2001/10/14  First version
+ *             Kazuhiko Iwama <iwama@ymc.ne.jp>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include "identify_encoding.h"
+
+enum encoding_id
+{
+       eid_KNOWN = 0,
+       eid_ASCII = 1,
+       eid_JIS   = 2,
+       eid_SJIS  = 3,
+       eid_EUCJP = 4,
+       eid_UTF8  = 5
+};
+
+const char *encoding_str[] =
+{
+       "KNOWN", "ASCII", "ISO-2022-JP", "SJIS", "EUC-JP", "UTF-8"
+};
+
+static int
+is_ascii(ie_state_t *st, const unsigned char *p)
+{
+       if (!(isprint(*p) || isspace(*p)) || *p >= 0x80)
+               st->flag = 0;
+       return st->flag;
+}
+
+static int
+is_jis(ie_state_t *st, const unsigned char *p)
+{
+       if (*p >= 0x80)
+               st->flag = 0;
+    return st->flag;
+}
+
+static int
+is_sjis(ie_state_t *st, const unsigned char *p)
+{
+       switch (st->state)
+       {
+               case 0:
+                       st->c_type = 0;
+                       if (*p >= 0x80)
+                       {
+                               st->state = 1;
+                               if              (*p >= 0x81 && *p <= 0x9f)      st->c_type = 1;
+                               else if (*p >= 0xe0 && *p <= 0xef)      st->c_type = 1;
+                               else if (*p >= 0xa1 && *p <= 0xdf)      st->state = 0;
+                               else                                                            st->flag = 1;
+                       }
+                       break;
+               case 1:
+                       if              (*p >= 0x40 && *p <= 0x7e)      st->state = 0;
+                       else if (*p >= 0x80 && *p <= 0xfc)      st->state = 0;
+                       else                                                            st->flag = 0;
+                       break;
+               default:
+                       st->flag = 0;
+                       break;
+       }
+
+       return st->flag;
+}
+
+static int
+is_eucjp(ie_state_t *st, const unsigned char *p)
+{
+       switch (st->state)
+       {
+               case 0:
+                       st->c_type = 0;
+                       if (*p >= 0x80)
+                       {
+                               st->state = 1;
+                               if              (*p >= 0xa1 && *p <= 0xfe)  st->c_type = 1;
+                               else if (*p == 0x8e              )  st->c_type = 2;
+                               else if (*p == 0x8f              )  st->c_type = 3;
+                           else                                                                st->flag = 0;
+                       }
+                       break;
+               case 1:
+                       switch (st->c_type)
+                       {
+                               case 1:
+                                       if (*p >= 0xa1 && *p <= 0xfe)  st->state = 0;
+                                       else                           st->flag = 0;
+                                       break;
+                               case 2:
+                                       if (*p >= 0x81 && *p <= 0xff)  st->state = 0;
+                                       else                           st->flag = 0;
+                                       break;
+                               case 3:
+                                       if (*p >= 0x81 && *p <= 0xff)  st->state = 2;
+                                       else                           st->flag = 0;
+                                       break;
+                               default:
+                                       st->flag = 0;
+                                       break;
+                       }
+                       break;
+               case 2:
+                       if (*p >= 0x81 && *p <= 0xff)  st->state = 0;
+                       else                           st->flag = 0;
+               default:
+                       st->flag = 0;
+                       break;
+       }
+
+       return st->flag;
+}
+
+static int
+is_utf8(ie_state_t *st, const unsigned char *p)
+{
+    switch (st->state)
+       {
+               case 0:
+                       st->c_type = 0;
+                       if (*p >= 0x80)
+                       {
+                               st->state = 1;
+                               if      (*p >= 0xc2 && *p <= 0xdf)  st->c_type = 1;
+                               else if (*p == 0xe0              )  st->c_type = 2;
+                               else if (*p >= 0xe1 && *p <= 0xef)  st->c_type = 3;
+                               else if (*p == 0xf0              )  st->c_type = 4;
+                               else if (*p >= 0xf1 && *p <= 0xf3)  st->c_type = 5;
+                               else if (*p == 0xf4              )  st->c_type = 6;
+                               else                                                            st->flag = 0;
+                       }
+                       break;
+               case 1:
+                       switch (st->c_type)
+                       {
+                               case 1:
+                                       if (*p >= 0x80 && *p <= 0xbf)  st->state = 0;
+                                       else                           st->flag = 0;
+                                       break;
+                               case 2:
+                                       if (*p >= 0xa0 && *p <= 0xbf)  st->state = 2;
+                                       else                           st->flag = 0;
+                                       break;
+                               case 3:
+                                       if (*p >= 0x80 && *p <= 0xbf)  st->state = 2;
+                                       else                           st->flag = 0;
+                                       break;
+                               case 4:
+                                       if (*p >= 0x90 && *p <= 0xbf)  st->state = 2;
+                                       else                           st->flag = 0;
+                                       break;
+                               case 5:
+                                       if (*p >= 0x80 && *p <= 0xbf)  st->state = 2;
+                                       else                           st->flag = 0;
+                                       break;
+                               case 6:
+                                       if (*p >= 0x80 && *p <= 0x8f)  st->state = 2;
+                                       else                           st->flag = 0;
+                                       break;
+                               default:
+                                       st->flag = 0;
+                                       break;
+                       }
+                       break;
+               case 2:
+                       if (st->c_type >= 2 && st->c_type <= 3)
+                       {
+                               if (*p >= 0x80 && *p <= 0xbf)  st->state = 0;
+                               else                           st->flag = 0;
+                       }else if (st->c_type >= 4 && st->c_type <= 6)
+                       {
+                               if (*p >= 0x80 && *p <= 0xbf)  st->state = 3;
+                               else                           st->flag = 0;
+                       }else{
+                               st->flag = 0;
+                       }
+                       break;
+               case 3:
+                       if (st->c_type >= 4 && st->c_type <= 6)
+                       {
+                               if (*p >= 0x80 && *p <= 0xbf)  st->state = 0;
+                               else                           st->flag = 0;
+                       }else{
+                               st->flag = 0;
+                       }
+                       break;
+               default:
+                       st->flag = 0;
+                       break;
+       }
+
+       return st->flag;
+}
+
+identify_encoding_t*
+identify_encoding_open(enum identify_encoding_order order)
+{
+       identify_encoding_t* cd;
+       cd = (identify_encoding_t*)malloc(sizeof(identify_encoding_t));
+
+       if (cd == NULL)
+       {
+               cd = (identify_encoding_t*)(-1);
+    }else{
+               cd->order = order;
+               identify_encoding_reset(cd);
+       }
+       return cd;
+}
+
+void
+identify_encoding_close(identify_encoding_t* cd)
+{
+       if (cd != (identify_encoding_t*)(-1) || cd != NULL)
+       {
+               free(cd);
+    }
+}
+
+static void
+identify_encoding_reset_state(ie_state_t* st)
+{
+       st->flag = 1;
+       st->state = 0;
+       st->c_type = 0;
+}
+
+void
+identify_encoding_reset(identify_encoding_t* cd)
+{
+       identify_encoding_reset_state(&(cd->st_ascii));
+       identify_encoding_reset_state(&(cd->st_jis));
+       identify_encoding_reset_state(&(cd->st_sjis));
+       identify_encoding_reset_state(&(cd->st_eucjp));
+       identify_encoding_reset_state(&(cd->st_utf8));
+}
+
+const char*
+identify_encoding(identify_encoding_t *cd, char* instr)
+{
+       int n;
+       unsigned char *p;
+       enum encoding_id eid = eid_KNOWN;
+
+       identify_encoding_reset(cd);
+
+       for (n = 0, p = (unsigned char *)instr; *p != '\0' && n < IDENTIFY_MAX_LENGTH; p++, n++)
+       {
+               if (cd->st_ascii.flag == 1)  is_ascii(&(cd->st_ascii), p);
+               if (cd->st_jis.flag   == 1)  is_jis(&(cd->st_jis), p);
+               if (cd->st_sjis.flag  == 1)  is_sjis(&(cd->st_sjis), p);
+               if (cd->st_eucjp.flag == 1)  is_eucjp(&(cd->st_eucjp), p);
+               if (cd->st_utf8.flag  == 1)  is_utf8(&(cd->st_utf8), p);
+    }
+
+       if      (cd->st_ascii.flag == 1)  eid = eid_ASCII;
+       else if (cd->st_jis.flag   == 1)  eid = eid_JIS;
+       else if (cd->st_utf8.flag  == 1)  eid = eid_UTF8;
+       else if (cd->order == ieo_EUCJP)
+       {
+               if      (cd->st_eucjp.flag == 1)  eid = eid_EUCJP;
+               else if (cd->st_sjis.flag  == 1)  eid = eid_SJIS;
+    }else{
+               if      (cd->st_sjis.flag  == 1)  eid = eid_SJIS;
+               else if (cd->st_eucjp.flag == 1)  eid = eid_EUCJP;
+       }
+
+       return encoding_str[ eid ];
+}
diff --git a/PeerCast.root/PeerCast/core/common/identify_encoding.h b/PeerCast.root/PeerCast/core/common/identify_encoding.h
new file mode 100644 (file)
index 0000000..5ccaf72
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ *
+ * \8a¿\8e\9a\83R\81[\83h\82Ì\94»\95Ê\82µ\81Aiconv \97p\82Ì\95\8e\9a\83G\83\93\83R\81[\83f\83B\83\93\83O\95\8e\9a\97ñ\82ð\95Ô\82·
+ *
+ * 2001/10/24  Remove static variables
+ *             Kazuhiko Iwama <iwama@ymc.ne.jp>
+ * 2001/10/14  First version
+ *             Kazuhiko Iwama <iwama@ymc.ne.jp>
+ *
+ */
+
+#ifndef IDENTIFY_ENCODING_H
+#define IDENTIFY_ENCODING_H
+
+#define IDENTIFY_MAX_LENGTH 256
+
+enum identify_encoding_order {
+       ieo_EUCJP = 0,
+       ieo_SJIS  = 1
+};
+
+typedef struct {
+       int flag;
+       int state;
+       int c_type;
+} ie_state_t;
+
+typedef struct {
+       enum identify_encoding_order order;
+       ie_state_t  st_ascii;
+       ie_state_t  st_jis;
+       ie_state_t  st_sjis;
+       ie_state_t  st_eucjp;
+       ie_state_t  st_utf8;
+} identify_encoding_t;
+
+identify_encoding_t* identify_encoding_open(enum identify_encoding_order order);
+void identify_encoding_close(identify_encoding_t* cd);
+void identify_encoding_reset(identify_encoding_t* cd);
+const char *identify_encoding(identify_encoding_t *cd, char* instr);
+
+#endif
diff --git a/PeerCast.root/PeerCast/core/common/inifile.cpp b/PeerCast.root/PeerCast/core/common/inifile.cpp
new file mode 100644 (file)
index 0000000..965f2a9
--- /dev/null
@@ -0,0 +1,168 @@
+// ------------------------------------------------
+// File : inifile.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             .INI file reading/writing class
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include <stdlib.h>
+#include "inifile.h"
+#include "sys.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+       void    openReadOnly(const char *);
+       void    openWriteReplace(const char *);
+// -----------------------------------------
+bool IniFile::openReadOnly(const char *fn)
+{
+       try 
+       {
+               fStream.openReadOnly(fn);
+       }catch(StreamException &)
+       {
+               return false;
+       }
+       return true;
+}
+// -----------------------------------------
+bool IniFile::openWriteReplace(const char *fn)
+{
+       try 
+       {
+               fStream.openWriteReplace(fn);
+#if defined(_LINUX) || defined(__APPLE__)
+               fStream.writeCRLF = false;
+#endif
+
+       }catch(StreamException &)
+       {
+               return false;
+       }
+       return true;
+}
+// -----------------------------------------
+void IniFile::close()
+{
+       fStream.close();
+}
+
+
+// -----------------------------------------
+bool   IniFile::readNext()
+{
+       if (fStream.eof())
+               return false;
+
+       try
+       {
+               fStream.readLine(currLine,256);
+       }catch(StreamException &)
+       {
+               return false;
+       }
+
+
+       // find end of value name and null terminate
+       char *nend = strstr(currLine,"=");
+
+       if (nend)
+       {
+               *nend = 0;
+               valueStr = trimstr(nend+1);
+       }else
+               valueStr = NULL;
+
+       nameStr = trimstr(currLine);
+
+       return true;
+}
+// -----------------------------------------
+bool IniFile::isName(const char *str)
+{
+       return stricmp(getName(),str)==0;
+}
+
+// -----------------------------------------
+char * IniFile::getName()
+{
+       return nameStr;
+}
+// -----------------------------------------
+int            IniFile::getIntValue()
+{
+       if (valueStr)
+               return atoi(valueStr);
+       else
+               return 0;
+}
+// -----------------------------------------
+char * IniFile::getStrValue()
+{
+       if (valueStr)
+               return valueStr;
+       else
+               return "";
+}
+// -----------------------------------------
+bool   IniFile::getBoolValue()
+{
+       if (!valueStr)
+               return false;
+
+
+       if ( (stricmp(valueStr,"yes")==0) ||
+                (stricmp(valueStr,"y")==0) ||
+                (stricmp(valueStr,"1")==0) )
+               return true;
+
+       return false;
+}
+
+// -----------------------------------------
+void   IniFile::writeIntValue(const char *name, int iv)
+{
+       sprintf(currLine,"%s = %d",name,iv);
+       fStream.writeLine(currLine);
+}
+// -----------------------------------------
+void   IniFile::writeStrValue(const char *name, const char *sv)
+{
+       sprintf(currLine,"%s = %s",name,sv);
+       fStream.writeLine(currLine);
+}
+// -----------------------------------------
+void   IniFile::writeSection(const char *name)
+{
+       fStream.writeLine("");
+       sprintf(currLine,"[%s]",name);
+       fStream.writeLine(currLine);
+}
+// -----------------------------------------
+void   IniFile::writeBoolValue(const char *name, int v)
+{
+       sprintf(currLine,"%s = %s",name,(v!=0)?"Yes":"No");
+       fStream.writeLine(currLine);
+}
+// -----------------------------------------
+void   IniFile::writeLine(const char *str)
+{
+       fStream.writeLine(str);
+}
diff --git a/PeerCast.root/PeerCast/core/common/inifile.h b/PeerCast.root/PeerCast/core/common/inifile.h
new file mode 100644 (file)
index 0000000..2b75cca
--- /dev/null
@@ -0,0 +1,53 @@
+// ------------------------------------------------
+// File : inifile.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _INIFILE
+#define _INIFILE
+
+#include "stream.h"
+
+// -----------------------------------------
+class IniFile 
+{
+public:
+       bool    openReadOnly(const char *);
+       bool    openWriteReplace(const char *);
+       void    close();
+
+       bool    readNext();
+
+       bool    isName(const char *);
+       char *  getName();
+       int             getIntValue();
+       char *  getStrValue();
+       bool    getBoolValue();
+
+       void    writeSection(const char *);
+       void    writeIntValue(const char *, int);
+       void    writeStrValue(const char *, const char *);
+       void    writeBoolValue(const char *, int);
+       void    writeLine(const char *);
+
+
+       FileStream      fStream;
+       char    currLine[256];
+       char    *nameStr,*valueStr;
+};
+
+#endif
diff --git a/PeerCast.root/PeerCast/core/common/jis.cpp b/PeerCast.root/PeerCast/core/common/jis.cpp
new file mode 100644 (file)
index 0000000..1ce75f2
--- /dev/null
@@ -0,0 +1,755 @@
+// ------------------------------------------------
+// File : jis.cpp
+// Date: 1-april-2004
+// Author: giles
+//
+//     ShiftJIS/EUC to Unicode conversions 
+//     (modified version of program by Y. Kuno, see below)
+//
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+
+/* J2Uc.c --- written by Y. Kuno, July 1996.                             */
+/* Compile with -DSJIS if you want to convert from SJIS; otherwise       */
+/* EUC-JP is assumed.                                                    */
+/* We are thankful to following people for permitting us free use        */
+/* of the following materials.                                           */
+/*   * Itaru Ichikawa (Fujitsu)  --- nkf 1.4 source code.                */
+/*   * Glenn Adams (Unicode Inc.) --- JISx0208 to Unicode mapping table. */
+/* This source code can freely be used, distributed, modified provided   */
+/* that this credit is also included in the source code.                 */
+
+// -----------------------------------
+
+#include "jis.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+// -----------------------------------
+
+#define                SJ0162  0x00e1          /* 01 - 62 ku offset */
+#define                SJ6394  0x0161          /* 63 - 94 ku offset */
+
+
+// -----------------------------------
+static unsigned short uniTable[94][94] = {
+{12288,12289,12290,65292,65294,12539,65306,65307,65311,65281,12443,12444,
+ 180,65344,168,65342,65507,65343,12541,12542,12445,12446,12291,20189,
+ 12293,12294,12295,12540,8213,8208,65295,92,12316,8214,65372,8230,
+ 8229,8216,8217,8220,8221,65288,65289,12308,12309,65339,65341,65371,
+ 65373,12296,12297,12298,12299,12300,12301,12302,12303,12304,12305,65291,
+ 8722,177,215,247,65309,8800,65308,65310,8806,8807,8734,8756,
+ 9794,9792,176,8242,8243,8451,65509,65284,162,163,65285,65283,
+ 65286,65290,65312,167,9734,9733,9675,9679,9678,9671,},
+{9670,9633,9632,9651,9650,9661,9660,8251,12306,8594,8592,8593,
+ 8595,12307,0,0,0,0,0,0,0,0,0,0,0,8712,8715,8838,8839,8834,8835,
+ 8746,8745,0,0,0,0,0,0,0,0,8743,8744,172,8658,8660,8704,8707,0,0,
+ 0,0,0,0,0,0,0,0,0,8736,8869,8978,8706,8711,8801,8786,8810,8811,
+ 8730,8765,8733,8757,8747,8748,0,0,0,0,0,0,0,8491,8240,9839,9837,
+ 9834,8224,8225,182,0,0,0,0,9711,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65296,65297,65298,65299,65300,65301,65302,
+ 65303,65304,65305,0,0,0,0,0,0,0,65313,65314,65315,65316,65317,65318,65319,
+ 65320,65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331,
+ 65332,65333,65334,65335,65336,65337,65338,0,0,0,0,0,0,65345,65346,65347,
+ 65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358,65359,
+ 65360,65361,65362,65363,65364,65365,65366,65367,65368,65369,65370,0,0,0,0,},
+{12353,12354,12355,12356,12357,12358,12359,12360,12361,12362,12363,12364,
+ 12365,12366,12367,12368,12369,12370,12371,12372,12373,12374,12375,12376,
+ 12377,12378,12379,12380,12381,12382,12383,12384,12385,12386,12387,12388,
+ 12389,12390,12391,12392,12393,12394,12395,12396,12397,12398,12399,12400,
+ 12401,12402,12403,12404,12405,12406,12407,12408,12409,12410,12411,12412,
+ 12413,12414,12415,12416,12417,12418,12419,12420,12421,12422,12423,12424,
+ 12425,12426,12427,12428,12429,12430,12431,12432,12433,12434,12435,0,0,0,0,
+ 0,0,0,0,0,0,0,},
+{12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460,
+ 12461,12462,12463,12464,12465,12466,12467,12468,12469,12470,12471,12472,
+ 12473,12474,12475,12476,12477,12478,12479,12480,12481,12482,12483,12484,
+ 12485,12486,12487,12488,12489,12490,12491,12492,12493,12494,12495,12496,
+ 12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507,12508,
+ 12509,12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520,
+ 12521,12522,12523,12524,12525,12526,12527,12528,12529,12530,12531,12532,
+ 12533,12534,0,0,0,0,0,0,0,0,},
+{913,914,915,916,917,918,919,920,921,922,923,924,
+ 925,926,927,928,929,931,932,933,934,935,936,937,0,
+ 0,0,0,0,0,0,0,945,946,947,948,949,950,951,952,953,954,
+ 955,956,957,958,959,960,961,963,964,965,966,967,
+ 968,969,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,},
+{1040,1041,1042,1043,1044,1045,1025,1046,1047,1048,1049,1050,
+ 1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,
+ 1063,1064,1065,1066,1067,1068,1069,1070,1071,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,1072,1073,1074,1075,1076,1077,1105,1078,1079,1080,
+ 1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,
+ 1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,},
+{9472,9474,9484,9488,9496,9492,9500,9516,9508,9524,9532,9473,
+ 9475,9487,9491,9499,9495,9507,9523,9515,9531,9547,9504,9519,
+ 9512,9527,9535,9501,9520,9509,9528,9538,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{20124,21782,23043,38463,21696,24859,25384,23030,36898,33909,33564,31312,
+ 24746,25569,28197,26093,33894,33446,39925,26771,22311,26017,25201,23451,
+ 22992,34427,39156,32098,32190,39822,25110,31903,34999,23433,24245,25353,
+ 26263,26696,38343,38797,26447,20197,20234,20301,20381,20553,22258,22839,
+ 22996,23041,23561,24799,24847,24944,26131,26885,28858,30031,30064,31227,
+ 32173,32239,32963,33806,34915,35586,36949,36986,21307,20117,20133,22495,
+ 32946,37057,30959,19968,22769,28322,36920,31282,33576,33419,39983,20801,
+ 21360,21693,21729,22240,23035,24341,39154,28139,32996,34093,},
+{38498,38512,38560,38907,21515,21491,23431,28879,32701,36802,38632,21359,
+ 40284,31418,19985,30867,33276,28198,22040,21764,27421,34074,39995,23013,
+ 21417,28006,29916,38287,22082,20113,36939,38642,33615,39180,21473,21942,
+ 23344,24433,26144,26355,26628,27704,27891,27945,29787,30408,31310,38964,
+ 33521,34907,35424,37613,28082,30123,30410,39365,24742,35585,36234,38322,
+ 27022,21421,20870,22290,22576,22852,23476,24310,24616,25513,25588,27839,
+ 28436,28814,28948,29017,29141,29503,32257,33398,33489,34199,36960,37467,
+ 40219,22633,26044,27738,29989,20985,22830,22885,24448,24540,},
+{25276,26106,27178,27431,27572,29579,32705,35158,40236,40206,40644,23713,
+ 27798,33659,20740,23627,25014,33222,26742,29281,20057,20474,21368,24681,
+ 28201,31311,38899,19979,21270,20206,20309,20285,20385,20339,21152,21487,
+ 22025,22799,23233,23478,23521,31185,26247,26524,26550,27468,27827,28779,
+ 29634,31117,31166,31292,31623,33457,33499,33540,33655,33775,33747,34662,
+ 35506,22057,36008,36838,36942,38686,34442,20420,23784,25105,29273,30011,
+ 33253,33469,34558,36032,38597,39187,39381,20171,20250,35299,22238,22602,
+ 22730,24315,24555,24618,24724,24674,25040,25106,25296,25913,},
+{39745,26214,26800,28023,28784,30028,30342,32117,33445,34809,38283,38542,
+ 35997,20977,21182,22806,21683,23475,23830,24936,27010,28079,30861,33995,
+ 34903,35442,37799,39608,28012,39336,34521,22435,26623,34510,37390,21123,
+ 22151,21508,24275,25313,25785,26684,26680,27579,29554,30906,31339,35226,
+ 35282,36203,36611,37101,38307,38548,38761,23398,23731,27005,38989,38990,
+ 25499,31520,27179,27263,26806,39949,28511,21106,21917,24688,25324,27963,
+ 28167,28369,33883,35088,36676,19988,39993,21494,26907,27194,38788,26666,
+ 20828,31427,33970,37340,37772,22107,40232,26658,33541,33841,},
+{31909,21000,33477,29926,20094,20355,20896,23506,21002,21208,21223,24059,
+ 21914,22570,23014,23436,23448,23515,24178,24185,24739,24863,24931,25022,
+ 25563,25954,26577,26707,26874,27454,27475,27735,28450,28567,28485,29872,
+ 29976,30435,30475,31487,31649,31777,32233,32566,32752,32925,33382,33694,
+ 35251,35532,36011,36996,37969,38291,38289,38306,38501,38867,39208,33304,
+ 20024,21547,23736,24012,29609,30284,30524,23721,32747,36107,38593,38929,
+ 38996,39000,20225,20238,21361,21916,22120,22522,22855,23305,23492,23696,
+ 24076,24190,24524,25582,26426,26071,26082,26399,26827,26820,},
+{27231,24112,27589,27671,27773,30079,31048,23395,31232,32000,24509,35215,
+ 35352,36020,36215,36556,36637,39138,39438,39740,20096,20605,20736,22931,
+ 23452,25135,25216,25836,27450,29344,30097,31047,32681,34811,35516,35696,
+ 25516,33738,38816,21513,21507,21931,26708,27224,35440,30759,26485,40653,
+ 21364,23458,33050,34384,36870,19992,20037,20167,20241,21450,21560,23470,
+ 24339,24613,25937,26429,27714,27762,27875,28792,29699,31350,31406,31496,
+ 32026,31998,32102,26087,29275,21435,23621,24040,25298,25312,25369,28192,
+ 34394,35377,36317,37624,28417,31142,39770,20136,20139,20140,},
+{20379,20384,20689,20807,31478,20849,20982,21332,21281,21375,21483,21932,
+ 22659,23777,24375,24394,24623,24656,24685,25375,25945,27211,27841,29378,
+ 29421,30703,33016,33029,33288,34126,37111,37857,38911,39255,39514,20208,
+ 20957,23597,26241,26989,23616,26354,26997,29577,26704,31873,20677,21220,
+ 22343,24062,37670,26020,27427,27453,29748,31105,31165,31563,32202,33465,
+ 33740,34943,35167,35641,36817,37329,21535,37504,20061,20534,21477,21306,
+ 29399,29590,30697,33510,36527,39366,39368,39378,20855,24858,34398,21936,
+ 31354,20598,23507,36935,38533,20018,27355,37351,23633,23624,},
+{25496,31391,27795,38772,36705,31402,29066,38536,31874,26647,32368,26705,
+ 37740,21234,21531,34219,35347,32676,36557,37089,21350,34952,31041,20418,
+ 20670,21009,20804,21843,22317,29674,22411,22865,24418,24452,24693,24950,
+ 24935,25001,25522,25658,25964,26223,26690,28179,30054,31293,31995,32076,
+ 32153,32331,32619,33550,33610,34509,35336,35427,35686,36605,38938,40335,
+ 33464,36814,39912,21127,25119,25731,28608,38553,26689,20625,27424,27770,
+ 28500,31348,32080,34880,35363,26376,20214,20537,20518,20581,20860,21048,
+ 21091,21927,22287,22533,23244,24314,25010,25080,25331,25458,},
+{26908,27177,29309,29356,29486,30740,30831,32121,30476,32937,35211,35609,
+ 36066,36562,36963,37749,38522,38997,39443,40568,20803,21407,21427,24187,
+ 24358,28187,28304,29572,29694,32067,33335,35328,35578,38480,20046,20491,
+ 21476,21628,22266,22993,23396,24049,24235,24359,25144,25925,26543,28246,
+ 29392,31946,34996,32929,32993,33776,34382,35463,36328,37431,38599,39015,
+ 40723,20116,20114,20237,21320,21577,21566,23087,24460,24481,24735,26791,
+ 27278,29786,30849,35486,35492,35703,37264,20062,39881,20132,20348,20399,
+ 20505,20502,20809,20844,21151,21177,21246,21402,21475,21521,},
+{21518,21897,22353,22434,22909,23380,23389,23439,24037,24039,24055,24184,
+ 24195,24218,24247,24344,24658,24908,25239,25304,25511,25915,26114,26179,
+ 26356,26477,26657,26775,27083,27743,27946,28009,28207,28317,30002,30343,
+ 30828,31295,31968,32005,32024,32094,32177,32789,32771,32943,32945,33108,
+ 33167,33322,33618,34892,34913,35611,36002,36092,37066,37237,37489,30783,
+ 37628,38308,38477,38917,39321,39640,40251,21083,21163,21495,21512,22741,
+ 25335,28640,35946,36703,40633,20811,21051,21578,22269,31296,37239,40288,
+ 40658,29508,28425,33136,29969,24573,24794,39592,29403,36796,},
+{27492,38915,20170,22256,22372,22718,23130,24680,25031,26127,26118,26681,
+ 26801,28151,30165,32058,33390,39746,20123,20304,21449,21766,23919,24038,
+ 24046,26619,27801,29811,30722,35408,37782,35039,22352,24231,25387,20661,
+ 20652,20877,26368,21705,22622,22971,23472,24425,25165,25505,26685,27507,
+ 28168,28797,37319,29312,30741,30758,31085,25998,32048,33756,35009,36617,
+ 38555,21092,22312,26448,32618,36001,20916,22338,38442,22586,27018,32948,
+ 21682,23822,22524,30869,40442,20316,21066,21643,25662,26152,26388,26613,
+ 31364,31574,32034,37679,26716,39853,31545,21273,20874,21047,},
+{23519,25334,25774,25830,26413,27578,34217,38609,30352,39894,25420,37638,
+ 39851,30399,26194,19977,20632,21442,23665,24808,25746,25955,26719,29158,
+ 29642,29987,31639,32386,34453,35715,36059,37240,39184,26028,26283,27531,
+ 20181,20180,20282,20351,21050,21496,21490,21987,22235,22763,22987,22985,
+ 23039,23376,23629,24066,24107,24535,24605,25351,25903,23388,26031,26045,
+ 26088,26525,27490,27515,27663,29509,31049,31169,31992,32025,32043,32930,
+ 33026,33267,35222,35422,35433,35430,35468,35566,36039,36060,38604,39164,
+ 27503,20107,20284,20365,20816,23383,23546,24904,25345,26178,},
+{27425,28363,27835,29246,29885,30164,30913,31034,32780,32819,33258,33940,
+ 36766,27728,40575,24335,35672,40235,31482,36600,23437,38635,19971,21489,
+ 22519,22833,23241,23460,24713,28287,28422,30142,36074,23455,34048,31712,
+ 20594,26612,33437,23649,34122,32286,33294,20889,23556,25448,36198,26012,
+ 29038,31038,32023,32773,35613,36554,36974,34503,37034,20511,21242,23610,
+ 26451,28796,29237,37196,37320,37675,33509,23490,24369,24825,20027,21462,
+ 23432,25163,26417,27530,29417,29664,31278,33131,36259,37202,39318,20754,
+ 21463,21610,23551,25480,27193,32172,38656,22234,21454,21608,},
+{23447,23601,24030,20462,24833,25342,27954,31168,31179,32066,32333,32722,
+ 33261,33311,33936,34886,35186,35728,36468,36655,36913,37195,37228,38598,
+ 37276,20160,20303,20805,21313,24467,25102,26580,27713,28171,29539,32294,
+ 37325,37507,21460,22809,23487,28113,31069,32302,31899,22654,29087,20986,
+ 34899,36848,20426,23803,26149,30636,31459,33308,39423,20934,24490,26092,
+ 26991,27529,28147,28310,28516,30462,32020,24033,36981,37255,38918,20966,
+ 21021,25152,26257,26329,28186,24246,32210,32626,26360,34223,34295,35576,
+ 21161,21465,22899,24207,24464,24661,37604,38500,20663,20767,},
+{21213,21280,21319,21484,21736,21830,21809,22039,22888,22974,23100,23477,
+ 23558,23567,23569,23578,24196,24202,24288,24432,25215,25220,25307,25484,
+ 25463,26119,26124,26157,26230,26494,26786,27167,27189,27836,28040,28169,
+ 28248,28988,28966,29031,30151,30465,30813,30977,31077,31216,31456,31505,
+ 31911,32057,32918,33750,33931,34121,34909,35059,35359,35388,35412,35443,
+ 35937,36062,37284,37478,37758,37912,38556,38808,19978,19976,19998,20055,
+ 20887,21104,22478,22580,22732,23330,24120,24773,25854,26465,26454,27972,
+ 29366,30067,31331,33976,35698,37304,37664,22065,22516,39166,},
+{25325,26893,27542,29165,32340,32887,33394,35302,39135,34645,36785,23611,
+ 20280,20449,20405,21767,23072,23517,23529,24515,24910,25391,26032,26187,
+ 26862,27035,28024,28145,30003,30137,30495,31070,31206,32051,33251,33455,
+ 34218,35242,35386,36523,36763,36914,37341,38663,20154,20161,20995,22645,
+ 22764,23563,29978,23613,33102,35338,36805,38499,38765,31525,35535,38920,
+ 37218,22259,21416,36887,21561,22402,24101,25512,27700,28810,30561,31883,
+ 32736,34928,36930,37204,37648,37656,38543,29790,39620,23815,23913,25968,
+ 26530,36264,38619,25454,26441,26905,33733,38935,38592,35070,},
+{28548,25722,23544,19990,28716,30045,26159,20932,21046,21218,22995,24449,
+ 24615,25104,25919,25972,26143,26228,26866,26646,27491,28165,29298,29983,
+ 30427,31934,32854,22768,35069,35199,35488,35475,35531,36893,37266,38738,
+ 38745,25993,31246,33030,38587,24109,24796,25114,26021,26132,26512,30707,
+ 31309,31821,32318,33034,36012,36196,36321,36447,30889,20999,25305,25509,
+ 25666,25240,35373,31363,31680,35500,38634,32118,33292,34633,20185,20808,
+ 21315,21344,23459,23554,23574,24029,25126,25159,25776,26643,26676,27849,
+ 27973,27927,26579,28508,29006,29053,26059,31359,31661,32218,},
+{32330,32680,33146,33307,33337,34214,35438,36046,36341,36984,36983,37549,
+ 37521,38275,39854,21069,21892,28472,28982,20840,31109,32341,33203,31950,
+ 22092,22609,23720,25514,26366,26365,26970,29401,30095,30094,30990,31062,
+ 31199,31895,32032,32068,34311,35380,38459,36961,40736,20711,21109,21452,
+ 21474,20489,21930,22766,22863,29245,23435,23652,21277,24803,24819,25436,
+ 25475,25407,25531,25805,26089,26361,24035,27085,27133,28437,29157,20105,
+ 30185,30456,31379,31967,32207,32156,32865,33609,33624,33900,33980,34299,
+ 35013,36208,36865,36973,37783,38684,39442,20687,22679,24974,},
+{33235,34101,36104,36896,20419,20596,21063,21363,24687,25417,26463,28204,
+ 36275,36895,20439,23646,36042,26063,32154,21330,34966,20854,25539,23384,
+ 23403,23562,25613,26449,36956,20182,22810,22826,27760,35409,21822,22549,
+ 22949,24816,25171,26561,33333,26965,38464,39364,39464,20307,22534,23550,
+ 32784,23729,24111,24453,24608,24907,25140,26367,27888,28382,32974,33151,
+ 33492,34955,36024,36864,36910,38538,40667,39899,20195,21488,22823,31532,
+ 37261,38988,40441,28381,28711,21331,21828,23429,25176,25246,25299,27810,
+ 28655,29730,35351,37944,28609,35582,33592,20967,34552,21482,},
+{21481,20294,36948,36784,22890,33073,24061,31466,36799,26842,35895,29432,
+ 40008,27197,35504,20025,21336,22022,22374,25285,25506,26086,27470,28129,
+ 28251,28845,30701,31471,31658,32187,32829,32966,34507,35477,37723,22243,
+ 22727,24382,26029,26262,27264,27573,30007,35527,20516,30693,22320,24347,
+ 24677,26234,27744,30196,31258,32622,33268,34584,36933,39347,31689,30044,
+ 31481,31569,33988,36880,31209,31378,33590,23265,30528,20013,20210,23449,
+ 24544,25277,26172,26609,27880,34411,34935,35387,37198,37619,39376,27159,
+ 28710,29482,33511,33879,36015,19969,20806,20939,21899,23541,},
+{24086,24115,24193,24340,24373,24427,24500,25074,25361,26274,26397,28526,
+ 29266,30010,30522,32884,33081,33144,34678,35519,35548,36229,36339,37530,
+ 38263,38914,40165,21189,25431,30452,26389,27784,29645,36035,37806,38515,
+ 27941,22684,26894,27084,36861,37786,30171,36890,22618,26626,25524,27131,
+ 20291,28460,26584,36795,34086,32180,37716,26943,28528,22378,22775,23340,
+ 32044,29226,21514,37347,40372,20141,20302,20572,20597,21059,35998,21576,
+ 22564,23450,24093,24213,24237,24311,24351,24716,25269,25402,25552,26799,
+ 27712,30855,31118,31243,32224,33351,35330,35558,36420,36883,},
+{37048,37165,37336,40718,27877,25688,25826,25973,28404,30340,31515,36969,
+ 37841,28346,21746,24505,25764,36685,36845,37444,20856,22635,22825,23637,
+ 24215,28155,32399,29980,36028,36578,39003,28857,20253,27583,28593,30000,
+ 38651,20814,21520,22581,22615,22956,23648,24466,26007,26460,28193,30331,
+ 33759,36077,36884,37117,37709,30757,30778,21162,24230,22303,22900,24594,
+ 20498,20826,20908,20941,20992,21776,22612,22616,22871,23445,23798,23947,
+ 24764,25237,25645,26481,26691,26812,26847,30423,28120,28271,28059,28783,
+ 29128,24403,30168,31095,31561,31572,31570,31958,32113,21040,},
+{33891,34153,34276,35342,35588,35910,36367,36867,36879,37913,38518,38957,
+ 39472,38360,20685,21205,21516,22530,23566,24999,25758,27934,30643,31461,
+ 33012,33796,36947,37509,23776,40199,21311,24471,24499,28060,29305,30563,
+ 31167,31716,27602,29420,35501,26627,27233,20984,31361,26932,23626,40182,
+ 33515,23493,37193,28702,22136,23663,24775,25958,27788,35930,36929,38931,
+ 21585,26311,37389,22856,37027,20869,20045,20970,34201,35598,28760,25466,
+ 37707,26978,39348,32260,30071,21335,26976,36575,38627,27741,20108,23612,
+ 24336,36841,21250,36049,32905,34425,24319,26085,20083,20837,},
+{22914,23615,38894,20219,22922,24525,35469,28641,31152,31074,23527,33905,
+ 29483,29105,24180,24565,25467,25754,29123,31896,20035,24316,20043,22492,
+ 22178,24745,28611,32013,33021,33075,33215,36786,35223,34468,24052,25226,
+ 25773,35207,26487,27874,27966,29750,30772,23110,32629,33453,39340,20467,
+ 24259,25309,25490,25943,26479,30403,29260,32972,32954,36649,37197,20493,
+ 22521,23186,26757,26995,29028,29437,36023,22770,36064,38506,36889,34687,
+ 31204,30695,33833,20271,21093,21338,25293,26575,27850,30333,31636,31893,
+ 33334,34180,36843,26333,28448,29190,32283,33707,39361,40614,},
+{20989,31665,30834,31672,32903,31560,27368,24161,32908,30033,30048,20843,
+ 37474,28300,30330,37271,39658,20240,32624,25244,31567,38309,40169,22138,
+ 22617,34532,38588,20276,21028,21322,21453,21467,24070,25644,26001,26495,
+ 27710,27726,29256,29359,29677,30036,32321,33324,34281,36009,31684,37318,
+ 29033,38930,39151,25405,26217,30058,30436,30928,34115,34542,21290,21329,
+ 21542,22915,24199,24444,24754,25161,25209,25259,26000,27604,27852,30130,
+ 30382,30865,31192,32203,32631,32933,34987,35513,36027,36991,38750,39131,
+ 27147,31800,20633,23614,24494,26503,27608,29749,30473,32654,},
+{40763,26570,31255,21305,30091,39661,24422,33181,33777,32920,24380,24517,
+ 30050,31558,36924,26727,23019,23195,32016,30334,35628,20469,24426,27161,
+ 27703,28418,29922,31080,34920,35413,35961,24287,25551,30149,31186,33495,
+ 37672,37618,33948,34541,39981,21697,24428,25996,27996,28693,36007,36051,
+ 38971,25935,29942,19981,20184,22496,22827,23142,23500,20904,24067,24220,
+ 24598,25206,25975,26023,26222,28014,29238,31526,33104,33178,33433,35676,
+ 36000,36070,36212,38428,38468,20398,25771,27494,33310,33889,34154,37096,
+ 23553,26963,39080,33914,34135,20239,21103,24489,24133,26381,},
+{31119,33145,35079,35206,28149,24343,25173,27832,20175,29289,39826,20998,
+ 21563,22132,22707,24996,25198,28954,22894,31881,31966,32027,38640,25991,
+ 32862,19993,20341,20853,22592,24163,24179,24330,26564,20006,34109,38281,
+ 38491,31859,38913,20731,22721,30294,30887,21029,30629,34065,31622,20559,
+ 22793,29255,31687,32232,36794,36820,36941,20415,21193,23081,24321,38829,
+ 20445,33303,37610,22275,25429,27497,29995,35036,36628,31298,21215,22675,
+ 24917,25098,26286,27597,31807,33769,20515,20472,21253,21574,22577,22857,
+ 23453,23792,23791,23849,24214,25265,25447,25918,26041,26379,},
+{27861,27873,28921,30770,32299,32990,33459,33804,34028,34562,35090,35370,
+ 35914,37030,37586,39165,40179,40300,20047,20129,20621,21078,22346,22952,
+ 24125,24536,24537,25151,26292,26395,26576,26834,20882,32033,32938,33192,
+ 35584,35980,36031,37502,38450,21536,38956,21271,20693,21340,22696,25778,
+ 26420,29287,30566,31302,37350,21187,27809,27526,22528,24140,22868,26412,
+ 32763,20961,30406,25705,30952,39764,40635,22475,22969,26151,26522,27598,
+ 21737,27097,24149,33180,26517,39850,26622,40018,26717,20134,20451,21448,
+ 25273,26411,27819,36804,20397,32365,40639,19975,24930,28288,},
+{28459,34067,21619,26410,39749,24051,31637,23724,23494,34588,28234,34001,
+ 31252,33032,22937,31885,27665,30496,21209,22818,28961,29279,30683,38695,
+ 40289,26891,23167,23064,20901,21517,21629,26126,30431,36855,37528,40180,
+ 23018,29277,28357,20813,26825,32191,32236,38754,40634,25720,27169,33538,
+ 22916,23391,27611,29467,30450,32178,32791,33945,20786,26408,40665,30446,
+ 26466,21247,39173,23588,25147,31870,36016,21839,24758,32011,38272,21249,
+ 20063,20918,22812,29242,32822,37326,24357,30690,21380,24441,32004,34220,
+ 35379,36493,38742,26611,34222,37971,24841,24840,27833,30290,},
+{35565,36664,21807,20305,20778,21191,21451,23461,24189,24736,24962,25558,
+ 26377,26586,28263,28044,29494,29495,30001,31056,35029,35480,36938,37009,
+ 37109,38596,34701,22805,20104,20313,19982,35465,36671,38928,20653,24188,
+ 22934,23481,24248,25562,25594,25793,26332,26954,27096,27915,28342,29076,
+ 29992,31407,32650,32768,33865,33993,35201,35617,36362,36965,38525,39178,
+ 24958,25233,27442,27779,28020,32716,32764,28096,32645,34746,35064,26469,
+ 33713,38972,38647,27931,32097,33853,37226,20081,21365,23888,27396,28651,
+ 34253,34349,35239,21033,21519,23653,26446,26792,29702,29827,},
+{30178,35023,35041,37324,38626,38520,24459,29575,31435,33870,25504,30053,
+ 21129,27969,28316,29705,30041,30827,31890,38534,31452,40845,20406,24942,
+ 26053,34396,20102,20142,20698,20001,20940,23534,26009,26753,28092,29471,
+ 30274,30637,31260,31975,33391,35538,36988,37327,38517,38936,21147,32209,
+ 20523,21400,26519,28107,29136,29747,33256,36650,38563,40023,40607,29792,
+ 22593,28057,32047,39006,20196,20278,20363,20919,21169,23994,24604,29618,
+ 31036,33491,37428,38583,38646,38666,40599,40802,26278,27508,21015,21155,
+ 28872,35010,24265,24651,24976,28451,29001,31806,32244,32879,},
+{34030,36899,37676,21570,39791,27347,28809,36034,36335,38706,21172,23105,
+ 24266,24324,26391,27004,27028,28010,28431,29282,29436,31725,32769,32894,
+ 34635,37070,20845,40595,31108,32907,37682,35542,20525,21644,35441,27498,
+ 36036,33031,24785,26528,40434,20121,20120,39952,35435,34241,34152,26880,
+ 28286,30871,33109,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{24332,19984,19989,20010,20017,20022,20028,20031,20034,20054,20056,20098,
+ 20101,35947,20106,33298,24333,20110,20126,20127,20128,20130,20144,20147,
+ 20150,20174,20173,20164,20166,20162,20183,20190,20205,20191,20215,20233,
+ 20314,20272,20315,20317,20311,20295,20342,20360,20367,20376,20347,20329,
+ 20336,20369,20335,20358,20374,20760,20436,20447,20430,20440,20443,20433,
+ 20442,20432,20452,20453,20506,20520,20500,20522,20517,20485,20252,20470,
+ 20513,20521,20524,20478,20463,20497,20486,20547,20551,26371,20565,20560,
+ 20552,20570,20566,20588,20600,20608,20634,20613,20660,20658,},
+{20681,20682,20659,20674,20694,20702,20709,20717,20707,20718,20729,20725,
+ 20745,20737,20738,20758,20757,20756,20762,20769,20794,20791,20796,20795,
+ 20799,20800,20818,20812,20820,20834,31480,20841,20842,20846,20864,20866,
+ 22232,20876,20873,20879,20881,20883,20885,20886,20900,20902,20898,20905,
+ 20906,20907,20915,20913,20914,20912,20917,20925,20933,20937,20955,20960,
+ 34389,20969,20973,20976,20981,20990,20996,21003,21012,21006,21031,21034,
+ 21038,21043,21049,21071,21060,21067,21068,21086,21076,21098,21108,21097,
+ 21107,21119,21117,21133,21140,21138,21105,21128,21137,36776,},
+{36775,21164,21165,21180,21173,21185,21197,21207,21214,21219,21222,39149,
+ 21216,21235,21237,21240,21241,21254,21256,30008,21261,21264,21263,21269,
+ 21274,21283,21295,21297,21299,21304,21312,21318,21317,19991,21321,21325,
+ 20950,21342,21353,21358,22808,21371,21367,21378,21398,21408,21414,21413,
+ 21422,21424,21430,21443,31762,38617,21471,26364,29166,21486,21480,21485,
+ 21498,21505,21565,21568,21548,21549,21564,21550,21558,21545,21533,21582,
+ 21647,21621,21646,21599,21617,21623,21616,21650,21627,21632,21622,21636,
+ 21648,21638,21703,21666,21688,21669,21676,21700,21704,21672,},
+{21675,21698,21668,21694,21692,21720,21733,21734,21775,21780,21757,21742,
+ 21741,21754,21730,21817,21824,21859,21836,21806,21852,21829,21846,21847,
+ 21816,21811,21853,21913,21888,21679,21898,21919,21883,21886,21912,21918,
+ 21934,21884,21891,21929,21895,21928,21978,21957,21983,21956,21980,21988,
+ 21972,22036,22007,22038,22014,22013,22043,22009,22094,22096,29151,22068,
+ 22070,22066,22072,22123,22116,22063,22124,22122,22150,22144,22154,22176,
+ 22164,22159,22181,22190,22198,22196,22210,22204,22209,22211,22208,22216,
+ 22222,22225,22227,22231,22254,22265,22272,22271,22276,22281,},
+{22280,22283,22285,22291,22296,22294,21959,22300,22310,22327,22328,22350,
+ 22331,22336,22351,22377,22464,22408,22369,22399,22409,22419,22432,22451,
+ 22436,22442,22448,22467,22470,22484,22482,22483,22538,22486,22499,22539,
+ 22553,22557,22642,22561,22626,22603,22640,27584,22610,22589,22649,22661,
+ 22713,22687,22699,22714,22750,22715,22712,22702,22725,22739,22737,22743,
+ 22745,22744,22757,22748,22756,22751,22767,22778,22777,22779,22780,22781,
+ 22786,22794,22800,22811,26790,22821,22828,22829,22834,22840,22846,31442,
+ 22869,22864,22862,22874,22872,22882,22880,22887,22892,22889,},
+{22904,22913,22941,20318,20395,22947,22962,22982,23016,23004,22925,23001,
+ 23002,23077,23071,23057,23068,23049,23066,23104,23148,23113,23093,23094,
+ 23138,23146,23194,23228,23230,23243,23234,23229,23267,23255,23270,23273,
+ 23254,23290,23291,23308,23307,23318,23346,23248,23338,23350,23358,23363,
+ 23365,23360,23377,23381,23386,23387,23397,23401,23408,23411,23413,23416,
+ 25992,23418,23424,23427,23462,23480,23491,23495,23497,23508,23504,23524,
+ 23526,23522,23518,23525,23531,23536,23542,23539,23557,23559,23560,23565,
+ 23571,23584,23586,23592,23608,23609,23617,23622,23630,23635,},
+{23632,23631,23409,23660,23662,20066,23670,23673,23692,23697,23700,22939,
+ 23723,23739,23734,23740,23735,23749,23742,23751,23769,23785,23805,23802,
+ 23789,23948,23786,23819,23829,23831,23900,23839,23835,23825,23828,23842,
+ 23834,23833,23832,23884,23890,23886,23883,23916,23923,23926,23943,23940,
+ 23938,23970,23965,23980,23982,23997,23952,23991,23996,24009,24013,24019,
+ 24018,24022,24027,24043,24050,24053,24075,24090,24089,24081,24091,24118,
+ 24119,24132,24131,24128,24142,24151,24148,24159,24162,24164,24135,24181,
+ 24182,24186,40636,24191,24224,24257,24258,24264,24272,24271,},
+{24278,24291,24285,24282,24283,24290,24289,24296,24297,24300,24305,24307,
+ 24304,24308,24312,24318,24323,24329,24413,24412,24331,24337,24342,24361,
+ 24365,24376,24385,24392,24396,24398,24367,24401,24406,24407,24409,24417,
+ 24429,24435,24439,24451,24450,24447,24458,24456,24465,24455,24478,24473,
+ 24472,24480,24488,24493,24508,24534,24571,24548,24568,24561,24541,24755,
+ 24575,24609,24672,24601,24592,24617,24590,24625,24603,24597,24619,24614,
+ 24591,24634,24666,24641,24682,24695,24671,24650,24646,24653,24675,24643,
+ 24676,24642,24684,24683,24665,24705,24717,24807,24707,24730,},
+{24708,24731,24726,24727,24722,24743,24715,24801,24760,24800,24787,24756,
+ 24560,24765,24774,24757,24792,24909,24853,24838,24822,24823,24832,24820,
+ 24826,24835,24865,24827,24817,24845,24846,24903,24894,24872,24871,24906,
+ 24895,24892,24876,24884,24893,24898,24900,24947,24951,24920,24921,24922,
+ 24939,24948,24943,24933,24945,24927,24925,24915,24949,24985,24982,24967,
+ 25004,24980,24986,24970,24977,25003,25006,25036,25034,25033,25079,25032,
+ 25027,25030,25018,25035,32633,25037,25062,25059,25078,25082,25076,25087,
+ 25085,25084,25086,25088,25096,25097,25101,25100,25108,25115,},
+{25118,25121,25130,25134,25136,25138,25139,25153,25166,25182,25187,25179,
+ 25184,25192,25212,25218,25225,25214,25234,25235,25238,25300,25219,25236,
+ 25303,25297,25275,25295,25343,25286,25812,25288,25308,25292,25290,25282,
+ 25287,25243,25289,25356,25326,25329,25383,25346,25352,25327,25333,25424,
+ 25406,25421,25628,25423,25494,25486,25472,25515,25462,25507,25487,25481,
+ 25503,25525,25451,25449,25534,25577,25536,25542,25571,25545,25554,25590,
+ 25540,25622,25652,25606,25619,25638,25654,25885,25623,25640,25615,25703,
+ 25711,25718,25678,25898,25749,25747,25765,25769,25736,25788,},
+{25818,25810,25797,25799,25787,25816,25794,25841,25831,33289,25824,25825,
+ 25260,25827,25839,25900,25846,25844,25842,25850,25856,25853,25880,25884,
+ 25861,25892,25891,25899,25908,25909,25911,25910,25912,30027,25928,25942,
+ 25941,25933,25944,25950,25949,25970,25976,25986,25987,35722,26011,26015,
+ 26027,26039,26051,26054,26049,26052,26060,26066,26075,26073,26080,26081,
+ 26097,26482,26122,26115,26107,26483,26165,26166,26164,26140,26191,26180,
+ 26185,26177,26206,26205,26212,26215,26216,26207,26210,26224,26243,26248,
+ 26254,26249,26244,26264,26269,26305,26297,26313,26302,26300,},
+{26308,26296,26326,26330,26336,26175,26342,26345,26352,26357,26359,26383,
+ 26390,26398,26406,26407,38712,26414,26431,26422,26433,26424,26423,26438,
+ 26462,26464,26457,26467,26468,26505,26480,26537,26492,26474,26508,26507,
+ 26534,26529,26501,26551,26607,26548,26604,26547,26601,26552,26596,26590,
+ 26589,26594,26606,26553,26574,26566,26599,27292,26654,26694,26665,26688,
+ 26701,26674,26702,26803,26667,26713,26723,26743,26751,26783,26767,26797,
+ 26772,26781,26779,26755,27310,26809,26740,26805,26784,26810,26895,26765,
+ 26750,26881,26826,26888,26840,26914,26918,26849,26892,26829,},
+{26836,26855,26837,26934,26898,26884,26839,26851,26917,26873,26848,26863,
+ 26920,26922,26906,26915,26913,26822,27001,26999,26972,27000,26987,26964,
+ 27006,26990,26937,26996,26941,26969,26928,26977,26974,26973,27009,26986,
+ 27058,27054,27088,27071,27073,27091,27070,27086,23528,27082,27101,27067,
+ 27075,27047,27182,27025,27040,27036,27029,27060,27102,27112,27138,27163,
+ 27135,27402,27129,27122,27111,27141,27057,27166,27117,27156,27115,27146,
+ 27154,27329,27171,27155,27204,27148,27250,27190,27256,27207,27234,27225,
+ 27238,27208,27192,27170,27280,27277,27296,27268,27298,27299,},
+{27287,34327,27323,27331,27330,27320,27315,27308,27358,27345,27359,27306,
+ 27354,27370,27387,27397,34326,27386,27410,27414,39729,27423,27448,27447,
+ 30428,27449,39150,27463,27459,27465,27472,27481,27476,27483,27487,27489,
+ 27512,27513,27519,27520,27524,27523,27533,27544,27541,27550,27556,27562,
+ 27563,27567,27570,27569,27571,27575,27580,27590,27595,27603,27615,27628,
+ 27627,27635,27631,40638,27656,27667,27668,27675,27684,27683,27742,27733,
+ 27746,27754,27778,27789,27802,27777,27803,27774,27752,27763,27794,27792,
+ 27844,27889,27859,27837,27863,27845,27869,27822,27825,27838,},
+{27834,27867,27887,27865,27882,27935,34893,27958,27947,27965,27960,27929,
+ 27957,27955,27922,27916,28003,28051,28004,27994,28025,27993,28046,28053,
+ 28644,28037,28153,28181,28170,28085,28103,28134,28088,28102,28140,28126,
+ 28108,28136,28114,28101,28154,28121,28132,28117,28138,28142,28205,28270,
+ 28206,28185,28274,28255,28222,28195,28267,28203,28278,28237,28191,28227,
+ 28218,28238,28196,28415,28189,28216,28290,28330,28312,28361,28343,28371,
+ 28349,28335,28356,28338,28372,28373,28303,28325,28354,28319,28481,28433,
+ 28748,28396,28408,28414,28479,28402,28465,28399,28466,28364,},
+{28478,28435,28407,28550,28538,28536,28545,28544,28527,28507,28659,28525,
+ 28546,28540,28504,28558,28561,28610,28518,28595,28579,28577,28580,28601,
+ 28614,28586,28639,28629,28652,28628,28632,28657,28654,28635,28681,28683,
+ 28666,28689,28673,28687,28670,28699,28698,28532,28701,28696,28703,28720,
+ 28734,28722,28753,28771,28825,28818,28847,28913,28844,28856,28851,28846,
+ 28895,28875,28893,28889,28937,28925,28956,28953,29029,29013,29064,29030,
+ 29026,29004,29014,29036,29071,29179,29060,29077,29096,29100,29143,29113,
+ 29118,29138,29129,29140,29134,29152,29164,29159,29173,29180,},
+{29177,29183,29197,29200,29211,29224,29229,29228,29232,29234,29243,29244,
+ 29247,29248,29254,29259,29272,29300,29310,29314,29313,29319,29330,29334,
+ 29346,29351,29369,29362,29379,29382,29380,29390,29394,29410,29408,29409,
+ 29433,29431,20495,29463,29450,29468,29462,29469,29492,29487,29481,29477,
+ 29502,29518,29519,40664,29527,29546,29544,29552,29560,29557,29563,29562,
+ 29640,29619,29646,29627,29632,29669,29678,29662,29858,29701,29807,29733,
+ 29688,29746,29754,29781,29759,29791,29785,29761,29788,29801,29808,29795,
+ 29802,29814,29822,29835,29854,29863,29898,29903,29908,29681,},
+{29920,29923,29927,29929,29934,29938,29936,29937,29944,29943,29956,29955,
+ 29957,29964,29966,29965,29973,29971,29982,29990,29996,30012,30020,30029,
+ 30026,30025,30043,30022,30042,30057,30052,30055,30059,30061,30072,30070,
+ 30086,30087,30068,30090,30089,30082,30100,30106,30109,30117,30115,30146,
+ 30131,30147,30133,30141,30136,30140,30129,30157,30154,30162,30169,30179,
+ 30174,30206,30207,30204,30209,30192,30202,30194,30195,30219,30221,30217,
+ 30239,30247,30240,30241,30242,30244,30260,30256,30267,30279,30280,30278,
+ 30300,30296,30305,30306,30312,30313,30314,30311,30316,30320,},
+{30322,30326,30328,30332,30336,30339,30344,30347,30350,30358,30355,30361,
+ 30362,30384,30388,30392,30393,30394,30402,30413,30422,30418,30430,30433,
+ 30437,30439,30442,34351,30459,30472,30471,30468,30505,30500,30494,30501,
+ 30502,30491,30519,30520,30535,30554,30568,30571,30555,30565,30591,30590,
+ 30585,30606,30603,30609,30624,30622,30640,30646,30649,30655,30652,30653,
+ 30651,30663,30669,30679,30682,30684,30691,30702,30716,30732,30738,31014,
+ 30752,31018,30789,30862,30836,30854,30844,30874,30860,30883,30901,30890,
+ 30895,30929,30918,30923,30932,30910,30908,30917,30922,30956,},
+{30951,30938,30973,30964,30983,30994,30993,31001,31020,31019,31040,31072,
+ 31063,31071,31066,31061,31059,31098,31103,31114,31133,31143,40779,31146,
+ 31150,31155,31161,31162,31177,31189,31207,31212,31201,31203,31240,31245,
+ 31256,31257,31264,31263,31104,31281,31291,31294,31287,31299,31319,31305,
+ 31329,31330,31337,40861,31344,31353,31357,31368,31383,31381,31384,31382,
+ 31401,31432,31408,31414,31429,31428,31423,36995,31431,31434,31437,31439,
+ 31445,31443,31449,31450,31453,31457,31458,31462,31469,31472,31490,31503,
+ 31498,31494,31539,31512,31513,31518,31541,31528,31542,31568,},
+{31610,31492,31565,31499,31564,31557,31605,31589,31604,31591,31600,31601,
+ 31596,31598,31645,31640,31647,31629,31644,31642,31627,31634,31631,31581,
+ 31641,31691,31681,31692,31695,31668,31686,31709,31721,31761,31764,31718,
+ 31717,31840,31744,31751,31763,31731,31735,31767,31757,31734,31779,31783,
+ 31786,31775,31799,31787,31805,31820,31811,31828,31823,31808,31824,31832,
+ 31839,31844,31830,31845,31852,31861,31875,31888,31908,31917,31906,31915,
+ 31905,31912,31923,31922,31921,31918,31929,31933,31936,31941,31938,31960,
+ 31954,31964,31970,39739,31983,31986,31988,31990,31994,32006,},
+{32002,32028,32021,32010,32069,32075,32046,32050,32063,32053,32070,32115,
+ 32086,32078,32114,32104,32110,32079,32099,32147,32137,32091,32143,32125,
+ 32155,32186,32174,32163,32181,32199,32189,32171,32317,32162,32175,32220,
+ 32184,32159,32176,32216,32221,32228,32222,32251,32242,32225,32261,32266,
+ 32291,32289,32274,32305,32287,32265,32267,32290,32326,32358,32315,32309,
+ 32313,32323,32311,32306,32314,32359,32349,32342,32350,32345,32346,32377,
+ 32362,32361,32380,32379,32387,32213,32381,36782,32383,32392,32393,32396,
+ 32402,32400,32403,32404,32406,32398,32411,32412,32568,32570,},
+{32581,32588,32589,32590,32592,32593,32597,32596,32600,32607,32608,32616,
+ 32617,32615,32632,32642,32646,32643,32648,32647,32652,32660,32670,32669,
+ 32666,32675,32687,32690,32697,32686,32694,32696,35697,32709,32710,32714,
+ 32725,32724,32737,32742,32745,32755,32761,39132,32774,32772,32779,32786,
+ 32792,32793,32796,32801,32808,32831,32827,32842,32838,32850,32856,32858,
+ 32863,32866,32872,32883,32882,32880,32886,32889,32893,32895,32900,32902,
+ 32901,32923,32915,32922,32941,20880,32940,32987,32997,32985,32989,32964,
+ 32986,32982,33033,33007,33009,33051,33065,33059,33071,33099,},
+{38539,33094,33086,33107,33105,33020,33137,33134,33125,33126,33140,33155,
+ 33160,33162,33152,33154,33184,33173,33188,33187,33119,33171,33193,33200,
+ 33205,33214,33208,33213,33216,33218,33210,33225,33229,33233,33241,33240,
+ 33224,33242,33247,33248,33255,33274,33275,33278,33281,33282,33285,33287,
+ 33290,33293,33296,33302,33321,33323,33336,33331,33344,33369,33368,33373,
+ 33370,33375,33380,33378,33384,33386,33387,33326,33393,33399,33400,33406,
+ 33421,33426,33451,33439,33467,33452,33505,33507,33503,33490,33524,33523,
+ 33530,33683,33539,33531,33529,33502,33542,33500,33545,33497,},
+{33589,33588,33558,33586,33585,33600,33593,33616,33605,33583,33579,33559,
+ 33560,33669,33690,33706,33695,33698,33686,33571,33678,33671,33674,33660,
+ 33717,33651,33653,33696,33673,33704,33780,33811,33771,33742,33789,33795,
+ 33752,33803,33729,33783,33799,33760,33778,33805,33826,33824,33725,33848,
+ 34054,33787,33901,33834,33852,34138,33924,33911,33899,33965,33902,33922,
+ 33897,33862,33836,33903,33913,33845,33994,33890,33977,33983,33951,34009,
+ 33997,33979,34010,34000,33985,33990,34006,33953,34081,34047,34036,34071,
+ 34072,34092,34079,34069,34068,34044,34112,34147,34136,34120,},
+{34113,34306,34123,34133,34176,34212,34184,34193,34186,34216,34157,34196,
+ 34203,34282,34183,34204,34167,34174,34192,34249,34234,34255,34233,34256,
+ 34261,34269,34277,34268,34297,34314,34323,34315,34302,34298,34310,34338,
+ 34330,34352,34367,34381,20053,34388,34399,34407,34417,34451,34467,34473,
+ 34474,34443,34444,34486,34479,34500,34502,34480,34505,34851,34475,34516,
+ 34526,34537,34540,34527,34523,34543,34578,34566,34568,34560,34563,34555,
+ 34577,34569,34573,34553,34570,34612,34623,34615,34619,34597,34601,34586,
+ 34656,34655,34680,34636,34638,34676,34647,34664,34670,34649,},
+{34643,34659,34666,34821,34722,34719,34690,34735,34763,34749,34752,34768,
+ 38614,34731,34756,34739,34759,34758,34747,34799,34802,34784,34831,34829,
+ 34814,34806,34807,34830,34770,34833,34838,34837,34850,34849,34865,34870,
+ 34873,34855,34875,34884,34882,34898,34905,34910,34914,34923,34945,34942,
+ 34974,34933,34941,34997,34930,34946,34967,34962,34990,34969,34978,34957,
+ 34980,34992,35007,34993,35011,35012,35028,35032,35033,35037,35065,35074,
+ 35068,35060,35048,35058,35076,35084,35082,35091,35139,35102,35109,35114,
+ 35115,35137,35140,35131,35126,35128,35148,35101,35168,35166,},
+{35174,35172,35181,35178,35183,35188,35191,35198,35203,35208,35210,35219,
+ 35224,35233,35241,35238,35244,35247,35250,35258,35261,35263,35264,35290,
+ 35292,35293,35303,35316,35320,35331,35350,35344,35340,35355,35357,35365,
+ 35382,35393,35419,35410,35398,35400,35452,35437,35436,35426,35461,35458,
+ 35460,35496,35489,35473,35493,35494,35482,35491,35524,35533,35522,35546,
+ 35563,35571,35559,35556,35569,35604,35552,35554,35575,35550,35547,35596,
+ 35591,35610,35553,35606,35600,35607,35616,35635,38827,35622,35627,35646,
+ 35624,35649,35660,35663,35662,35657,35670,35675,35674,35691,},
+{35679,35692,35695,35700,35709,35712,35724,35726,35730,35731,35734,35737,
+ 35738,35898,35905,35903,35912,35916,35918,35920,35925,35938,35948,35960,
+ 35962,35970,35977,35973,35978,35981,35982,35988,35964,35992,25117,36013,
+ 36010,36029,36018,36019,36014,36022,36040,36033,36068,36067,36058,36093,
+ 36090,36091,36100,36101,36106,36103,36111,36109,36112,40782,36115,36045,
+ 36116,36118,36199,36205,36209,36211,36225,36249,36290,36286,36282,36303,
+ 36314,36310,36300,36315,36299,36330,36331,36319,36323,36348,36360,36361,
+ 36351,36381,36382,36368,36383,36418,36405,36400,36404,36426,},
+{36423,36425,36428,36432,36424,36441,36452,36448,36394,36451,36437,36470,
+ 36466,36476,36481,36487,36485,36484,36491,36490,36499,36497,36500,36505,
+ 36522,36513,36524,36528,36550,36529,36542,36549,36552,36555,36571,36579,
+ 36604,36603,36587,36606,36618,36613,36629,36626,36633,36627,36636,36639,
+ 36635,36620,36646,36659,36667,36665,36677,36674,36670,36684,36681,36678,
+ 36686,36695,36700,36706,36707,36708,36764,36767,36771,36781,36783,36791,
+ 36826,36837,36834,36842,36847,36999,36852,36869,36857,36858,36881,36885,
+ 36897,36877,36894,36886,36875,36903,36918,36917,36921,36856,},
+{36943,36944,36945,36946,36878,36937,36926,36950,36952,36958,36968,36975,
+ 36982,38568,36978,36994,36989,36993,36992,37002,37001,37007,37032,37039,
+ 37041,37045,37090,37092,25160,37083,37122,37138,37145,37170,37168,37194,
+ 37206,37208,37219,37221,37225,37235,37234,37259,37257,37250,37282,37291,
+ 37295,37290,37301,37300,37306,37312,37313,37321,37323,37328,37334,37343,
+ 37345,37339,37372,37365,37366,37406,37375,37396,37420,37397,37393,37470,
+ 37463,37445,37449,37476,37448,37525,37439,37451,37456,37532,37526,37523,
+ 37531,37466,37583,37561,37559,37609,37647,37626,37700,37678,},
+{37657,37666,37658,37667,37690,37685,37691,37724,37728,37756,37742,37718,
+ 37808,37804,37805,37780,37817,37846,37847,37864,37861,37848,37827,37853,
+ 37840,37832,37860,37914,37908,37907,37891,37895,37904,37942,37931,37941,
+ 37921,37946,37953,37970,37956,37979,37984,37986,37982,37994,37417,38000,
+ 38005,38007,38013,37978,38012,38014,38017,38015,38274,38279,38282,38292,
+ 38294,38296,38297,38304,38312,38311,38317,38332,38331,38329,38334,38346,
+ 28662,38339,38349,38348,38357,38356,38358,38364,38369,38373,38370,38433,
+ 38440,38446,38447,38466,38476,38479,38475,38519,38492,38494,},
+{38493,38495,38502,38514,38508,38541,38552,38549,38551,38570,38567,38577,
+ 38578,38576,38580,38582,38584,38585,38606,38603,38601,38605,35149,38620,
+ 38669,38613,38649,38660,38662,38664,38675,38670,38673,38671,38678,38681,
+ 38692,38698,38704,38713,38717,38718,38724,38726,38728,38722,38729,38748,
+ 38752,38756,38758,38760,21202,38763,38769,38777,38789,38780,38785,38778,
+ 38790,38795,38799,38800,38812,38824,38822,38819,38835,38836,38851,38854,
+ 38856,38859,38876,38893,40783,38898,31455,38902,38901,38927,38924,38968,
+ 38948,38945,38967,38973,38982,38991,38987,39019,39023,39024,},
+{39025,39028,39027,39082,39087,39089,39094,39108,39107,39110,39145,39147,
+ 39171,39177,39186,39188,39192,39201,39197,39198,39204,39200,39212,39214,
+ 39229,39230,39234,39241,39237,39248,39243,39249,39250,39244,39253,39319,
+ 39320,39333,39341,39342,39356,39391,39387,39389,39384,39377,39405,39406,
+ 39409,39410,39419,39416,39425,39439,39429,39394,39449,39467,39479,39493,
+ 39490,39488,39491,39486,39509,39501,39515,39511,39519,39522,39525,39524,
+ 39529,39531,39530,39597,39600,39612,39616,39631,39633,39635,39636,39646,
+ 39647,39650,39651,39654,39663,39659,39662,39668,39665,39671,},
+{39675,39686,39704,39706,39711,39714,39715,39717,39719,39720,39721,39722,
+ 39726,39727,39730,39748,39747,39759,39757,39758,39761,39768,39796,39827,
+ 39811,39825,39830,39831,39839,39840,39848,39860,39872,39882,39865,39878,
+ 39887,39889,39890,39907,39906,39908,39892,39905,39994,39922,39921,39920,
+ 39957,39956,39945,39955,39948,39942,39944,39954,39946,39940,39982,39963,
+ 39973,39972,39969,39984,40007,39986,40006,39998,40026,40032,40039,40054,
+ 40056,40167,40172,40176,40201,40200,40171,40195,40198,40234,40230,40367,
+ 40227,40223,40260,40213,40210,40257,40255,40254,40262,40264,},
+{40285,40286,40292,40273,40272,40281,40306,40329,40327,40363,40303,40314,
+ 40346,40356,40361,40370,40388,40385,40379,40376,40378,40390,40399,40386,
+ 40409,40403,40440,40422,40429,40431,40445,40474,40475,40478,40565,40569,
+ 40573,40577,40584,40587,40588,40594,40597,40593,40605,40613,40617,40632,
+ 40618,40621,38753,40652,40654,40655,40656,40660,40668,40670,40669,40672,
+ 40677,40680,40687,40692,40694,40695,40697,40699,40700,40701,40711,40712,
+ 30391,40725,40737,40748,40766,40778,40786,40788,40803,40799,40800,40801,
+ 40806,40807,40812,40810,40823,40818,40822,40853,40860,40864,},
+{22575,27079,36953,29796,20956,29081,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+};
+
+
+// ------------------------------------------------------------
+unsigned short JISConverter::sjisToUnicode(unsigned short sjis)
+{
+       unsigned short u;
+       unsigned int c = sjis>>8;
+       unsigned int c1 = sjis&0xff;
+  
+       c = c + c - ((c <= 0x9f) ? SJ0162 : SJ6394);
+       if(c1 < 0x9f) 
+       {
+               c1 = c1 - ((c1 > 0x7f) ? 0x20 : 0x1f); 
+       }
+       else 
+       {
+           c1 = c1 - 0x7e; c++; 
+       }
+       c -= 33; 
+       c1 -= 33;
+       if(c < 0 || c1 < 0 || c > 93 || c1 > 93)
+               u = 0x3013; 
+       else
+       {
+               u = uniTable[c][c1]; 
+               if(!u) 
+                       u = 0x3013; 
+       }
+
+       return u;
+}
+// ------------------------------------------------------------
+unsigned short JISConverter::eucToUnicode(unsigned short euc)
+{      
+       unsigned short u;
+       unsigned int c = euc>>8;
+       unsigned int c1 = euc&0xff; 
+
+       c &= 0x7f; 
+       c -= 33; 
+       c1 &= 0x7f; 
+       c1 -= 33;
+    if(c < 0 || c1 < 0 || c > 93 || c1 > 93)
+               u = 0x3013; 
+    else 
+       {
+        u = uniTable[c][c1]; 
+               if(!u) 
+                       u = 0x3013; 
+       }
+       return u;
+}
diff --git a/PeerCast.root/PeerCast/core/common/jis.h b/PeerCast.root/PeerCast/core/common/jis.h
new file mode 100644 (file)
index 0000000..da4df03
--- /dev/null
@@ -0,0 +1,35 @@
+// ------------------------------------------------
+// File : jis.h
+// Date: 1-april-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _JIS_H
+#define _JIS_H
+
+// ----------------------------------
+class JISConverter
+{
+public:
+
+       static unsigned short sjisToUnicode(unsigned short);
+       static unsigned short eucToUnicode(unsigned short);
+};
+
+
+
+#endif
+
+
diff --git a/PeerCast.root/PeerCast/core/common/mms.cpp b/PeerCast.root/PeerCast/core/common/mms.cpp
new file mode 100644 (file)
index 0000000..2ddafbc
--- /dev/null
@@ -0,0 +1,194 @@
+// ------------------------------------------------
+// File : mms.cpp
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "channel.h"
+#include "mms.h"
+#include "asf.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ------------------------------------------
+ASFInfo parseASFHeader(Stream &in);
+
+
+// ------------------------------------------
+void MMSStream::readEnd(Stream &,Channel *)
+{
+}
+
+// ------------------------------------------
+void MMSStream::readHeader(Stream &,Channel *)
+{
+}
+// ------------------------------------------
+int MMSStream::readPacket(Stream &in,Channel *ch)
+{
+       {
+               ASFChunk chunk;
+
+               chunk.read(in);
+
+               switch (chunk.type)
+               {
+                       case 0x4824:            // asf header
+                       {
+                               MemoryStream mem(ch->headPack.data,sizeof(ch->headPack.data));
+
+                               chunk.write(mem);
+
+
+
+
+                               MemoryStream asfm(chunk.data,chunk.dataLen);
+                               ASFObject asfHead;
+                               asfHead.readHead(asfm);
+
+                               ASFInfo asf = parseASFHeader(asfm);
+                               LOG_DEBUG("ASF Info: pnum=%d, psize=%d, br=%d",asf.numPackets,asf.packetSize,asf.bitrate);
+                               for(int i=0; i<ASFInfo::MAX_STREAMS; i++)
+                               {
+                                       ASFStream *s = &asf.streams[i];
+                                       if (s->id)
+                                               LOG_DEBUG("ASF Stream %d : %s, br=%d",s->id,s->getTypeName(),s->bitrate);
+                               }
+
+                               ch->info.bitrate = asf.bitrate/1000;
+
+                               ch->headPack.type = ChanPacket::T_HEAD;
+                               ch->headPack.len = mem.pos;
+                               ch->headPack.pos = ch->streamPos;
+                               ch->newPacket(ch->headPack);
+
+                               ch->streamPos += ch->headPack.len;
+
+                               break;
+                       }
+                       case 0x4424:            // asf data
+                       {
+
+                               ChanPacket pack;
+
+                               MemoryStream mem(pack.data,sizeof(pack.data));
+
+                               chunk.write(mem);
+
+                               pack.type = ChanPacket::T_DATA;
+                               pack.len = mem.pos;
+                               pack.pos = ch->streamPos;
+
+                               ch->newPacket(pack);
+                               ch->streamPos += pack.len;
+
+                               break;
+                       }
+                       default:
+                               throw StreamException("Unknown ASF chunk");
+
+               }
+
+       }
+       return 0;
+}
+
+
+// -----------------------------------
+ASFInfo parseASFHeader(Stream &in)
+{
+       ASFInfo asf;
+
+       try
+       {
+               int numHeaders = in.readLong();
+
+               in.readChar();
+               in.readChar();
+
+               LOG_CHANNEL("ASF Headers: %d",numHeaders);
+               for(int i=0; i<numHeaders; i++)
+               {
+
+                       ASFObject obj;
+
+                       unsigned int l = obj.readHead(in);
+                       obj.readData(in,l);
+
+
+                       MemoryStream data(obj.data,obj.lenLo);
+
+
+                       switch (obj.type)
+                       {
+                               case ASFObject::T_FILE_PROP:
+                               {
+                                       data.skip(32);
+
+                                       unsigned int dpLo = data.readLong();
+                                       unsigned int dpHi = data.readLong();
+
+                                       data.skip(24);
+
+                                       data.readLong();
+                                       //data.writeLong(1);    // flags = broadcast, not seekable
+
+                                       int min = data.readLong();
+                                       int max = data.readLong();
+                                       int br = data.readLong();
+
+                                       if (min != max)
+                                               throw StreamException("ASF packetsizes (min/max) must match");
+
+                                       asf.packetSize = max;
+                                       asf.bitrate = br;
+                                       asf.numPackets = dpLo;
+                                       break;
+                               }
+                               case ASFObject::T_STREAM_BITRATE:
+                               {
+                                       int cnt = data.readShort();
+                                       for(int i=0; i<cnt; i++)
+                                       {
+                                               unsigned int id = data.readShort();
+                                               int bitrate = data.readLong();
+                                               if (id < ASFInfo::MAX_STREAMS)
+                                                       asf.streams[id].bitrate = bitrate;
+                                       }
+                                       break;
+                               }
+                               case ASFObject::T_STREAM_PROP:
+                               {
+                                       ASFStream s;
+                                       s.read(data);
+                                       asf.streams[s.id].id = s.id;
+                                       asf.streams[s.id].type = s.type;
+                                       break;
+                               }
+                       }
+
+               }
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("ASF: %s",e.msg);
+       }
+
+       return asf;
+}
+
+
diff --git a/PeerCast.root/PeerCast/core/common/mms.h b/PeerCast.root/PeerCast/core/common/mms.h
new file mode 100644 (file)
index 0000000..11195a7
--- /dev/null
@@ -0,0 +1,37 @@
+// ------------------------------------------------
+// File : mms.h
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _MMS_H
+#define _MMS_H
+
+
+#include "channel.h"
+
+// ----------------------------------------------
+class MMSStream : public ChannelStream
+{
+public:
+
+       virtual void readHeader(Stream &,Channel *);
+       virtual int readPacket(Stream &,Channel *);
+       virtual void readEnd(Stream &,Channel *);
+};
+
+
+#endif 
+
diff --git a/PeerCast.root/PeerCast/core/common/mp3.cpp b/PeerCast.root/PeerCast/core/common/mp3.cpp
new file mode 100644 (file)
index 0000000..4997927
--- /dev/null
@@ -0,0 +1,82 @@
+// ------------------------------------------------
+// File : mp3.cpp
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "channel.h"
+#include "mp3.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+// ------------------------------------------
+void MP3Stream::readEnd(Stream &,Channel *)
+{
+}
+
+// ------------------------------------------
+void MP3Stream::readHeader(Stream &,Channel *)
+{
+}
+// ------------------------------------------
+int MP3Stream::readPacket(Stream &in,Channel *ch)
+{
+       ChanPacket pack;
+
+       if (ch->icyMetaInterval)
+       {
+
+               int rlen = ch->icyMetaInterval;
+
+               while (rlen)
+               {
+                       int rl = rlen;
+                       if (rl > ChanMgr::MAX_METAINT)
+                               rl = ChanMgr::MAX_METAINT;
+
+                       pack.init(ChanPacket::T_DATA,pack.data,rl,ch->streamPos);
+                       in.read(pack.data,pack.len);
+                       ch->newPacket(pack);
+                       ch->checkReadDelay(pack.len);
+                       ch->streamPos+=pack.len;
+
+                       rlen-=rl;
+               }
+
+               unsigned char len;
+               in.read(&len,1);
+               if (len)
+               {
+                       if (len*16 > 1024) len = 1024/16;
+                       char buf[1024];
+                       in.read(buf,len*16);
+                       ch->processMp3Metadata(buf);
+               }
+
+       }else{
+
+               pack.init(ChanPacket::T_DATA,pack.data,ChanMgr::MAX_METAINT,ch->streamPos);
+               in.read(pack.data,pack.len);
+               ch->newPacket(pack);
+               ch->checkReadDelay(pack.len);
+
+               ch->streamPos += pack.len;
+       }
+       return 0;
+}
diff --git a/PeerCast.root/PeerCast/core/common/mp3.h b/PeerCast.root/PeerCast/core/common/mp3.h
new file mode 100644 (file)
index 0000000..2297d10
--- /dev/null
@@ -0,0 +1,35 @@
+// ------------------------------------------------
+// File : mp3.h
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _MP3_H
+#define _MP3_H
+
+
+#include "channel.h"
+
+// ----------------------------------------------
+class MP3Stream : public ChannelStream
+{
+public:
+       virtual void readHeader(Stream &,Channel *);
+       virtual int      readPacket(Stream &,Channel *);
+       virtual void readEnd(Stream &,Channel *);
+};
+
+
+#endif 
diff --git a/PeerCast.root/PeerCast/core/common/nsv.cpp b/PeerCast.root/PeerCast/core/common/nsv.cpp
new file mode 100644 (file)
index 0000000..55cdb98
--- /dev/null
@@ -0,0 +1,80 @@
+// ------------------------------------------------
+// File : nsv.cpp
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "nsv.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ------------------------------------------
+void NSVStream::readEnd(Stream &,Channel *)
+{
+}
+
+// ------------------------------------------
+void NSVStream::readHeader(Stream &,Channel *)
+{
+}
+// ------------------------------------------
+int NSVStream::readPacket(Stream &in,Channel *ch)
+{
+       ChanPacket pack;
+
+       if (ch->icyMetaInterval)
+       {
+
+               int rlen = ch->icyMetaInterval;
+
+               while (rlen)
+               {
+                       int rl = rlen;
+                       if (rl > ChanMgr::MAX_METAINT)
+                               rl = ChanMgr::MAX_METAINT;
+
+                       pack.init(ChanPacket::T_DATA,pack.data,rl,ch->streamPos);
+                       in.read(pack.data,pack.len);
+                       ch->newPacket(pack);
+                       ch->checkReadDelay(pack.len);
+                       ch->streamPos+=pack.len;
+
+                       rlen-=rl;
+               }
+
+               unsigned char len;
+               in.read(&len,1);
+               if (len)
+               {
+                       if (len*16 > 1024) len = 1024/16;
+                       char buf[1024];
+                       in.read(buf,len*16);
+                       ch->processMp3Metadata(buf);
+               }
+
+       }else{
+
+               pack.init(ChanPacket::T_DATA,pack.data,ChanMgr::MAX_METAINT,ch->streamPos);
+               in.read(pack.data,pack.len);
+               ch->newPacket(pack);
+               ch->checkReadDelay(pack.len);
+
+               ch->streamPos += pack.len;
+       }
+       return 0;
+}
diff --git a/PeerCast.root/PeerCast/core/common/nsv.h b/PeerCast.root/PeerCast/core/common/nsv.h
new file mode 100644 (file)
index 0000000..cca0106
--- /dev/null
@@ -0,0 +1,35 @@
+// ------------------------------------------------
+// File : nsv.h
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _NSV_H
+#define _NSV_H
+
+
+#include "channel.h"
+
+// ----------------------------------------------
+class NSVStream : public ChannelStream
+{
+public:
+       virtual void readHeader(Stream &,Channel *);
+       virtual int readPacket(Stream &,Channel *);
+       virtual void readEnd(Stream &,Channel *);
+};
+
+
+#endif 
diff --git a/PeerCast.root/PeerCast/core/common/ogg.cpp b/PeerCast.root/PeerCast/core/common/ogg.cpp
new file mode 100644 (file)
index 0000000..ed38bc7
--- /dev/null
@@ -0,0 +1,494 @@
+// ------------------------------------------------
+// File : mp3.cpp
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "channel.h"
+#include "ogg.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+static int test=0;
+// ------------------------------------------
+void OGGStream::readHeader(Stream &,Channel *)
+{
+       test = 0;
+}
+
+// ------------------------------------------
+void OGGStream::readEnd(Stream &,Channel *)
+{
+}
+
+// ------------------------------------------
+int OGGStream::readPacket(Stream &in,Channel *ch)
+{
+       OggPage ogg;
+       ChanPacket pack;
+
+       ogg.read(in);
+
+       if (ogg.isBOS())
+       {
+               if (!vorbis.needHeader() && !theora.needHeader())
+               {
+                       ch->headPack.len = 0;
+               }
+
+               if (ogg.detectVorbis())
+                       vorbis.bos(ogg.getSerialNo());
+               if (ogg.detectTheora())
+                       theora.bos(ogg.getSerialNo());
+       }
+
+       if (ogg.isEOS())
+       {
+
+               if (ogg.getSerialNo() == vorbis.serialNo)
+               {
+                       LOG_CHANNEL("Vorbis stream: EOS");
+                       vorbis.eos();
+               }
+               if (ogg.getSerialNo() == theora.serialNo)
+               {
+                       LOG_CHANNEL("Theora stream: EOS");
+                       theora.eos();
+               }
+       }
+
+       if (vorbis.needHeader() || theora.needHeader())
+       {
+
+               if (ogg.getSerialNo() == vorbis.serialNo)
+                       vorbis.readHeader(ch,ogg);
+               else if (ogg.getSerialNo() == theora.serialNo)
+                       theora.readHeader(ch,ogg);
+               else
+                       throw StreamException("Bad OGG serial no.");
+
+
+               if (!vorbis.needHeader() && !theora.needHeader())
+               {
+
+                       ch->info.bitrate = 0;
+
+                       if (vorbis.isActive())
+                               ch->info.bitrate += vorbis.bitrate;
+
+                       if (theora.isActive())
+                       {
+                               ch->info.bitrate += theora.bitrate;
+                               ch->info.contentType = ChanInfo::T_OGM;
+                       }
+
+                       
+                       ch->headPack.type = ChanPacket::T_HEAD;
+                       ch->headPack.pos = ch->streamPos;
+
+                       ch->startTime = sys->getDTime();                
+
+                       ch->streamPos += ch->headPack.len;
+
+                       ch->newPacket(ch->headPack);
+                       LOG_CHANNEL("Got %d bytes of headers",ch->headPack.len);
+               }
+
+       }else
+       {
+
+
+               pack.init(ChanPacket::T_DATA,ogg.data,ogg.headLen+ogg.bodyLen,ch->streamPos);
+               ch->newPacket(pack);
+
+               ch->streamPos+=pack.len;
+
+               if (theora.isActive())
+               {
+                       if (ogg.getSerialNo() == theora.serialNo)
+                       {
+                               ch->sleepUntil(theora.getTime(ogg));
+                       }
+               }else if (vorbis.isActive())
+               {
+                       if (ogg.getSerialNo() == vorbis.serialNo)
+                       {
+                               ch->sleepUntil(vorbis.getTime(ogg));
+                       }
+               }
+
+       }
+       return 0;
+}
+
+// -----------------------------------
+void OggSubStream::readHeader(Channel *ch,OggPage &ogg)
+{
+       if ((pack.bodyLen + ogg.bodyLen) >= OggPacket::MAX_BODYLEN)
+               throw StreamException("OGG packet too big");
+
+       if (ch->headPack.len+(ogg.bodyLen+ogg.headLen) >= ChanMeta::MAX_DATALEN)
+               throw StreamException("OGG packet too big for headMeta");
+
+// copy complete packet into head packet
+       memcpy(&ch->headPack.data[ch->headPack.len],ogg.data,ogg.headLen+ogg.bodyLen);
+       ch->headPack.len += ogg.headLen+ogg.bodyLen;
+
+       // add body to packet
+       memcpy(&pack.body[pack.bodyLen],&ogg.data[ogg.headLen],ogg.bodyLen);
+       pack.bodyLen += ogg.bodyLen;
+
+       pack.addLacing(ogg);
+
+       if (pack.numPackets >= maxHeaders)
+               procHeaders(ch);
+
+}
+// -----------------------------------
+void OggVorbisSubStream::procHeaders(Channel *ch)
+{
+       unsigned int packPtr=0;
+
+       for(int i=0; i<pack.numPackets; i++)
+       {
+               MemoryStream vin(&pack.body[packPtr],pack.packetSizes[i]);
+
+               packPtr += pack.packetSizes[i];
+
+               char id[8];
+
+               vin.read(id,7);
+               id[7]=0;
+
+               switch (id[0])
+               {
+                       case 1: // ident
+                               LOG_CHANNEL("OGG Vorbis Header: Ident (%d bytes)",vin.len);
+                               readIdent(vin,ch->info);
+                               break;
+                       case 3: // comment
+                               {
+                                       LOG_CHANNEL("OGG Vorbis Header: Comment (%d bytes)",vin.len);
+                                       ChanInfo newInfo = ch->info;
+                                       readComment(vin,newInfo);
+                                       ch->updateInfo(newInfo);
+                               }
+                               break;
+                       case 5: // setup
+                               LOG_CHANNEL("OGG Vorbis Header: Setup (%d bytes)",vin.len);
+                               //readSetup(vin);
+                               break;
+                       default:
+                               throw StreamException("Unknown Vorbis packet header type");
+                               break;
+               }
+       }
+
+}
+// -----------------------------------
+double OggTheoraSubStream::getTime(OggPage &ogg)
+{
+    int64_t iframe=ogg.granPos>>granposShift;
+    int64_t pframe=ogg.granPos-(iframe<<granposShift);
+
+    return (iframe+pframe)*frameTime;
+}
+// -----------------------------------
+void OggTheoraSubStream::readInfo(Stream &in, ChanInfo &info)
+{
+       int verMaj = in.readBits(8);
+       int verMin = in.readBits(8);
+       int verSub = in.readBits(8);
+
+       int encWidth = in.readBits(16) << 4;
+       int encHeight = in.readBits(16) << 4;
+
+       in.readBits(24+24+8+8);
+
+       int fpsNum = in.readBits(32);
+       int fpsDen = in.readBits(32);
+
+       float fps = (float)fpsNum/(float)fpsDen;
+       frameTime = (double)fpsDen/(double)fpsNum;
+
+       in.readBits(24+24+8);
+
+       bitrate = in.readBits(24) / 1000;
+       int quality = in.readBits(6);
+
+       granposShift = in.readBits(5);
+
+       LOG_CHANNEL("OGG Theora Info: %dx%dx%.1ffps %dkbps %dQ %dG",encWidth,encHeight,fps,bitrate,quality,granposShift);
+
+
+}
+// -----------------------------------
+void OggTheoraSubStream::procHeaders(Channel *ch)
+{
+       unsigned int packPtr=0;
+
+       for(int i=0; i<pack.numPackets; i++)
+       {
+               MemoryStream vin(&pack.body[packPtr],pack.packetSizes[i]);
+
+               packPtr += pack.packetSizes[i];
+
+               unsigned char id[8];
+
+               vin.read(id,7);
+               id[7]=0;
+
+               switch (id[0] & 0xff)
+               {
+                       case 128:       // info
+                               LOG_CHANNEL("OGG Theora Header: Info (%d bytes)",vin.len);
+                               readInfo(vin,ch->info);
+                               break;
+                       default:
+                               LOG_CHANNEL("OGG Theora Header: Unknown %d (%d bytes)",id[0] & 0xff,vin.len);
+                               break;
+               }
+
+
+
+       }
+
+}
+
+// -----------------------------------
+double OggVorbisSubStream::getTime(OggPage &ogg)
+{
+       return (double)ogg.granPos / (double)samplerate;
+
+}
+
+// -----------------------------------
+void OggVorbisSubStream::readIdent(Stream &in, ChanInfo &info)
+{
+       int ver = in.readLong();
+       int chans = in.readChar();
+       samplerate = in.readLong();
+       int brMax = in.readLong();
+       int brNom = in.readLong();
+       int brLow = in.readLong();
+       
+
+       in.readChar();  // skip blocksize 0+1
+
+       LOG_CHANNEL("OGG Vorbis Ident: ver=%d, chans=%d, rate=%d, brMax=%d, brNom=%d, brLow=%d",
+               ver,chans,samplerate,brMax,brNom,brLow);
+
+
+       bitrate = brNom/1000;
+
+       char frame = in.readChar();             // framing bit
+       if (!frame)
+               throw StreamException("Bad Indent frame");
+
+}
+
+// -----------------------------------
+void OggVorbisSubStream::readSetup(Stream &in)
+{
+       // skip everything in packet
+       int cnt=0;
+       while (!in.eof())
+       {
+               cnt++;
+               in.readChar();
+       }
+
+       LOG_CHANNEL("Read %d bytes of Vorbis Setup",cnt);
+}
+// -----------------------------------
+void OggVorbisSubStream::readComment(Stream &in, ChanInfo &info)
+{
+       int vLen = in.readLong();       // vendor len
+
+       in.skip(vLen);
+
+       char argBuf[8192];
+
+       info.track.clear();
+
+       int cLen = in.readLong();       // comment len
+       for(int i=0; i<cLen; i++)
+       {
+               int l = in.readLong();
+               if (l > sizeof(argBuf))
+                       throw StreamException("Comment string too long");
+               in.read(argBuf,l);
+               argBuf[l] = 0;
+               LOG_CHANNEL("OGG Comment: %s",argBuf);
+
+               char *arg;
+               if ((arg=stristr(argBuf,"ARTIST=")))
+               {
+                       info.track.artist.set(arg+7,String::T_ASCII);
+                       info.track.artist.convertTo(String::T_UNICODE);
+
+               }else if ((arg=stristr(argBuf,"TITLE=")))
+               {
+                       info.track.title.set(arg+6,String::T_ASCII);
+                       info.track.title.convertTo(String::T_UNICODE);
+
+               }else if ((arg=stristr(argBuf,"GENRE=")))
+               {
+                       info.track.genre.set(arg+6,String::T_ASCII);
+                       info.track.genre.convertTo(String::T_UNICODE);
+
+               }else if ((arg=stristr(argBuf,"CONTACT=")))
+               {
+                       info.track.contact.set(arg+8,String::T_ASCII);
+                       info.track.contact.convertTo(String::T_UNICODE);
+
+               }else if ((arg=stristr(argBuf,"ALBUM=")))
+               {
+                       info.track.album.set(arg+6,String::T_ASCII);
+                       info.track.album.convertTo(String::T_UNICODE);
+               }
+       }
+
+       char frame = in.readChar();             // framing bit
+       if (!frame)
+               throw StreamException("Bad Comment frame");
+
+//     updateMeta();
+
+}
+
+// -----------------------------------
+bool OggPage::isBOS()
+{
+       return (data[5] & 0x02) != 0;
+}
+// -----------------------------------
+bool OggPage::isEOS()
+{
+       return (data[5] & 0x04) != 0;
+}
+// -----------------------------------
+bool OggPage::isNewPacket()
+{
+       return (data[5] & 0x01) == 0;
+}
+// -----------------------------------
+bool OggPage::isHeader()
+{
+       return ((*(unsigned int *)&data[6]) || (*(unsigned int *)&data[10])) == 0;
+}
+// -----------------------------------
+unsigned int OggPage::getSerialNo()
+{
+       return *(unsigned int *)&data[14];
+}
+
+// -----------------------------------
+void OggPage::read(Stream &in)
+{
+       // skip until we get OGG capture pattern
+       bool gotOgg=false;
+       while (!gotOgg)
+       {
+               if (in.readChar() == 'O')
+                       if (in.readChar() == 'g')
+                               if (in.readChar() == 'g')
+                                       if (in.readChar() == 'S')
+                                               gotOgg = true;
+               if (!gotOgg)
+                       LOG_CHANNEL("Skipping OGG packet");
+       }
+
+
+
+       memcpy(&data[0],"OggS",4);
+
+       in.read(&data[4],27-4);
+
+       int numSegs = data[26];
+       bodyLen = 0;
+
+       // read segment table
+       in.read(&data[27],numSegs);
+       for(int i=0; i<numSegs; i++)
+               bodyLen += data[27+i];
+
+       if (bodyLen >= MAX_BODYLEN)             
+               throw StreamException("OGG body too big");
+
+       headLen = 27+numSegs;
+
+       if (headLen > MAX_HEADERLEN)
+               throw StreamException("OGG header too big");
+
+       in.read(&data[headLen],bodyLen);
+
+       granPos = *(unsigned int *)&data[10];
+       granPos <<= 32;
+       granPos |= *(unsigned int *)&data[6];
+
+
+       #if 0
+               LOG_DEBUG("OGG Packet - page %d, id = %x - %s %s %s - %d:%d - %d segs, %d bytes",
+                       *(unsigned int *)&data[18],
+                       *(unsigned int *)&data[14],
+                       data[5]&0x1?"cont":"new",
+                       data[5]&0x2?"bos":"",
+                       data[5]&0x4?"eos":"",
+                       (unsigned int)(granPos>>32),
+                       (unsigned int)(granPos&0xffffffff),
+                       numSegs,
+                       headLen+bodyLen);
+
+       #endif
+
+}
+// -----------------------------------
+bool OggPage::detectVorbis()
+{
+       return memcmp(&data[headLen+1],"vorbis",6) == 0;
+}
+// -----------------------------------
+bool OggPage::detectTheora()
+{
+       return memcmp(&data[headLen+1],"theora",6) == 0;
+}
+
+// -----------------------------------
+void   OggPacket::addLacing(OggPage &ogg)
+{
+       
+       int numSegs = ogg.data[26];
+       for(int i=0; i<numSegs; i++)
+       {
+               int seg = ogg.data[27+i];
+
+               packetSizes[numPackets]+=seg;
+
+               if (seg < 255)
+               {
+                       numPackets++;
+                       if (numPackets >= MAX_PACKETS)
+                               throw StreamException("Too many OGG packets");
+                       packetSizes[numPackets]=0;
+               }
+       }
+
+}
diff --git a/PeerCast.root/PeerCast/core/common/ogg.h b/PeerCast.root/PeerCast/core/common/ogg.h
new file mode 100644 (file)
index 0000000..67a228c
--- /dev/null
@@ -0,0 +1,169 @@
+// ------------------------------------------------
+// File : ogg.h
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _OGG_H
+#define _OGG_H
+
+
+#include "channel.h"
+// ----------------------------------------------
+class OggPage;
+
+// ----------------------------------
+class OggPacket
+{
+public:
+       enum 
+       {
+               MAX_BODYLEN = 65536,            // probably too small
+               MAX_PACKETS = 256                       // prolly too small too, but realloc?!?!?!
+       };
+
+       void    addLacing(OggPage &);
+
+       int     bodyLen;
+       unsigned char body[MAX_BODYLEN];
+
+
+       int     numPackets;
+       unsigned int packetSizes[MAX_PACKETS];
+};
+
+// ----------------------------------------------
+class OggSubStream
+{
+public:
+       OggSubStream()
+       :maxHeaders(0),serialNo(0),bitrate(0)
+       {}
+
+       bool needHeader()
+       {
+               return maxHeaders && (pack.numPackets < maxHeaders);
+       }
+
+       void eos()
+       {
+               maxHeaders=0;
+               serialNo=0;
+       }
+
+       void bos(unsigned int ser)
+       {
+               maxHeaders = 3;
+               pack.numPackets=0;
+               pack.packetSizes[0]=0;
+               pack.bodyLen = 0;
+               serialNo = ser;
+               bitrate = 0;
+       }
+
+       bool    isActive() {return serialNo!=0;}
+
+       void readHeader(Channel *,OggPage &);
+
+       virtual void procHeaders(Channel *) = 0;
+
+       int     bitrate;
+
+       OggPacket       pack;
+       int     maxHeaders;
+       unsigned int serialNo;
+};
+// ----------------------------------------------
+class OggVorbisSubStream : public OggSubStream
+{
+public:
+       OggVorbisSubStream()
+       :samplerate(0)
+       {}
+
+       virtual void procHeaders(Channel *);
+
+       void    readIdent(Stream &, ChanInfo &);
+       void    readSetup(Stream &);
+       void    readComment(Stream &, ChanInfo &);
+
+       double  getTime(OggPage &);
+
+       int samplerate;
+
+};
+// ----------------------------------------------
+class OggTheoraSubStream : public OggSubStream
+{
+public:
+       OggTheoraSubStream() : granposShift(0), frameTime(0) {}
+
+       virtual void procHeaders(Channel *);
+
+       void readInfo(Stream &, ChanInfo &);
+
+       double  getTime(OggPage &);
+
+       int granposShift;
+       double frameTime;
+};
+
+// ----------------------------------------------
+class OGGStream : public ChannelStream
+{
+public:
+       OGGStream()
+       {}
+
+
+       virtual void readHeader(Stream &,Channel *);
+       virtual int readPacket(Stream &,Channel *);
+       virtual void readEnd(Stream &,Channel *);
+
+
+       void    readHeaders(Stream &,Channel *, OggPage &);
+
+       OggVorbisSubStream      vorbis;
+       OggTheoraSubStream      theora; 
+};
+
+// ----------------------------------
+class OggPage
+{
+public:
+       enum 
+       {
+               MAX_BODYLEN = 65536,
+               MAX_HEADERLEN = 27+256
+       };
+
+       void    read(Stream &);
+       bool    isBOS();
+       bool    isEOS();
+       bool    isNewPacket();
+       bool    isHeader();
+       unsigned int getSerialNo();
+
+       bool    detectVorbis();
+       bool    detectTheora();
+
+
+       int64_t granPos;
+       int headLen,bodyLen;
+       unsigned char data[MAX_HEADERLEN+MAX_BODYLEN];
+};
+
+
+#endif 
diff --git a/PeerCast.root/PeerCast/core/common/pcp.cpp b/PeerCast.root/PeerCast/core/common/pcp.cpp
new file mode 100644 (file)
index 0000000..37514ed
--- /dev/null
@@ -0,0 +1,886 @@
+// ------------------------------------------------
+// File : pcp.cpp
+// Date: 1-mar-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "atom.h"
+#include "pcp.h"
+#include "peercast.h"
+#include "version2.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ------------------------------------------
+void PCPStream::init(GnuID &rid)
+{
+       remoteID = rid;
+       routeList.clear();
+
+       lastPacketTime = 0;
+       nextRootPacket = 0;      // 0 seconds (never)
+
+       inData.init();
+       inData.accept = ChanPacket::T_PCP;
+
+       outData.init();
+       outData.accept = ChanPacket::T_PCP;
+}
+// ------------------------------------------
+void PCPStream::readVersion(Stream &in)
+{
+       int len = in.readInt();
+
+       if (len != 4)
+               throw StreamException("Invalid PCP");
+
+       int ver = in.readInt();
+
+       LOG_DEBUG("PCP ver: %d",ver);
+}
+// ------------------------------------------
+void PCPStream::readHeader(Stream &in,Channel *)
+{
+//     AtomStream atom(in);
+
+//     if (in.readInt() != PCP_CONNECT)
+//             throw StreamException("Not PCP");
+
+//     readVersion(in);
+}
+// ------------------------------------------
+bool PCPStream::sendPacket(ChanPacket &pack,GnuID &destID)
+{
+       if (destID.isSet())
+               if (!destID.isSame(remoteID))
+                       if (!routeList.contains(destID))
+                               return false;
+
+       return outData.writePacket(pack);
+}
+// ------------------------------------------
+void PCPStream::flush(Stream &in)
+{
+       ChanPacket pack;
+       // send outward packets
+       while (outData.numPending())
+       {
+               outData.readPacket(pack);
+               pack.writeRaw(in);
+       }
+}
+// ------------------------------------------
+int PCPStream::readPacket(Stream &in,Channel *)
+{
+       BroadcastState bcs;
+       return readPacket(in,bcs);
+}
+// ------------------------------------------
+int PCPStream::readPacket(Stream &in,BroadcastState &bcs)
+{
+       int error = PCP_ERROR_GENERAL;
+       try
+       {
+               AtomStream atom(in);
+
+               ChanPacket pack;
+               MemoryStream mem(pack.data,sizeof(pack.data));
+               AtomStream patom(mem);
+
+
+               // send outward packets
+               error = PCP_ERROR_WRITE;
+               if (outData.numPending())
+               {
+                       outData.readPacket(pack);
+                       pack.writeRaw(in);
+               }
+               error = PCP_ERROR_GENERAL;
+
+               if (outData.willSkip())
+               {
+                       error = PCP_ERROR_WRITE+PCP_ERROR_SKIP;
+                       throw StreamException("Send too slow");
+               }
+
+
+               error = PCP_ERROR_READ;
+               // poll for new downward packet
+               if (in.readReady())
+               {
+                       int numc,numd;
+                       ID4 id;
+
+                       id = atom.read(numc,numd);
+
+                       mem.rewind();
+                       pack.len = patom.writeAtoms(id, in, numc, numd);
+                       pack.type = ChanPacket::T_PCP;
+
+                       //inData.writePacket(pack);
+               //}
+               error = PCP_ERROR_GENERAL;
+
+               // process downward packets
+               //if (inData.numPending())
+               //{
+                       //inData.readPacket(pack);
+
+                       mem.rewind();
+
+                       //int numc,numd;
+                       id = patom.read(numc,numd);
+
+                       error = PCPStream::procAtom(patom,id,numc,numd,bcs);
+                       
+                       if (error)
+                               throw StreamException("PCP exception");
+               }
+
+               error = 0;
+
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("PCP readPacket: %s (%d)",e.msg,error);
+       }
+
+       return error;
+}
+
+// ------------------------------------------
+void PCPStream::readEnd(Stream &,Channel *)
+{
+}
+
+
+// ------------------------------------------
+void PCPStream::readPushAtoms(AtomStream &atom, int numc,BroadcastState &bcs)
+{
+       Host host;
+       GnuID   chanID;
+
+       chanID.clear();
+
+       for(int i=0; i<numc; i++)
+       {
+               int c,d;
+               ID4 id = atom.read(c,d);
+
+               if (id == PCP_PUSH_IP)
+                       host.ip = atom.readInt();
+               else if (id == PCP_PUSH_PORT)
+                       host.port = atom.readShort();
+               else if (id == PCP_PUSH_CHANID)
+                       atom.readBytes(chanID.id,16);
+               else
+               {
+                       LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d);
+                       atom.skip(c,d);
+               }
+       }
+
+
+       if (bcs.forMe)
+       {
+               char ipstr[64];
+               host.toStr(ipstr);
+
+               Servent *s = NULL;
+
+               if (chanID.isSet())
+               {
+                       Channel *ch = chanMgr->findChannelByID(chanID);
+                       if (ch)
+                               if (ch->isBroadcasting() || !ch->isFull() && !servMgr->relaysFull() && ch->info.id.isSame(chanID))
+                                       s = servMgr->allocServent();
+               }else{
+                       s = servMgr->allocServent();
+               }
+
+               if (s)
+               {
+                       LOG_DEBUG("GIVing to %s",ipstr);
+                       s->initGIV(host,chanID);
+               }
+       }
+
+}
+// ------------------------------------------
+void PCPStream::readRootAtoms(AtomStream &atom, int numc,BroadcastState &bcs)
+{
+       String url;
+
+       for(int i=0; i<numc; i++)
+       {
+               int c,d;
+               ID4 id = atom.read(c,d);
+
+               if (id == PCP_ROOT_UPDINT)
+               {
+                       int si = atom.readInt();
+
+                       chanMgr->setUpdateInterval(si);
+                       LOG_DEBUG("PCP got new host update interval: %ds",si);
+               }else if (id == PCP_ROOT_URL)
+               {
+                       url = "http://www.peercast.org/";
+                       String loc;
+                       atom.readString(loc.data,sizeof(loc.data),d);
+                       url.append(loc);
+
+               }else if (id == PCP_ROOT_CHECKVER)
+               {
+                       unsigned int newVer = atom.readInt();
+                       if (newVer > PCP_CLIENT_VERSION)
+                       {
+                               strcpy(servMgr->downloadURL,url.cstr());
+                               peercastApp->notifyMessage(ServMgr::NT_UPGRADE,"There is a new version available, please click here to upgrade your client.");
+                       }
+                       LOG_DEBUG("PCP got version check: %d / %d",newVer,PCP_CLIENT_VERSION);
+
+               }else if (id == PCP_ROOT_NEXT)
+               {
+                       unsigned int time = atom.readInt();
+
+                       if (time)
+                       {
+                               unsigned int ctime = sys->getTime();
+                               nextRootPacket = ctime+time;
+                               LOG_DEBUG("PCP expecting next root packet in %ds",time);
+                       }else
+                       {
+                               nextRootPacket = 0;
+                       }
+
+               }else if (id == PCP_ROOT_UPDATE)
+               {
+                       atom.skip(c,d);
+
+                       chanMgr->broadcastTrackerUpdate(remoteID,true);
+
+               }else if ((id == PCP_MESG_ASCII) || (id == PCP_MESG))                   // PCP_MESG_ASCII to be depreciated 
+               {
+                       String newMsg;
+
+                       atom.readString(newMsg.data,sizeof(newMsg.data),d);
+                       if (!newMsg.isSame(servMgr->rootMsg.cstr()))
+                       {
+                               servMgr->rootMsg = newMsg;
+                               LOG_DEBUG("PCP got new root mesg: %s",servMgr->rootMsg.cstr());
+                               peercastApp->notifyMessage(ServMgr::NT_PEERCAST,servMgr->rootMsg.cstr());
+                       }
+               }else
+               {
+                       LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d);
+                       atom.skip(c,d);
+               }
+       }
+}
+
+// ------------------------------------------
+void PCPStream::readPktAtoms(Channel *ch,AtomStream &atom,int numc,BroadcastState &bcs)
+{
+       ChanPacket pack;
+       ID4 type;
+
+
+       for(int i=0; i<numc; i++)
+       {
+               int c,d;
+               ID4 id = atom.read(c,d);
+
+               if (id == PCP_CHAN_PKT_TYPE)
+               {
+                       type = atom.readID4();
+
+                       if (type == PCP_CHAN_PKT_HEAD)
+                               pack.type = ChanPacket::T_HEAD;
+                       else if (type == PCP_CHAN_PKT_DATA)
+                               pack.type = ChanPacket::T_DATA;
+                       else
+                               pack.type = ChanPacket::T_UNKNOWN;
+
+               }else if (id == PCP_CHAN_PKT_POS)
+               {
+                       pack.pos = atom.readInt();
+
+
+               }else if (id == PCP_CHAN_PKT_DATA)
+               {
+                       pack.len = d;
+                       atom.readBytes(pack.data,pack.len);
+               }
+               else
+               {
+                       LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d);
+                       atom.skip(c,d);
+               }
+       }
+
+       if (ch)
+       {
+
+               int diff = pack.pos - ch->streamPos;
+               if (diff)
+               {
+                       LOG_DEBUG("PCP skipping %s%8d (%10d -> %10d) count=%2d",(diff>0)?"+":"",diff,ch->streamPos,pack.pos, ch->skipCount);
+                       if (ch->lastSkipTime + 120 < sys->getTime()){
+                               ch->skipCount = 0;
+                       }
+                       ch->lastSkipTime = sys->getTime();
+                       ch->skipCount++; //JP-EX
+                       pack.skip = true;
+               }
+
+               if (servMgr->autoBumpSkipCount) //JP-EX
+               {
+                       if (ch->skipCount > servMgr->autoBumpSkipCount)
+                       {
+                               LOG_DEBUG("Auto bump");
+                               ch->bump = true;
+                       }
+               }
+
+               if (pack.type == ChanPacket::T_HEAD)
+               {
+                       LOG_DEBUG("New head packet at %d",pack.pos);
+                       bool renewhead;
+                       if (servMgr->keepDownstreams)
+                               renewhead = (memcmp(ch->headPack.data, pack.data, pack.len) != 0);
+                       else
+                               renewhead = true;
+
+                       /*
+                       // check for stream restart
+                       if (pack.pos == 0)              
+                       {
+                               LOG_CHANNEL("PCP resetting stream");
+                               ch->streamIndex++;
+                               ch->rawData.init();
+                       }
+                       */
+                       if (renewhead || ch->lastStopTime + 30 < sys->getTime()) {
+                               // check for stream restart
+                               if (pack.pos == 0)
+                               {
+                                       LOG_CHANNEL("PCP resetting stream");
+                                       ch->streamIndex++;
+                                       ch->rawData.init();
+                               }
+
+                               ch->headPack = pack;
+
+                               ch->rawData.writePacket(pack,true);
+                               ch->streamPos = pack.pos+pack.len;
+                       }
+
+               }else if (pack.type == ChanPacket::T_DATA)
+               {
+                       ch->rawData.writePacket(pack,true);
+                       ch->streamPos = pack.pos+pack.len;
+               }
+
+       }
+
+       // update this parent packet stream position
+       if ((pack.pos) && (!bcs.streamPos || (pack.pos < bcs.streamPos)))
+               bcs.streamPos = pack.pos;
+
+}
+// -----------------------------------
+void PCPStream::readHostAtoms(AtomStream &atom, int numc, BroadcastState &bcs, ChanHit &hit, bool flg)
+{
+//     ChanHit hit;
+       hit.init();
+       GnuID chanID = bcs.chanID;      //use default
+
+       bool busy=false;
+
+       unsigned int ipNum=0;
+
+       for(int i=0; i<numc; i++)
+       {
+               int c,d;
+               ID4 id = atom.read(c,d);
+
+               if (id == PCP_HOST_IP)
+               {
+                       unsigned int ip = atom.readInt();
+                       hit.rhost[ipNum].ip = ip;
+               }else if (id == PCP_HOST_PORT)
+               {
+                       int port = atom.readShort();
+                       hit.rhost[ipNum++].port = port;
+
+                       if (ipNum > 1)
+                               ipNum = 1;
+               }
+               else if (id == PCP_HOST_NUML)
+                       hit.numListeners = atom.readInt();
+               else if (id == PCP_HOST_NUMR)
+                       hit.numRelays = atom.readInt();
+               else if (id == PCP_HOST_UPTIME)
+                       hit.upTime = atom.readInt();
+               else if (id == PCP_HOST_OLDPOS)
+                       hit.oldestPos = atom.readInt();
+               else if (id == PCP_HOST_NEWPOS)
+                       hit.newestPos = atom.readInt();
+               else if (id == PCP_HOST_VERSION)
+                       hit.version = atom.readInt();
+               else if (id == PCP_HOST_VERSION_VP)
+                       hit.version_vp = atom.readInt();
+               else if (id == PCP_HOST_VERSION_EX_PREFIX)
+                       atom.readBytes(hit.version_ex_prefix,2);
+               else if (id == PCP_HOST_VERSION_EX_NUMBER){
+                       hit.version_ex_number = atom.readShort();
+               }
+               else if (id == PCP_HOST_FLAGS1)
+               {
+                       int fl1 = atom.readChar();
+
+                       hit.recv = (fl1 & PCP_HOST_FLAGS1_RECV) !=0;
+                       hit.relay = (fl1 & PCP_HOST_FLAGS1_RELAY) !=0;
+                       hit.direct = (fl1 & PCP_HOST_FLAGS1_DIRECT) !=0;
+                       hit.cin = (fl1 & PCP_HOST_FLAGS1_CIN) !=0;
+                       hit.tracker = (fl1 & PCP_HOST_FLAGS1_TRACKER) !=0;
+                       hit.firewalled = (fl1 & PCP_HOST_FLAGS1_PUSH) !=0;
+
+
+               }else if (id == PCP_HOST_ID)
+                       atom.readBytes(hit.sessionID.id,16);
+               else if (id == PCP_HOST_CHANID)
+                       atom.readBytes(chanID.id,16);
+               else if (id == PCP_HOST_UPHOST_IP)
+                       hit.uphost.ip = atom.readInt();
+               else if (id == PCP_HOST_UPHOST_PORT)
+                       hit.uphost.port = atom.readInt();
+               else if (id == PCP_HOST_UPHOST_HOPS)
+                       hit.uphostHops = atom.readInt();
+               else
+               {
+                       LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d);
+                       atom.skip(c,d);
+               }
+       }
+
+       hit.host = hit.rhost[0];
+       hit.chanID = chanID;
+
+       hit.numHops = bcs.numHops;
+
+       hit.servent_id = bcs.servent_id;
+
+       if (flg){
+//             LOG_DEBUG("readHostAtoms HITLISTLOCK ON-------------");
+               chanMgr->hitlistlock.on();
+               if (hit.recv)
+                       chanMgr->addHit(hit);
+               else
+                       chanMgr->delHit(hit);
+//             LOG_DEBUG("readHostAtoms HITLISTLOCK OFF-------------");
+               chanMgr->hitlistlock.off();
+       }
+
+       if (hit.numHops == 1){
+               Servent *sv = servMgr->findServentByServentID(hit.servent_id);
+               if (sv){
+//                     LOG_DEBUG("set servent's waitPort = %d", hit.host.port);
+                       sv->waitPort = hit.host.port;
+               }
+       }
+}
+
+// ------------------------------------------
+void PCPStream::readChanAtoms(AtomStream &atom,int numc,BroadcastState &bcs)
+{
+/*     Channel *ch=NULL;
+       ChanHitList *chl=NULL;
+       ChanInfo newInfo;
+
+       ch = chanMgr->findChannelByID(bcs.chanID);
+       chl = chanMgr->findHitListByID(bcs.chanID);
+
+       if (ch)
+               newInfo = ch->info;
+       else if (chl)
+               newInfo = chl->info;*/
+
+       Channel *ch=NULL;
+       ChanHitList *chl=NULL;
+       ChanInfo newInfo, chaInfo;
+
+       ch = this->parent;
+       if (ch){
+               newInfo = ch->info;
+               chaInfo = ch->info;
+       }
+
+       for(int i=0; i<numc; i++)
+       {
+
+               int c,d;
+               ID4 id = atom.read(c,d);
+
+               if ((id == PCP_CHAN_PKT) && (ch))
+               {
+                       readPktAtoms(ch,atom,c,bcs);
+               }else if (id == PCP_CHAN_INFO)
+               {
+                       newInfo.readInfoAtoms(atom,c);
+
+               }else if (id == PCP_CHAN_TRACK)
+               {
+                       newInfo.readTrackAtoms(atom,c);
+
+               }else if (id == PCP_CHAN_BCID)
+               {
+                       atom.readBytes(newInfo.bcID.id,16);
+
+               }else if (id == PCP_CHAN_KEY)                   // depreciated
+               {
+                       atom.readBytes(newInfo.bcID.id,16);
+                       newInfo.bcID.id[0] = 0;                         // clear flags
+
+               }else if (id == PCP_CHAN_ID)
+               {
+                       atom.readBytes(newInfo.id.id,16);
+
+                       ch = chanMgr->findChannelByID(newInfo.id);
+                       chl = chanMgr->findHitListByID(newInfo.id);
+
+               }else
+               {
+                       LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d);
+                       atom.skip(c,d);
+               }
+       }
+
+       chl = chanMgr->findHitList(newInfo);
+
+       if (!chl)
+               chl = chanMgr->addHitList(newInfo);
+
+       if (chl)
+       {
+               chl->info.update(newInfo);
+       
+               if (!servMgr->chanLog.isEmpty())
+               {
+                       //if (chl->numListeners())
+                       {
+                               try
+                               {
+                                       FileStream file;
+                                       file.openWriteAppend(servMgr->chanLog.cstr());
+
+                                       XML::Node *rn = new XML::Node("update time=\"%d\"",sys->getTime());
+                                               XML::Node *n = chl->info.createChannelXML();
+                                       n->add(chl->createXML(false));
+                                       n->add(chl->info.createTrackXML());
+                                       rn->add(n);     
+       
+                                       rn->write(file,0);
+                                       delete rn;
+                                       file.close();
+                               }catch(StreamException &e)
+                               {
+                                       LOG_ERROR("Unable to update channel log: %s",e.msg);
+                               }
+                       }
+               }
+
+       }
+
+       if (ch && !ch->isBroadcasting())
+               ch->updateInfo(newInfo);
+
+
+}
+// ------------------------------------------
+int PCPStream::readBroadcastAtoms(AtomStream &atom,int numc,BroadcastState &bcs)
+{
+       ChanPacket pack;
+       int ttl=0;              
+       int ver=0;
+       int ver_vp=0;
+       GnuID fromID,destID;
+       int r=0;
+       char ver_ex_prefix[2];
+       int ver_ex_number = 0;
+
+       fromID.clear();
+       destID.clear();
+
+       bcs.initPacketSettings();
+
+       MemoryStream pmem(pack.data,sizeof(pack.data));
+       AtomStream patom(pmem);
+
+       patom.writeParent(PCP_BCST,numc);
+
+       for(int i=0; i<numc; i++)
+       {
+               int c,d;
+               ID4 id = atom.read(c,d);
+               
+               if (id == PCP_BCST_TTL)
+               {
+                       ttl = atom.readChar()-1;
+                       patom.writeChar(id,ttl);
+
+               }else if (id == PCP_BCST_HOPS)
+               {
+                       bcs.numHops = atom.readChar()+1;
+                       patom.writeChar(id,bcs.numHops);
+
+               }else if (id == PCP_BCST_FROM)
+               {
+                       atom.readBytes(fromID.id,16);
+                       patom.writeBytes(id,fromID.id,16);
+
+                       routeList.add(fromID);
+               }else if (id == PCP_BCST_GROUP)
+               {
+                       bcs.group = atom.readChar();
+                       patom.writeChar(id,bcs.group);
+               }else if (id == PCP_BCST_DEST)
+               {
+                       atom.readBytes(destID.id,16);
+                       patom.writeBytes(id,destID.id,16);
+                       bcs.forMe = destID.isSame(servMgr->sessionID);
+
+                       char idstr1[64];
+                       char idstr2[64];
+
+                       destID.toStr(idstr1);
+                       servMgr->sessionID.toStr(idstr2);
+
+               }else if (id == PCP_BCST_CHANID)
+               {
+                       atom.readBytes(bcs.chanID.id,16);
+                       patom.writeBytes(id,bcs.chanID.id,16);
+               }else if (id == PCP_BCST_VERSION)
+               {
+                       ver = atom.readInt();
+                       patom.writeInt(id,ver);
+               }else if (id == PCP_BCST_VERSION_VP)
+               {
+                       ver_vp = atom.readInt();
+                       patom.writeInt(id,ver_vp);
+               }else if (id == PCP_BCST_VERSION_EX_PREFIX)
+               {
+                       atom.readBytes(ver_ex_prefix,2);
+                       patom.writeBytes(id,ver_ex_prefix,2);
+               }else if (id == PCP_BCST_VERSION_EX_NUMBER)
+               {
+                       ver_ex_number = atom.readShort();
+                       patom.writeShort(id,ver_ex_number);
+               }else if (id == PCP_HOST)
+               {
+                       ChanHit hit;
+                       readHostAtoms(atom,c,bcs,hit,false);
+                       if (hit.uphost.ip == 0){
+//                             LOG_DEBUG("bcs servent_id = %d", bcs.servent_id);
+                               if (bcs.numHops == 1){
+                                       hit.uphost.ip = servMgr->serverHost.ip;
+                                       hit.uphost.port = servMgr->serverHost.port;
+                                       hit.uphostHops = 1;
+                               } else {
+                                       Servent *sv = servMgr->findServentByServentID(bcs.servent_id);
+                                       if (sv){
+                                               hit.uphost.ip = sv->getHost().ip;
+                                               hit.uphost.port = sv->waitPort;
+                                               hit.uphostHops = bcs.numHops - 1;
+                                       }
+                               }
+                       }
+                       int oldPos = pmem.pos;
+                       hit.writeAtoms(patom, hit.chanID);
+                       pmem.pos = oldPos;
+                       r = readAtom(patom,bcs);
+               } else {
+                       // copy and process atoms
+                       int oldPos = pmem.pos;
+                       patom.writeAtoms(id,atom.io,c,d);
+                       pmem.pos = oldPos;
+                       r = readAtom(patom,bcs);
+               }
+       }
+
+       char fromStr[64];
+       fromStr[0] = 0;
+       if (fromID.isSet())
+               fromID.toStr(fromStr);
+       char destStr[64];
+       destStr[0] = 0;
+       if (destID.isSet())
+               destID.toStr(destStr);
+       char tmp[64];
+       bcs.chanID.toStr(tmp);
+
+//     LOG_DEBUG(tmp);
+
+       if (ver_ex_number){
+               LOG_DEBUG("PCP bcst: group=%d, hops=%d, ver=%d(%c%c%04d), from=%s, dest=%s ttl=%d",
+                       bcs.group,bcs.numHops,ver,ver_ex_prefix[0],ver_ex_prefix[1],ver_ex_number,fromStr,destStr,ttl);
+       } else if (ver_vp){
+               LOG_DEBUG("PCP bcst: group=%d, hops=%d, ver=%d(VP%04d), from=%s, dest=%s ttl=%d",bcs.group,bcs.numHops,ver,ver_vp,fromStr,destStr,ttl);
+       } else {
+               LOG_DEBUG("PCP bcst: group=%d, hops=%d, ver=%d, from=%s, dest=%s ttl=%d",bcs.group,bcs.numHops,ver,fromStr,destStr,ttl);
+       }
+
+       if (fromID.isSet())
+               if (fromID.isSame(servMgr->sessionID))
+               {
+                       LOG_ERROR("BCST loopback"); 
+                       return PCP_ERROR_BCST+PCP_ERROR_LOOPBACK;
+               }
+
+       // broadcast back out if ttl > 0 
+       if ((ttl>0) && (!bcs.forMe))
+       {
+               pack.len = pmem.pos;
+               pack.type = ChanPacket::T_PCP;
+
+               if (bcs.group & (/*PCP_BCST_GROUP_ROOT|*/PCP_BCST_GROUP_TRACKERS|PCP_BCST_GROUP_RELAYS))
+               {
+                       chanMgr->broadcastPacketUp(pack,bcs.chanID,remoteID,destID);
+               }
+
+               if (bcs.group & (/*PCP_BCST_GROUP_ROOT|*/PCP_BCST_GROUP_TRACKERS|PCP_BCST_GROUP_RELAYS))
+               {
+                       servMgr->broadcastPacket(pack,bcs.chanID,remoteID,destID,Servent::T_COUT);
+               }
+
+               if (bcs.group & (PCP_BCST_GROUP_RELAYS|PCP_BCST_GROUP_TRACKERS))
+               {
+                       servMgr->broadcastPacket(pack,bcs.chanID,remoteID,destID,Servent::T_CIN);
+               }
+
+               if (bcs.group & (PCP_BCST_GROUP_RELAYS))
+               {
+                       servMgr->broadcastPacket(pack,bcs.chanID,remoteID,destID,Servent::T_RELAY);
+               }
+
+
+//             LOG_DEBUG("ttl=%d",ttl);
+
+       } else {
+//             LOG_DEBUG("ttl=%d",ttl);
+       }
+       return r;
+}
+
+
+// ------------------------------------------
+int PCPStream::procAtom(AtomStream &atom,ID4 id,int numc, int dlen,BroadcastState &bcs)
+{
+       int r=0;
+       ChanHit hit;
+       int rBan = 0;
+
+       if (id == PCP_CHAN)
+       {
+               readChanAtoms(atom,numc,bcs);
+       }else if (id == PCP_ROOT)
+       {
+               if (servMgr->isRoot)
+                       throw StreamException("Unauthorized root message");                             
+               else
+                       readRootAtoms(atom,numc,bcs);
+
+       }else if (id == PCP_HOST)
+       {
+               readHostAtoms(atom,numc,bcs,hit);
+               Channel *ch = chanMgr->findChannelByID(hit.chanID);
+               if (ch && (ch->isBroadcasting() || servMgr->vpDebug)){
+                       if (servMgr->autoPort0Kick && (hit.numHops == 1) && (hit.firewalled || (!hit.relay && !hit.numRelays))){
+                               char tmp[32];
+                               hit.host.IPtoStr(tmp);
+                               LOG_DEBUG("host that can't relay is disconnect: %s", tmp);
+                               rBan = PCP_ERROR_BANNED;
+                       }
+                       if (servMgr->allowOnlyVP && (hit.numHops == 1) && !hit.version_vp){
+                               char tmp[32];
+                               hit.host.IPtoStr(tmp);
+                               LOG_DEBUG("host that is not VP is disconnect: %s", tmp);
+                               rBan = PCP_ERROR_BANNED;
+                       }
+               }
+
+       }else if ((id == PCP_MESG_ASCII) || (id == PCP_MESG))           // PCP_MESG_ASCII to be depreciated
+       {
+               String msg;
+               atom.readString(msg.data,sizeof(msg.data),dlen);
+               LOG_DEBUG("PCP got text: %s",msg.cstr());
+       }else if (id == PCP_BCST)
+       {
+               r = readBroadcastAtoms(atom,numc,bcs);
+       }else if (id == PCP_HELO)
+       {
+               atom.skip(numc,dlen);
+               atom.writeParent(PCP_OLEH,1);
+                       atom.writeBytes(PCP_HELO_SESSIONID,servMgr->sessionID.id,16);
+       }else if (id == PCP_PUSH)
+       {
+
+               readPushAtoms(atom,numc,bcs);
+       }else if (id == PCP_OK)
+       {
+               atom.readInt();
+
+       }else if (id == PCP_QUIT)
+       {
+               r = atom.readInt();
+               if (!r)
+                       r = PCP_ERROR_QUIT;
+
+       }else if (id == PCP_ATOM)
+       {
+               for(int i=0; i<numc; i++)
+               {
+                       int nc,nd;
+                       ID4 aid = atom.read(nc,nd);
+                       int ar = procAtom(atom,aid,nc,nd,bcs);
+                       if (ar)
+                               r = ar;
+               }
+
+       }else
+       {
+               LOG_CHANNEL("PCP skip: %s",id.getString().str());
+               atom.skip(numc,dlen);
+       }
+
+       if (!r)
+               r = rBan;
+
+       return r;
+
+}
+
+// ------------------------------------------
+int PCPStream::readAtom(AtomStream &atom,BroadcastState &bcs)
+{
+       int numc,dlen;
+       ID4 id = atom.read(numc,dlen);
+
+       return  procAtom(atom,id,numc,dlen,bcs);
+}
+
+
diff --git a/PeerCast.root/PeerCast/core/common/pcp.h b/PeerCast.root/PeerCast/core/common/pcp.h
new file mode 100644 (file)
index 0000000..4085941
--- /dev/null
@@ -0,0 +1,268 @@
+// ------------------------------------------------
+// File : pcp.h
+// Date: 1-mar-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _PCP_H
+#define _PCP_H
+
+// ------------------------------------------------
+
+
+#include "id.h"
+#include "cstream.h"
+#include "channel.h"
+
+// ------------------------------------------------
+
+class Servent;
+
+
+// ------------------------------------------------
+
+static const ID4 PCP_CONNECT           = "pcp\n";
+
+static const ID4 PCP_OK                                = "ok";
+
+static const ID4 PCP_HELO                      = "helo";
+static const ID4 PCP_HELO_AGENT                = "agnt";
+static const ID4 PCP_HELO_OSTYPE       = "ostp";
+static const ID4 PCP_HELO_SESSIONID    = "sid";
+static const ID4 PCP_HELO_PORT         = "port";
+static const ID4 PCP_HELO_PING         = "ping";
+static const ID4 PCP_HELO_PONG         = "pong";
+static const ID4 PCP_HELO_REMOTEIP     = "rip";
+static const ID4 PCP_HELO_VERSION      = "ver";
+static const ID4 PCP_HELO_BCID         = "bcid";
+static const ID4 PCP_HELO_DISABLE      = "dis";
+
+static const ID4 PCP_OLEH                      = "oleh";
+
+static const ID4 PCP_MODE                      = "mode";
+static const ID4 PCP_MODE_GNUT06       = "gn06";
+
+static const ID4 PCP_ROOT                      = "root";
+static const ID4 PCP_ROOT_UPDINT       = "uint";
+static const ID4 PCP_ROOT_CHECKVER     = "chkv";
+static const ID4 PCP_ROOT_URL          = "url";
+static const ID4 PCP_ROOT_UPDATE       = "upd";
+static const ID4 PCP_ROOT_NEXT         = "next";
+
+
+static const ID4 PCP_OS_LINUX          = "lnux";
+static const ID4 PCP_OS_WINDOWS                = "w32";
+static const ID4 PCP_OS_OSX                    = "osx";
+static const ID4 PCP_OS_WINAMP         = "wamp";
+static const ID4 PCP_OS_ZAURUS         = "zaur";
+
+static const ID4 PCP_GET                       = "get";
+static const ID4 PCP_GET_ID                    = "id";
+static const ID4 PCP_GET_NAME          = "name";
+
+static const ID4 PCP_HOST                      = "host";
+static const ID4 PCP_HOST_ID           = "id";
+static const ID4 PCP_HOST_IP           = "ip";
+static const ID4 PCP_HOST_PORT         = "port";
+static const ID4 PCP_HOST_NUML         = "numl";
+static const ID4 PCP_HOST_NUMR         = "numr";
+static const ID4 PCP_HOST_UPTIME       = "uptm";
+static const ID4 PCP_HOST_TRACKER      = "trkr";
+static const ID4 PCP_HOST_CHANID       = "cid";
+static const ID4 PCP_HOST_VERSION      = "ver";
+static const ID4 PCP_HOST_VERSION_VP   = "vevp";
+static const ID4 PCP_HOST_VERSION_EX_PREFIX = "vexp";
+static const ID4 PCP_HOST_VERSION_EX_NUMBER = "vexn";
+static const ID4 PCP_HOST_FLAGS1       = "flg1";
+static const ID4 PCP_HOST_OLDPOS       = "oldp";
+static const ID4 PCP_HOST_NEWPOS       = "newp";
+static const ID4 PCP_HOST_UPHOST_IP    = "upip";
+static const ID4 PCP_HOST_UPHOST_PORT  = "uppt";
+static const ID4 PCP_HOST_UPHOST_HOPS  = "uphp";
+
+static const ID4 PCP_QUIT                      = "quit";
+
+static const ID4 PCP_CHAN                      = "chan";
+static const ID4 PCP_CHAN_ID           = "id";
+static const ID4 PCP_CHAN_BCID         = "bcid";
+static const ID4 PCP_CHAN_KEY          = "key";
+
+static const ID4 PCP_CHAN_PKT          = "pkt";
+static const ID4 PCP_CHAN_PKT_TYPE     = "type";
+static const ID4 PCP_CHAN_PKT_POS      = "pos";
+static const ID4 PCP_CHAN_PKT_HEAD     = "head";
+static const ID4 PCP_CHAN_PKT_DATA     = "data";
+static const ID4 PCP_CHAN_PKT_META     = "meta";
+
+static const ID4 PCP_CHAN_INFO                 = "info";
+static const ID4 PCP_CHAN_INFO_TYPE            = "type";
+static const ID4 PCP_CHAN_INFO_BITRATE = "bitr";
+static const ID4 PCP_CHAN_INFO_GENRE   = "gnre";
+static const ID4 PCP_CHAN_INFO_NAME            = "name";
+static const ID4 PCP_CHAN_INFO_URL             = "url";
+static const ID4 PCP_CHAN_INFO_DESC            = "desc";
+static const ID4 PCP_CHAN_INFO_COMMENT = "cmnt";
+
+static const ID4 PCP_CHAN_TRACK                        = "trck";
+static const ID4 PCP_CHAN_TRACK_TITLE  = "titl";
+static const ID4 PCP_CHAN_TRACK_CREATOR        = "crea";
+static const ID4 PCP_CHAN_TRACK_URL            = "url";
+static const ID4 PCP_CHAN_TRACK_ALBUM  = "albm";
+
+static const ID4 PCP_MESG                              = "mesg";
+static const ID4 PCP_MESG_ASCII                        = "asci";               // ascii/sjis to be depreciated.. utf8/unicode is the only supported format from now.
+static const ID4 PCP_MESG_SJIS                 = "sjis";
+
+static const ID4 PCP_BCST                              = "bcst";       
+static const ID4 PCP_BCST_TTL                  = "ttl";        
+static const ID4 PCP_BCST_HOPS                 = "hops";       
+static const ID4 PCP_BCST_FROM                 = "from";       
+static const ID4 PCP_BCST_DEST                 = "dest";       
+static const ID4 PCP_BCST_GROUP                        = "grp";        
+static const ID4 PCP_BCST_CHANID               = "cid";        
+static const ID4 PCP_BCST_VERSION              = "vers";
+static const ID4 PCP_BCST_VERSION_VP   = "vrvp";
+static const ID4 PCP_BCST_VERSION_EX_PREFIX = "vexp";
+static const ID4 PCP_BCST_VERSION_EX_NUMBER = "vexn";
+
+static const ID4 PCP_PUSH                              = "push";       
+static const ID4 PCP_PUSH_IP                   = "ip"; 
+static const ID4 PCP_PUSH_PORT                 = "port";       
+static const ID4 PCP_PUSH_CHANID               = "cid";        
+
+static const ID4 PCP_SPKT                              = "spkt";
+
+static const ID4 PCP_ATOM                              = "atom";       
+
+static const ID4 PCP_SESSIONID                 = "sid";
+
+static const int PCP_BCST_GROUP_ALL                    = (char)0xff;   
+static const int PCP_BCST_GROUP_ROOT           = 1;    
+static const int PCP_BCST_GROUP_TRACKERS       = 2;    
+static const int PCP_BCST_GROUP_RELAYS         = 4;    
+
+
+static const int PCP_ERROR_QUIT                        = 1000;
+static const int PCP_ERROR_BCST                        = 2000;
+static const int PCP_ERROR_READ                        = 3000;
+static const int PCP_ERROR_WRITE               = 4000;
+static const int PCP_ERROR_GENERAL             = 5000;
+
+static const int PCP_ERROR_SKIP                                = 1;
+static const int PCP_ERROR_ALREADYCONNECTED    = 2;
+static const int PCP_ERROR_UNAVAILABLE         = 3;
+static const int PCP_ERROR_LOOPBACK                    = 4;
+static const int PCP_ERROR_NOTIDENTIFIED       = 5;
+static const int PCP_ERROR_BADRESPONSE         = 6;
+static const int PCP_ERROR_BADAGENT                    = 7;
+static const int PCP_ERROR_OFFAIR                      = 8;
+static const int PCP_ERROR_SHUTDOWN                    = 9;
+static const int PCP_ERROR_NOROOT                      = 10;
+static const int PCP_ERROR_BANNED                      = 11;
+
+static const int PCP_HOST_FLAGS1_TRACKER       = 0x01;
+static const int PCP_HOST_FLAGS1_RELAY         = 0x02;
+static const int PCP_HOST_FLAGS1_DIRECT                = 0x04;
+static const int PCP_HOST_FLAGS1_PUSH          = 0x08;
+static const int PCP_HOST_FLAGS1_RECV          = 0x10;
+static const int PCP_HOST_FLAGS1_CIN           = 0x20;
+static const int PCP_HOST_FLAGS1_PRIVATE       = 0x40;
+
+
+// ----------------------------------------------
+class BroadcastState 
+{
+public:
+       BroadcastState()
+       :numHops(0)
+       ,forMe(false) 
+       ,streamPos(0)
+       ,group(0)
+       ,servent_id(0)
+       {
+               chanID.clear();
+               bcID.clear();
+       }
+
+
+       void initPacketSettings()
+       {
+               forMe = false;
+               group = 0;
+               numHops = 0;
+               bcID.clear();
+               chanID.clear();
+       }
+
+
+       GnuID chanID,bcID;
+       int numHops;
+       bool forMe;
+       unsigned int streamPos;
+       int group;
+       int servent_id;
+};
+
+// ----------------------------------------------
+class PCPStream : public ChannelStream
+{
+public:
+       PCPStream(GnuID &rid) 
+       :routeList(1000)
+       {
+               init(rid);
+       }
+
+       void    init(GnuID &);
+
+       virtual void kill()
+       {
+               inData.lock.on();
+               outData.lock.on();
+       }
+
+       virtual bool sendPacket(ChanPacket &,GnuID &);
+       virtual void flush(Stream &);
+       virtual void readHeader(Stream &,Channel *);
+       virtual int readPacket(Stream &,Channel *);
+       virtual void readEnd(Stream &,Channel *);
+
+       int             readPacket(Stream &,BroadcastState &);
+       void    flushOutput(Stream &in,BroadcastState &);
+       static void     readVersion(Stream &);
+
+       int             procAtom(AtomStream &,ID4,int,int,BroadcastState &);
+       int             readAtom(AtomStream &,BroadcastState &);
+       void    readChanAtoms(AtomStream &,int,BroadcastState &);
+//     void    readHostAtoms(AtomStream &, int, BroadcastState &);
+       void    readHostAtoms(AtomStream &, int, BroadcastState &, ChanHit &, bool flg=true);
+       void    readPushAtoms(AtomStream &, int,BroadcastState &);
+
+       void    readPktAtoms(Channel *,AtomStream &,int,BroadcastState &);
+       void    readRootAtoms(AtomStream &, int,BroadcastState &);
+
+       int             readBroadcastAtoms(AtomStream &,int,BroadcastState &);
+
+       ChanPacketBuffer inData,outData;
+       unsigned int lastPacketTime;
+       unsigned int nextRootPacket;    
+
+       //int   error;
+       GnuIDList       routeList;
+       GnuID   remoteID;
+
+};
+
+#endif
diff --git a/PeerCast.root/PeerCast/core/common/peercast.cpp b/PeerCast.root/PeerCast/core/common/peercast.cpp
new file mode 100644 (file)
index 0000000..9560fa8
--- /dev/null
@@ -0,0 +1,242 @@
+#include "sys.h"
+#include "peercast.h"
+#include "channel.h"
+#include "servmgr.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+
+// ---------------------------------
+// globals
+
+Sys *sys=NULL;
+ChanMgr *chanMgr;
+ServMgr *servMgr;
+
+PeercastInstance *peercastInst=NULL;
+PeercastApplication *peercastApp=NULL;
+
+
+// ---------------------------------
+void APICALL PeercastInstance::init()
+{
+       sys = createSys();
+       servMgr = new ServMgr();
+       chanMgr = new ChanMgr();
+
+       if (peercastApp->getIniFilename())
+               servMgr->loadSettings(peercastApp->getIniFilename());
+
+       servMgr->start();
+}
+// --------------------------------------------------
+void   APICALL PeercastInstance::setNotifyMask(int mask)
+{
+       if (servMgr)
+               servMgr->notifyMask = mask;
+}
+// --------------------------------------------------
+int            APICALL PeercastInstance::getNotifyMask()
+{
+       if (servMgr)
+               return servMgr->notifyMask;
+       else    
+               return 0;
+}
+
+// --------------------------------------------------
+void   APICALL PeercastInstance::setAutoConnect(bool on)
+{
+       if (servMgr)
+               servMgr->autoConnect = on;
+}
+// --------------------------------------------------
+bool   APICALL PeercastInstance::getAutoConnect()
+{
+       if (servMgr)
+               return servMgr->autoConnect;
+       else
+               return false;
+}
+// --------------------------------------------------
+void   APICALL PeercastInstance::setMaxOutput(int kbps)
+{
+       if (servMgr)
+               servMgr->maxBitrateOut = kbps;
+}
+// --------------------------------------------------
+int            APICALL PeercastInstance::getMaxOutput()
+{
+       if (servMgr)
+               return servMgr->maxBitrateOut;
+       else
+               return 0;
+}
+// --------------------------------------------------
+void   APICALL PeercastInstance::setMaxRelays(int max)
+{
+       if (servMgr)
+               servMgr->setMaxRelays(max);
+}
+// --------------------------------------------------
+int            APICALL PeercastInstance::getMaxRelays()
+{
+       if (servMgr)
+               return servMgr->maxRelays;
+       else
+               return 0;
+}
+// --------------------------------------------------
+void   APICALL PeercastInstance::setActive(bool on)
+{
+       if (servMgr)
+       {
+               servMgr->autoConnect = on;
+               servMgr->autoServe = on;
+       }
+}
+// --------------------------------------------------
+bool   APICALL PeercastInstance::getActive()
+{
+       if (servMgr)
+               return servMgr->autoConnect&&servMgr->autoServe;
+       else
+               return false;
+}
+// --------------------------------------------------
+void   APICALL PeercastInstance::saveSettings()
+{
+       if (servMgr)
+               servMgr->saveSettings(peercastApp->getIniFilename());
+}
+// --------------------------------------------------
+void   APICALL PeercastInstance::quit()
+{
+       isQuitting = true;
+       if (chanMgr)
+               chanMgr->quit();
+       if (servMgr)
+               servMgr->quit();
+}
+// --------------------------------------------------
+void   APICALL PeercastInstance::setServerPort(int port)
+{
+       if (servMgr)
+       {
+               servMgr->serverHost.port = port;
+               servMgr->restartServer = true;
+       }
+}
+// --------------------------------------------------
+int            APICALL PeercastInstance::getServerPort()
+{
+       if (servMgr)
+               return servMgr->serverHost.port;
+       else
+               return 0;
+}
+// --------------------------------------------------
+void   APICALL PeercastInstance::setServerPassword(const char *pwd)
+{
+       if (servMgr)
+               strcpy(servMgr->password,pwd);
+}
+// --------------------------------------------------
+const char *APICALL    PeercastInstance::getServerPassword()
+{
+       return servMgr->password;
+}
+// --------------------------------------------------
+void   APICALL PeercastInstance::callLocalURL(const char *url)
+{
+       if (sys && servMgr)
+               sys->callLocalURL(url,servMgr->serverHost.port);
+}
+
+
+// --------------------------------------------------
+void ADDLOG(const char *fmt,va_list ap,LogBuffer::TYPE type)
+{
+       if(sys)
+       {
+               const int MAX_LINELEN = 1024;
+
+               char str[MAX_LINELEN+1];
+               vsnprintf(str,MAX_LINELEN-1,fmt,ap);
+               str[MAX_LINELEN-1]=0;
+
+               if (type != LogBuffer::T_NONE)
+                       sys->logBuf->write(str,type);
+
+               peercastApp->printLog(type,str);
+       }
+}
+// --------------------------------------------------
+void LOG(const char *fmt,...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       ADDLOG(fmt,ap,LogBuffer::T_DEBUG);
+       va_end(ap);     
+}
+
+// --------------------------------------------------
+void LOG_ERROR(const char *fmt,...)
+{
+       if (servMgr)
+       {
+               if ((servMgr->showLog & (1<<LogBuffer::T_ERROR)) && (!servMgr->pauseLog))
+               {
+                       va_list ap;
+                       va_start(ap, fmt);
+                       ADDLOG(fmt,ap,LogBuffer::T_ERROR);
+                       va_end(ap);     
+               }
+       }
+}
+// --------------------------------------------------
+void LOG_DEBUG(const char *fmt,...)
+{
+       if (servMgr)
+       {
+               if ((servMgr->showLog & (1<<LogBuffer::T_DEBUG)) && (!servMgr->pauseLog))
+               {
+                       va_list ap;
+                       va_start(ap, fmt);
+                       ADDLOG(fmt,ap,LogBuffer::T_DEBUG);
+                       va_end(ap);     
+               }
+       }
+}
+// --------------------------------------------------
+void LOG_NETWORK(const char *fmt,...)
+{
+       if (servMgr)
+       {
+               if ((servMgr->showLog & (1<<LogBuffer::T_NETWORK)) && (!servMgr->pauseLog))
+               {
+                       va_list ap;
+                       va_start(ap, fmt);
+                       ADDLOG(fmt,ap,LogBuffer::T_NETWORK);
+                       va_end(ap);     
+               }
+       }
+}
+// --------------------------------------------------
+void LOG_CHANNEL(const char *fmt,...)
+{
+       if (servMgr)
+       {
+               if ((servMgr->showLog & (1<<LogBuffer::T_CHANNEL)) && (!servMgr->pauseLog))
+               {
+                       va_list ap;
+                       va_start(ap, fmt);
+                       ADDLOG(fmt,ap,LogBuffer::T_CHANNEL);
+                       va_end(ap);     
+               }
+       }
+}
diff --git a/PeerCast.root/PeerCast/core/common/peercast.h b/PeerCast.root/PeerCast/core/common/peercast.h
new file mode 100644 (file)
index 0000000..ef8732b
--- /dev/null
@@ -0,0 +1,102 @@
+#ifndef _PEERCAST_H
+#define _PEERCAST_H
+
+
+//#define APICALL _stdcall
+#ifdef WIN32
+#define APICALL _cdecl
+#else
+#define APICALL 
+#endif
+
+
+class ChanInfo;
+class Sys;
+
+#include "servmgr.h"
+
+
+// ------------------------------------------------------------
+// This is the interface from the application to the core.
+class PeercastInstance 
+{
+public:
+       PeercastInstance()
+       :isQuitting(false) 
+       {}
+
+       virtual void    APICALL init();
+
+       virtual void    APICALL setAutoConnect(bool);
+       virtual bool    APICALL getAutoConnect();
+
+       virtual void    APICALL setActive(bool);
+       virtual bool    APICALL getActive();
+
+       virtual int             APICALL getMaxOutput();
+       virtual void    APICALL setMaxOutput(int);
+
+       virtual int             APICALL getMaxRelays();
+       virtual void    APICALL setMaxRelays(int);
+
+       virtual void    APICALL setServerPort(int);
+       virtual int             APICALL getServerPort();
+       virtual void    APICALL setServerPassword(const char *);
+       virtual const char *APICALL     getServerPassword();
+
+       virtual void    APICALL saveSettings();
+
+       virtual void    APICALL callLocalURL(const char *);
+
+       virtual void    APICALL setNotifyMask(int);
+       virtual int             APICALL getNotifyMask();
+
+       virtual void    APICALL quit();
+
+       virtual Sys     *       APICALL createSys()=0;
+
+       bool isQuitting;
+
+};
+// ------------------------------------------------------------
+// This is the interface from the core to the application.
+class PeercastApplication
+{
+public:
+
+       virtual const char * APICALL getPath() {return "./";}
+       virtual const char * APICALL getIniFilename() {return "peercast.ini";}
+       virtual bool    APICALL clearTemp() { return false; } //JP-EX
+       virtual void    APICALL openLogFile() {} //JP-EX
+       virtual void    APICALL getDirectory() {} //JP-EX
+       virtual void    APICALL printLog(LogBuffer::TYPE, const char *) {}
+       virtual void    APICALL addChannel(ChanInfo *) {}
+       virtual void    APICALL delChannel(ChanInfo *) {}
+       virtual void    APICALL resetChannels() {}
+       virtual void    APICALL test(char *) {}
+       virtual const char *APICALL getClientTypeOS() = 0;
+       virtual void    APICALL updateSettings() {}
+
+       virtual void    APICALL notifyMessage(ServMgr::NOTIFY_TYPE, const char *) {}
+       virtual void    APICALL channelStart(ChanInfo *) {}
+       virtual void    APICALL channelStop(ChanInfo *) {}
+       virtual void    APICALL channelUpdate(ChanInfo *) {}
+};
+
+
+// ----------------------------------
+extern PeercastInstance *peercastInst;
+extern PeercastApplication *peercastApp;
+
+// ----------------------------------
+#ifdef WIN32
+extern "C"
+{
+__declspec( dllexport ) PeercastInstance * newPeercast(PeercastApplication *);
+};
+#endif
+
+// ----------------------------------
+
+
+#endif
diff --git a/PeerCast.root/PeerCast/core/common/rtsp.cpp b/PeerCast.root/PeerCast/core/common/rtsp.cpp
new file mode 100644 (file)
index 0000000..4101852
--- /dev/null
@@ -0,0 +1,26 @@
+// ------------------------------------------------
+// File : rtsp.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             RTSP protocol handling (experimental)
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "rtsp.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
diff --git a/PeerCast.root/PeerCast/core/common/rtsp.h b/PeerCast.root/PeerCast/core/common/rtsp.h
new file mode 100644 (file)
index 0000000..60bb71d
--- /dev/null
@@ -0,0 +1,32 @@
+// ------------------------------------------------
+// File : rtsp.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _RTSP_H
+#define _RTSP_H
+
+#include "http.h"
+
+// ---------------------------------------------
+class RTSP : public HTTP
+{
+public:
+       RTSP(Stream &s):HTTP(s){}
+};
+
+#endif
diff --git a/PeerCast.root/PeerCast/core/common/servent.cpp b/PeerCast.root/PeerCast/core/common/servent.cpp
new file mode 100644 (file)
index 0000000..1ce8a26
--- /dev/null
@@ -0,0 +1,3163 @@
+// ------------------------------------------------
+// File : servent.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             Servents are the actual connections between clients. They do the handshaking,
+//             transfering of data and processing of GnuPackets. Each servent has one socket allocated
+//             to it on connect, it uses this to transfer all of its data.
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+// todo: make lan->yp not check firewall
+
+#include <stdlib.h>
+#include "servent.h"
+#include "sys.h"
+#include "gnutella.h"
+#include "xml.h"
+#include "html.h"
+#include "http.h"
+#include "stats.h"
+#include "servmgr.h"
+#include "peercast.h"
+#include "atom.h"
+#include "pcp.h"
+#include "version2.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+const int DIRECT_WRITE_TIMEOUT = 60;
+
+// -----------------------------------
+char *Servent::statusMsgs[]=
+{
+        "NONE",
+               "CONNECTING",
+        "PROTOCOL",
+        "HANDSHAKE",
+        "CONNECTED",
+        "CLOSING",
+               "LISTENING",
+               "TIMEOUT",
+               "REFUSED",
+               "VERIFIED",
+               "ERROR",
+               "WAIT",
+               "FREE"
+};
+
+// -----------------------------------
+char *Servent::typeMsgs[]=
+{
+               "NONE",
+        "INCOMING",
+        "SERVER",
+               "RELAY",
+               "DIRECT",
+               "COUT",
+               "CIN",
+               "PGNU"
+};
+// -----------------------------------
+bool   Servent::isPrivate() 
+{
+       Host h = getHost();
+       return servMgr->isFiltered(ServFilter::F_PRIVATE,h) || h.isLocalhost();
+}
+// -----------------------------------
+bool   Servent::isAllowed(int a) 
+{
+       Host h = getHost();
+
+       if (servMgr->isFiltered(ServFilter::F_BAN,h))
+               return false;
+
+       return (allow&a)!=0;
+}
+
+// -----------------------------------
+bool   Servent::isFiltered(int f) 
+{
+       Host h = getHost();
+       return servMgr->isFiltered(f,h);
+}
+
+int servent_count = 1;
+// -----------------------------------
+Servent::Servent(int index)
+:outPacketsPri(MAX_OUTPACKETS)
+,outPacketsNorm(MAX_OUTPACKETS)
+,seenIDs(MAX_HASH)
+,serventIndex(index)
+,sock(NULL)
+,next(NULL)
+{
+       reset();
+       servent_id = servent_count++;
+       lastSkipTime = 0;
+       lastSkipCount = 0;
+       waitPort = 0;
+}
+
+// -----------------------------------
+Servent::~Servent()
+{      
+       
+}
+// -----------------------------------
+void   Servent::kill() 
+{
+       thread.active = false;
+               
+       setStatus(S_CLOSING);
+
+       if (pcpStream)
+       {
+               PCPStream *pcp = pcpStream;
+               pcpStream = NULL;
+               pcp->kill();
+               delete pcp;
+       }
+
+       chanMgr->hitlistlock.on();
+       ChanHitList *chl = chanMgr->findHitListByID(chanID);
+       if (chl) {
+               ChanHit *chh = chl->hit;
+               ChanHit *prev = NULL;
+               while (chh) {
+                       if (chh->servent_id == this->servent_id){
+                               if ((servMgr->kickKeepTime != 0) && (chh->firewalled == 1)){
+                                       chh->numHops = 0;
+                                       chh->numListeners = 0;
+                                       chh->numRelays = 0;
+                                       prev = chh;
+                                       chh = chh->next;
+                               } else {
+                                       ChanHit *next = chh->next;
+                                       if (prev)
+                                               prev->next = next;
+                                       else
+                                               chl->hit = next;
+
+       char ip0str[64],ip1str[64];
+       chh->rhost[0].toStr(ip0str);
+       chh->rhost[1].toStr(ip1str);
+       LOG_DEBUG("Delete hit (servent_id=%d): F%dT%dR%d %s/%s",
+               chh->servent_id,chh->firewalled,chh->tracker,chh->relay,ip0str,ip1str);
+
+                                       delete chh;
+                                       chh = next;
+                               }
+                       } else {
+                               prev = chh;
+                               chh = chh->next;
+                       }
+               }
+       }
+       chanMgr->hitlistlock.off();
+
+       if (sock)
+       {
+               sock->close();
+               delete sock;
+               sock = NULL;
+       }
+
+       if (pushSock)
+       {
+               pushSock->close();
+               delete pushSock;
+               pushSock = NULL;
+       }
+
+//     thread.unlock();
+
+       if (type != T_SERVER)
+       {
+               reset();
+               setStatus(S_FREE);
+       }
+
+}
+// -----------------------------------
+void   Servent::abort() 
+{
+       thread.active = false;
+       if (sock)
+       {
+               sock->close();
+       }
+
+}
+
+// -----------------------------------
+void Servent::reset()
+{
+
+       remoteID.clear();
+
+       servPort = 0;
+
+       pcpStream = NULL;
+
+       flowControl = false;
+       networkID.clear();
+
+       chanID.clear();
+
+       outputProtocol = ChanInfo::SP_UNKNOWN;
+
+       agent.clear();
+       sock = NULL;
+       allow = ALLOW_ALL;
+       syncPos = 0;
+       addMetadata = false;
+       nsSwitchNum = 0;
+       pack.func = 255;
+       lastConnect = lastPing = lastPacket = 0;
+       loginPassword[0] = 0;
+       loginMount[0] = 0;
+       bytesPerSecond = 0;
+       priorityConnect = false;
+       pushSock = NULL;
+       sendHeader = true;
+
+       outPacketsNorm.reset();
+       outPacketsPri.reset();
+
+       seenIDs.clear();
+
+       status = S_NONE;
+       type = T_NONE;
+
+       channel_id = 0;
+}
+// -----------------------------------
+bool Servent::sendPacket(ChanPacket &pack,GnuID &cid,GnuID &sid,GnuID &did,Servent::TYPE t)
+{
+
+       if  (      (type == t) 
+                       && (isConnected())
+                       && (!cid.isSet() || chanID.isSame(cid))
+                       && (!sid.isSet() || !sid.isSame(remoteID))
+                       && (pcpStream != NULL)
+               )
+       {
+               return pcpStream->sendPacket(pack,did);
+       }
+       return false;
+}
+
+
+// -----------------------------------
+bool Servent::acceptGIV(ClientSocket *givSock)
+{
+       if (!pushSock)
+       {
+               pushSock = givSock;
+               return true;
+       }else
+               return false;
+}
+
+// -----------------------------------
+Host Servent::getHost()
+{
+       Host h(0,0);
+
+       if (sock)
+               h = sock->host;
+
+       return h;
+}
+
+// -----------------------------------
+bool Servent::outputPacket(GnuPacket &p, bool pri)
+{
+       lock.on();
+
+       bool r=false;
+       if (pri)
+               r = outPacketsPri.write(p);
+       else
+       {
+               if (servMgr->useFlowControl)
+               {
+                       int per = outPacketsNorm.percentFull();
+                       if (per > 50)
+                               flowControl = true;
+                       else if (per < 25)
+                               flowControl = false;
+               }
+
+
+               bool send=true;
+               if (flowControl)
+               {
+                       // if in flowcontrol, only allow packets with less of a hop count than already in queue
+                       if (p.hops >= outPacketsNorm.findMinHop())
+                               send = false;
+               }
+
+               if (send)
+                       r = outPacketsNorm.write(p);
+       }
+
+       lock.off();
+       return r;
+}
+
+// -----------------------------------
+bool Servent::initServer(Host &h)
+{
+       try
+       {
+               checkFree();
+
+               status = S_WAIT;
+
+               createSocket();
+
+               sock->bind(h);
+
+               thread.data = this;
+
+               thread.func = serverProc;
+
+               type = T_SERVER;
+
+               if (!sys->startThread(&thread))
+                       throw StreamException("Can`t start thread");
+
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("Bad server: %s",e.msg);
+               kill();
+               return false;
+       }
+
+       return true;
+}
+// -----------------------------------
+void Servent::checkFree()
+{
+       if (sock)
+               throw StreamException("Socket already set");
+       if (thread.active)
+               throw StreamException("Thread already active");
+}
+// -----------------------------------
+void Servent::initIncoming(ClientSocket *s, unsigned int a)
+{
+
+       try{
+
+               checkFree();
+
+               type = T_INCOMING;
+               sock = s;
+               allow = a;
+               thread.data = this;
+               thread.func = incomingProc;
+
+               setStatus(S_PROTOCOL);
+
+               char ipStr[64];
+               sock->host.toStr(ipStr);
+               LOG_DEBUG("Incoming from %s",ipStr);
+
+
+               if (!sys->startThread(&thread))
+                       throw StreamException("Can`t start thread");
+       }catch(StreamException &e)
+       {
+               //LOG_ERROR("!!FATAL!! Incoming error: %s",e.msg);
+               //servMgr->shutdownTimer = 1;   
+               kill();
+
+               LOG_ERROR("INCOMING FAILED: %s",e.msg);
+
+       }
+}
+
+// -----------------------------------
+void Servent::initOutgoing(TYPE ty)
+{
+       try 
+       {
+               checkFree();
+
+
+               type = ty;
+
+               thread.data = this;
+               thread.func = outgoingProc;
+
+               if (!sys->startThread(&thread))
+                       throw StreamException("Can`t start thread");
+
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("Unable to start outgoing: %s",e.msg);
+               kill();
+       }
+}
+
+// -----------------------------------
+void Servent::initPCP(Host &rh)
+{
+       char ipStr[64];
+       rh.toStr(ipStr);
+       try 
+       {
+               checkFree();
+
+           createSocket();
+
+               type = T_COUT;
+
+               sock->open(rh);
+
+               if (!isAllowed(ALLOW_NETWORK))
+                       throw StreamException("Servent not allowed");
+
+               thread.data = this;
+               thread.func = outgoingProc;
+
+               LOG_DEBUG("Outgoing to %s",ipStr);
+
+               if (!sys->startThread(&thread))
+                       throw StreamException("Can`t start thread");
+
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("Unable to open connection to %s - %s",ipStr,e.msg);
+               kill();
+       }
+}
+
+#if 0
+// -----------------------------------
+void   Servent::initChannelFetch(Host &host)
+{
+       type = T_STREAM;
+
+       char ipStr[64];
+       host.toStr(ipStr);
+
+       checkFree();
+        
+       createSocket();
+               
+       sock->open(host);
+
+               
+       if (!isAllowed(ALLOW_DATA))     
+               throw StreamException("Servent not allowed");
+               
+       sock->connect();
+}
+#endif
+
+// -----------------------------------
+void Servent::initGIV(Host &h, GnuID &id)
+{
+       char ipStr[64];
+       h.toStr(ipStr);
+       try 
+       {
+               checkFree();
+
+               givID = id;
+
+           createSocket();
+
+               sock->open(h);
+
+               if (!isAllowed(ALLOW_NETWORK))
+                       throw StreamException("Servent not allowed");
+               
+               sock->connect();
+
+               thread.data = this;
+               thread.func = givProc;
+
+               type = T_RELAY;
+
+               if (!sys->startThread(&thread))
+                       throw StreamException("Can`t start thread");
+
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("GIV error to %s: %s",ipStr,e.msg);
+               kill();
+       }
+}
+// -----------------------------------
+void Servent::createSocket()
+{
+       if (sock)
+               LOG_ERROR("Servent::createSocket attempt made while active");
+
+       sock = sys->createSocket();
+}
+// -----------------------------------
+void Servent::setStatus(STATUS s)
+{
+       if (s != status)
+       {
+               status = s;
+
+               if ((s == S_HANDSHAKE) || (s == S_CONNECTED) || (s == S_LISTENING))
+                       lastConnect = sys->getTime();
+       }
+
+}
+
+// -----------------------------------
+void Servent::handshakeOut()
+{
+    sock->writeLine(GNU_PEERCONN);
+
+       char str[64];
+    
+       sock->writeLineF("%s %s",HTTP_HS_AGENT,PCX_AGENT);
+    sock->writeLineF("%s %d",PCX_HS_PCP,1);
+
+       if (priorityConnect)
+           sock->writeLineF("%s %d",PCX_HS_PRIORITY,1);
+       
+       if (networkID.isSet())
+       {
+               networkID.toStr(str);
+               sock->writeLineF("%s %s",PCX_HS_NETWORKID,str);
+       }
+
+       servMgr->sessionID.toStr(str);
+       sock->writeLineF("%s %s",PCX_HS_ID,str);
+
+       
+    sock->writeLineF("%s %s",PCX_HS_OS,peercastApp->getClientTypeOS());
+       
+       sock->writeLine("");
+
+       HTTP http(*sock);
+
+       int r = http.readResponse();
+
+       if (r != 200)
+       {
+               LOG_ERROR("Expected 200, got %d",r);
+               throw StreamException("Unexpected HTTP response");
+       }
+
+
+       bool versionValid = false;
+
+       GnuID clientID;
+       clientID.clear();
+
+    while (http.nextHeader())
+    {
+               LOG_DEBUG(http.cmdLine);
+
+               char *arg = http.getArgStr();
+               if (!arg)
+                       continue;
+
+               if (http.isHeader(HTTP_HS_AGENT))
+               {
+                       agent.set(arg);
+
+                       if (strnicmp(arg,"PeerCast/",9)==0)
+                               versionValid = (stricmp(arg+9,MIN_CONNECTVER)>=0);
+               }else if (http.isHeader(PCX_HS_NETWORKID))
+                       clientID.fromStr(arg);
+    }
+
+       if (!clientID.isSame(networkID))
+               throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+       if (!versionValid)
+               throw HTTPException(HTTP_SC_UNAUTHORIZED,401);
+
+
+    sock->writeLine(GNU_OK);
+    sock->writeLine("");
+
+}
+
+
+// -----------------------------------
+void Servent::processOutChannel()
+{
+}
+
+
+// -----------------------------------
+void Servent::handshakeIn()
+{
+
+       int osType=0;
+
+       HTTP http(*sock);
+
+
+       bool versionValid = false;
+       bool diffRootVer = false;
+
+       GnuID clientID;
+       clientID.clear();
+
+    while (http.nextHeader())
+    {
+               LOG_DEBUG("%s",http.cmdLine);
+
+               char *arg = http.getArgStr();
+               if (!arg)
+                       continue;
+
+               if (http.isHeader(HTTP_HS_AGENT))
+               {
+                       agent.set(arg);
+
+                       if (strnicmp(arg,"PeerCast/",9)==0)
+                       {
+                               versionValid = (stricmp(arg+9,MIN_CONNECTVER)>=0);
+                               diffRootVer = stricmp(arg+9,MIN_ROOTVER)<0;
+                       }
+               }else if (http.isHeader(PCX_HS_NETWORKID))
+               {
+                       clientID.fromStr(arg);
+
+               }else if (http.isHeader(PCX_HS_PRIORITY))
+               {
+                       priorityConnect = atoi(arg)!=0;
+
+               }else if (http.isHeader(PCX_HS_ID))
+               {
+                       GnuID id;
+                       id.fromStr(arg);
+                       if (id.isSame(servMgr->sessionID))
+                               throw StreamException("Servent loopback");
+
+               }else if (http.isHeader(PCX_HS_OS))
+               {
+                       if (stricmp(arg,PCX_OS_LINUX)==0)
+                               osType = 1;
+                       else if (stricmp(arg,PCX_OS_WIN32)==0)
+                               osType = 2;
+                       else if (stricmp(arg,PCX_OS_MACOSX)==0)
+                               osType = 3;
+                       else if (stricmp(arg,PCX_OS_WINAMP2)==0)
+                               osType = 4;
+               }
+
+    }
+
+       if (!clientID.isSame(networkID))
+               throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+       // if this is a priority connection and all incoming connections 
+       // are full then kill an old connection to make room. Otherwise reject connection.
+       //if (!priorityConnect)
+       {
+               if (!isPrivate())
+                       if (servMgr->pubInFull())
+                               throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+       }
+
+       if (!versionValid)
+               throw HTTPException(HTTP_SC_FORBIDDEN,403);
+
+    sock->writeLine(GNU_OK);
+
+    sock->writeLineF("%s %s",HTTP_HS_AGENT,PCX_OLDAGENT);
+
+       if (networkID.isSet())
+       {
+               char idStr[64];
+               networkID.toStr(idStr);
+               sock->writeLineF("%s %s",PCX_HS_NETWORKID,idStr);
+       }
+
+       if (servMgr->isRoot)
+       {
+               sock->writeLineF("%s %d",PCX_HS_FLOWCTL,servMgr->useFlowControl?1:0);
+               sock->writeLineF("%s %d",PCX_HS_MINBCTTL,chanMgr->minBroadcastTTL);
+               sock->writeLineF("%s %d",PCX_HS_MAXBCTTL,chanMgr->maxBroadcastTTL);
+               sock->writeLineF("%s %d",PCX_HS_RELAYBC,servMgr->relayBroadcast);
+               //sock->writeLine("%s %d",PCX_HS_FULLHIT,2);
+
+
+               if (diffRootVer)
+               {
+                       sock->writeString(PCX_HS_DL);
+                       sock->writeLine(PCX_DL_URL);
+               }
+
+               sock->writeLineF("%s %s",PCX_HS_MSG,servMgr->rootMsg.cstr());
+       }
+
+
+       char hostIP[64];
+       Host h = sock->host;
+       h.IPtoStr(hostIP);
+    sock->writeLineF("%s %s",PCX_HS_REMOTEIP,hostIP);
+
+
+    sock->writeLine("");
+
+
+       while (http.nextHeader());
+}
+
+// -----------------------------------
+bool   Servent::pingHost(Host &rhost,GnuID &rsid)
+{
+       char ipstr[64];
+       rhost.toStr(ipstr);
+       LOG_DEBUG("Ping host %s: trying..",ipstr);
+       ClientSocket *s=NULL;
+       bool hostOK=false;
+       try
+       {
+               s = sys->createSocket();
+               if (!s)
+                       return false;
+               else
+               {
+
+                       s->setReadTimeout(15000);
+                       s->setWriteTimeout(15000);
+                       s->open(rhost);
+                       s->connect();
+
+                       AtomStream atom(*s);
+
+                       atom.writeInt(PCP_CONNECT,1);
+                       atom.writeParent(PCP_HELO,1);
+                               atom.writeBytes(PCP_HELO_SESSIONID,servMgr->sessionID.id,16);
+
+                       GnuID sid;
+                       sid.clear();
+
+                       int numc,numd;
+                       ID4 id = atom.read(numc,numd);
+                       if (id == PCP_OLEH)
+                       {
+                               for(int i=0; i<numc; i++)
+                               {
+                                       int c,d;
+                                       ID4 pid = atom.read(c,d);
+                                       if (pid == PCP_SESSIONID)
+                                               atom.readBytes(sid.id,16,d);
+                                       else
+                                               atom.skip(c,d);
+                               }
+                       }else
+                       {
+                               LOG_DEBUG("Ping response: %s",id.getString().str());
+                               throw StreamException("Bad ping response");
+                       }
+
+                       if (!sid.isSame(rsid))
+                               throw StreamException("SIDs don`t match");
+
+                       hostOK = true;
+                       LOG_DEBUG("Ping host %s: OK",ipstr);
+                       atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT);
+
+
+               }
+       }catch(StreamException &e)
+       {
+               LOG_DEBUG("Ping host %s: %s",ipstr,e.msg);
+       }
+       if (s)
+       {
+               s->close();
+               delete s;
+       }
+
+       if (!hostOK)
+               rhost.port = 0;
+
+       return true;
+}
+
+WLock canStreamLock;
+
+// -----------------------------------
+bool Servent::handshakeStream(ChanInfo &chanInfo)
+{
+
+       HTTP http(*sock);
+
+
+       bool gotPCP=false;
+       unsigned int reqPos=0;
+
+       nsSwitchNum=0;
+
+       while (http.nextHeader())
+       {
+               char *arg = http.getArgStr();
+               if (!arg)
+                       continue;
+
+               if (http.isHeader(PCX_HS_PCP))
+                       gotPCP = atoi(arg)!=0;
+               else if (http.isHeader(PCX_HS_POS))
+                       reqPos = atoi(arg);
+               else if (http.isHeader("icy-metadata"))
+                       addMetadata = atoi(arg) > 0;
+               else if (http.isHeader(HTTP_HS_AGENT))
+                       agent = arg;
+               else if (http.isHeader("Pragma"))
+               {
+                       char *ssc = stristr(arg,"stream-switch-count=");
+                       char *so = stristr(arg,"stream-offset");
+
+                       if (ssc || so)
+                       {
+                               nsSwitchNum=1;
+                               //nsSwitchNum = atoi(ssc+20);
+                       }
+               }
+
+               LOG_DEBUG("Stream: %s",http.cmdLine);
+       }
+
+
+       if ((!gotPCP) && (outputProtocol == ChanInfo::SP_PCP))
+               outputProtocol = ChanInfo::SP_PEERCAST;
+
+       if (outputProtocol == ChanInfo::SP_HTTP)
+       {
+               if  ( (chanInfo.srcProtocol == ChanInfo::SP_MMS)
+                         || (chanInfo.contentType == ChanInfo::T_WMA)
+                         || (chanInfo.contentType == ChanInfo::T_WMV)
+                         || (chanInfo.contentType == ChanInfo::T_ASX)
+                       )
+               outputProtocol = ChanInfo::SP_MMS;
+       }
+
+
+       bool chanFound=false;
+       bool chanReady=false;
+
+       Channel *ch = chanMgr->findChannelByID(chanInfo.id);
+       if (ch)
+       {
+               sendHeader = true;
+//             if (reqPos)
+//             {
+//                     streamPos = ch->rawData.findOldestPos(reqPos);
+//             }else
+//             {
+                       streamPos = ch->rawData.getLatestPos();
+//             }
+
+               chanID = chanInfo.id;
+               canStreamLock.on();
+               chanReady = canStream(ch);
+               if (!chanReady) type = T_INCOMING;
+               thread.active = chanReady;
+               setStatus(S_CONNECTED);
+               canStreamLock.off();
+               channel_id = ch->channel_id;
+
+               //JP-Patch add-s
+               if (servMgr->isCheckPushStream())
+               {
+                       if (chanReady == true)
+                       {
+                               Host h = getHost();
+
+                               if (!h.isLocalhost()) 
+                               {
+                                       do 
+                                       {
+                                               if (strstr(agent.cstr(),"PeerCast/0.119") != NULL) 
+                                               {                                               
+                                                       char strip[256];
+                                                       h.toStr(strip);
+                                                       LOG_ERROR("Block v0.119 Servent : %s (%s)",strip,agent.cstr());
+                                                       chanReady = false;
+                                                       break;
+                                               }
+
+/*                                             ChanHitList *hits[ChanMgr::MAX_HITLISTS];
+                                               int numHits=0;
+                                               for(int i=0; i<ChanMgr::MAX_HITLISTS; i++)
+                                               {
+                                                       ChanHitList *chl = &chanMgr->hitlists[i];
+                                                       if (chl->isUsed())
+                                                               hits[numHits++] = chl;
+                                               }
+                                               bool isfw = false;
+                                               int numRelay = 0;
+                                               for(int i=0; i<numHits; i++)
+                                               {
+                                                       ChanHitList *chl = hits[i];
+                                                       if (chl->isUsed())
+                                                       {
+                                                               for (int j=0; j<ChanHitList::MAX_HITS; j++)
+                                                               {
+                                                                       ChanHit *hit = &chl->hits[j];
+                                                                       if (hit->host.isValid() && (h.ip == hit->host.ip)) 
+                                                                       {
+                                                                               if (hit->firewalled)
+                                                                                       isfw = true;
+                                                                               numRelay = hit->numRelays;
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                               if ((isfw == true) && (numRelay == 0))
+                                               {
+                                                       char strip[256];
+                                                       h.toStr(strip);
+                                                       LOG_ERROR("Block firewalled Servent : %s",strip);
+                                                       chanReady = false;
+                                               }*/
+
+                                               ChanHitList *chl = chanMgr->findHitList(chanInfo);
+                                               ChanHit *hit = chl->hit;
+                                               while(hit){
+                                                       if (hit->host.isValid() && (h.ip == hit->host.ip))
+                                                       {
+                                                               if ((hit->firewalled) && (hit->numRelays == 0)){
+                                                                       char strip[256];
+                                                                       h.toStr(strip);
+                                                                       LOG_ERROR("Block firewalled Servent : %s",strip);
+                                                                       chanReady = false;
+                                                               }
+                                                       }
+                                                       hit = hit->next;
+                                               }
+                                       }while (0);
+                               }               
+                       }
+               }
+               //JP-Patch add-e
+       }
+
+//     LockBlock lockblock(chanMgr->hitlistlock);
+
+//     lockblock.lockon();
+       ChanHitList *chl = chanMgr->findHitList(chanInfo);
+
+       if (chl)
+       {
+               chanFound = true;
+       }
+
+
+       bool result = false;
+
+       char idStr[64];
+       chanInfo.id.toStr(idStr);
+
+       char sidStr[64];
+       servMgr->sessionID.toStr(sidStr);
+
+       Host rhost = sock->host;
+
+
+
+
+       AtomStream atom(*sock);
+
+
+
+       if (!chanFound)
+       {
+               sock->writeLine(HTTP_SC_NOTFOUND);
+           sock->writeLine("");
+               LOG_DEBUG("Sending channel not found");
+               return false;
+       }
+
+
+       if (!chanReady)
+       {
+               if (outputProtocol == ChanInfo::SP_PCP)
+               {
+
+                       char tbuf[8196];
+                       MemoryStream mem(tbuf, sizeof(tbuf));
+                       mem.writeLine(HTTP_SC_UNAVAILABLE);
+                       mem.writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XPCP);
+                       mem.writeLine("");
+                       sock->write(tbuf, mem.getPosition());
+
+                       handshakeIncomingPCP(atom,rhost,remoteID,agent);
+
+                       char ripStr[64];
+                       rhost.toStr(ripStr);
+
+                       LOG_DEBUG("Sending channel unavailable");
+
+                       ChanHitSearch chs;
+
+                       mem.rewind();
+                       AtomStream atom2(mem);
+
+                       int error = PCP_ERROR_QUIT+PCP_ERROR_UNAVAILABLE;
+
+                       chanMgr->hitlistlock.on();
+
+                       chl = chanMgr->findHitList(chanInfo);
+
+                       if (chl)
+                       {
+                               ChanHit best;
+                               
+                               // search for up to 8 other hits
+                               int cnt=0;
+                               for(int i=0; i<8; i++)
+                               {
+                                       best.init();
+
+
+                                       // find best hit this network if local IP
+                                       if (!rhost.globalIP())
+                                       {
+                                               chs.init();
+                                               chs.matchHost = servMgr->serverHost;
+                                               chs.waitDelay = 2;
+                                               chs.excludeID = remoteID;
+                                               if (chl->pickHits(chs)){
+                                                       best = chs.best[0];
+                                                       LOG_DEBUG("find best hit this network if local IP");
+                                               }
+                                       }
+
+                                       // find best hit on same network
+                                       if (!best.host.ip)
+                                       {
+                                               chs.init();
+                                               chs.matchHost = rhost;
+                                               chs.waitDelay = 2;
+                                               chs.excludeID = remoteID;
+                                               if (chl->pickHits(chs)){
+                                                       best = chs.best[0];
+                                                       LOG_DEBUG("find best hit on same network");
+                                               }
+
+                                       }
+
+                                       // find best hit on other networks
+/*                                     if (!best.host.ip)
+                                       {
+                                               chs.init();
+                                               chs.waitDelay = 2;
+                                               chs.excludeID = remoteID;
+                                               if (chl->pickHits(chs)){
+                                                       best = chs.best[0];
+                                                       LOG_DEBUG("find best hit on other networks");
+                                               }
+
+                                       }*/
+                                       
+                                       if (!best.host.ip)
+                                               break;
+
+                                       best.writeAtoms(atom2,chanInfo.id);                             
+                                       cnt++;
+                               }
+
+                               if (!best.host.ip){
+                                       char tmp[50];
+//                                     chanMgr->hitlistlock.on();
+                                       int cnt = chs.getRelayHost(servMgr->serverHost, rhost, remoteID, chl);
+//                                     chanMgr->hitlistlock.off();
+                                       for (int i = 0; i < cnt; i++){
+                                               chs.best[i].writeAtoms(atom2, chanInfo.id);
+                                               chs.best[i].host.toStr(tmp);
+                                               LOG_DEBUG("relay info: %s hops = %d", tmp, chs.best[i].numHops);
+                                               best.host.ip = chs.best[i].host.ip;
+                                       }
+                               }
+
+                               if (cnt)
+                               {
+                                       LOG_DEBUG("Sent %d channel hit(s) to %s",cnt,ripStr);
+
+                               }
+                               else if (rhost.port)
+                               {
+                                       // find firewalled host
+                                       chs.init();
+                                       chs.waitDelay = 30;
+                                       chs.useFirewalled = true;
+                                       chs.excludeID = remoteID;
+                                       if (chl->pickHits(chs))
+                                       {
+                                               best = chs.best[0];
+                                               int cnt = servMgr->broadcastPushRequest(best,rhost,chl->info.id,Servent::T_RELAY);
+                                               LOG_DEBUG("Broadcasted channel push request to %d clients for %s",cnt,ripStr);
+                                       }
+                               } 
+
+                               // if all else fails, use tracker
+                               if (!best.host.ip)
+                               {
+                                       // find best tracker on this network if local IP
+                                       if (!rhost.globalIP())
+                                       {
+                                               chs.init();
+                                               chs.matchHost = servMgr->serverHost;
+                                               chs.trackersOnly = true;
+                                               chs.excludeID = remoteID;
+                                               if (chl->pickHits(chs))
+                                                       best = chs.best[0];
+
+                                       }
+
+                                       // find local tracker
+                                       if (!best.host.ip)
+                                       {
+                                               chs.init();
+                                               chs.matchHost = rhost;
+                                               chs.trackersOnly = true;
+                                               chs.excludeID = remoteID;
+                                               if (chl->pickHits(chs))
+                                                       best = chs.best[0];
+                                       }
+
+                                       // find global tracker
+                                       if (!best.host.ip)
+                                       {
+                                               chs.init();
+                                               chs.trackersOnly = true;
+                                               chs.excludeID = remoteID;
+                                               if (chl->pickHits(chs))
+                                                       best = chs.best[0];
+                                       }
+
+                                       if (best.host.ip)
+                                       {
+                                               best.writeAtoms(atom2,chanInfo.id);                             
+                                               LOG_DEBUG("Sent 1 tracker hit to %s",ripStr);
+                                       }else if (rhost.port)
+                                       {
+                                               // find firewalled tracker
+                                               chs.init();
+                                               chs.useFirewalled = true;
+                                               chs.trackersOnly = true;
+                                               chs.excludeID = remoteID;
+                                               chs.waitDelay = 30;
+                                               if (chl->pickHits(chs))
+                                               {
+                                                       best = chs.best[0];
+                                                       int cnt = servMgr->broadcastPushRequest(best,rhost,chl->info.id,Servent::T_CIN);
+                                                       LOG_DEBUG("Broadcasted tracker push request to %d clients for %s",cnt,ripStr);
+                                               }
+                                       }
+
+                               }
+
+
+                       }
+
+                       chanMgr->hitlistlock.off();
+
+                       // return not available yet code
+                       atom2.writeInt(PCP_QUIT,error);
+                       sock->write(tbuf, mem.getPosition());
+                       result = false;
+
+                       /*
+                       char c[512];
+                       // wait disconnect from other host
+                       try{
+                               while(sock->read(c, sizeof(c))){
+                                       sys->sleep(10);
+                               }
+                       }catch(StreamException &e){
+                               LOG_DEBUG("RelayInfoWait: %s",e.msg);
+                       }
+                       */
+               }else
+               {
+                       LOG_DEBUG("Sending channel unavailable");
+                       sock->writeLine(HTTP_SC_UNAVAILABLE);
+                       sock->writeLine("");
+                       result = false;
+               }
+
+       } else {
+
+               if (chanInfo.contentType != ChanInfo::T_MP3)
+                       addMetadata=false;
+
+               if (addMetadata && (outputProtocol == ChanInfo::SP_HTTP))               // winamp mp3 metadata check
+               {
+
+                       sock->writeLine(ICY_OK);
+
+                       sock->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT);
+                       sock->writeLineF("icy-name:%s",chanInfo.name.cstr());
+                       sock->writeLineF("icy-br:%d",chanInfo.bitrate);
+                       sock->writeLineF("icy-genre:%s",chanInfo.genre.cstr());
+                       sock->writeLineF("icy-url:%s",chanInfo.url.cstr());
+                       sock->writeLineF("icy-metaint:%d",chanMgr->icyMetaInterval);
+                       sock->writeLineF("%s %s",PCX_HS_CHANNELID,idStr);
+
+                       sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MP3);
+
+               }else
+               {
+
+                       sock->writeLine(HTTP_SC_OK);
+
+                       if ((chanInfo.contentType != ChanInfo::T_ASX) && (chanInfo.contentType != ChanInfo::T_WMV) && (chanInfo.contentType != ChanInfo::T_WMA))
+                       {
+                               sock->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT);
+
+                               sock->writeLine("Accept-Ranges: none");
+
+                               sock->writeLineF("x-audiocast-name: %s",chanInfo.name.cstr());
+                               sock->writeLineF("x-audiocast-bitrate: %d",chanInfo.bitrate);
+                               sock->writeLineF("x-audiocast-genre: %s",chanInfo.genre.cstr());
+                               sock->writeLineF("x-audiocast-description: %s",chanInfo.desc.cstr());
+                               sock->writeLineF("x-audiocast-url: %s",chanInfo.url.cstr());
+                               sock->writeLineF("%s %s",PCX_HS_CHANNELID,idStr);
+                       }
+
+
+                       if (outputProtocol == ChanInfo::SP_HTTP)
+                       {
+                               switch (chanInfo.contentType)
+                               {
+                                       case ChanInfo::T_OGG:
+                                               sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XOGG);
+                                               break;
+                                       case ChanInfo::T_MP3:
+                                               sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MP3);
+                                               break;
+                                       case ChanInfo::T_MOV:
+                                               sock->writeLine("Connection: close");
+                                               sock->writeLine("Content-Length: 10000000");
+                                               sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MOV);
+                                               break;
+                                       case ChanInfo::T_MPG:
+                                               sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MPG);
+                                               break;
+                                       case ChanInfo::T_NSV:
+                                               sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_NSV);
+                                               break;
+                                       case ChanInfo::T_ASX:
+                                               sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_ASX);
+                                               break;
+                                       case ChanInfo::T_WMA:
+                                               sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_WMA);
+                                               break;
+                                       case ChanInfo::T_WMV:
+                                               sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_WMV);
+                                               break;
+                               }
+                       } else if (outputProtocol == ChanInfo::SP_MMS)
+                       {
+                               sock->writeLine("Server: Rex/9.0.0.2980");
+                               sock->writeLine("Cache-Control: no-cache");
+                               sock->writeLine("Pragma: no-cache");
+                               sock->writeLine("Pragma: client-id=3587303426");
+                               sock->writeLine("Pragma: features=\"broadcast,playlist\"");
+
+                               if (nsSwitchNum)
+                               {
+                                       sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MMS);
+                               }else
+                               {
+                                       sock->writeLine("Content-Type: application/vnd.ms.wms-hdr.asfv1");
+                                       if (ch)
+                                               sock->writeLineF("Content-Length: %d",ch->headPack.len);
+                                       sock->writeLine("Connection: Keep-Alive");
+                               }
+                       
+                       } else if (outputProtocol == ChanInfo::SP_PCP)
+                       {
+                               sock->writeLineF("%s %d",PCX_HS_POS,streamPos);
+                               sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XPCP);
+
+                       }else if (outputProtocol == ChanInfo::SP_PEERCAST)
+                       {
+                               sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XPEERCAST);
+                       }
+               }
+               sock->writeLine("");
+               result = true;
+
+               if (gotPCP)
+               {
+                       handshakeIncomingPCP(atom,rhost,remoteID,agent);
+                       atom.writeInt(PCP_OK,0);
+               }
+
+       }
+
+
+
+       return result;
+}
+
+// -----------------------------------
+void Servent::handshakeGiv(GnuID &id)
+{
+       if (id.isSet())
+       {
+               char idstr[64];
+               id.toStr(idstr);
+               sock->writeLineF("GIV /%s",idstr);
+       }else
+               sock->writeLine("GIV");
+
+       sock->writeLine("");
+}
+
+
+// -----------------------------------
+void Servent::processGnutella()
+{
+       type = T_PGNU;
+
+       //if (servMgr->isRoot && !servMgr->needConnections())
+       if (servMgr->isRoot)
+       {
+               processRoot();
+               return;
+       }
+
+
+
+       gnuStream.init(sock);
+       setStatus(S_CONNECTED);
+
+       if (!servMgr->isRoot)
+       {
+               chanMgr->broadcastRelays(this, 1, 1);
+               GnuPacket *p;
+
+               if ((p=outPacketsNorm.curr()))  
+                       gnuStream.sendPacket(*p);
+               return;
+       }
+
+       gnuStream.ping(2);
+
+//     if (type != T_LOOKUP)
+//             chanMgr->broadcastRelays(this,chanMgr->minBroadcastTTL,2);
+
+       lastPacket = lastPing = sys->getTime();
+       bool doneBigPing=false;
+
+       const unsigned int      abortTimeoutSecs = 60;          // abort connection after 60 secs of no activitiy
+       const unsigned int      packetTimeoutSecs = 30;         // ping connection after 30 secs of no activity
+
+       unsigned int currBytes=0;
+       unsigned int lastWait=0;
+
+       unsigned int lastTotalIn=0,lastTotalOut=0;
+
+       while (thread.active && sock->active())
+       {
+
+               if (sock->readReady())
+               {
+                       lastPacket = sys->getTime();
+
+                       if (gnuStream.readPacket(pack))
+                       {
+                               char ipstr[64];
+                               sock->host.toStr(ipstr);
+
+                               GnuID routeID;
+                               GnuStream::R_TYPE ret = GnuStream::R_PROCESS;
+
+                               if (pack.func != GNU_FUNC_PONG)
+                                       if (servMgr->seenPacket(pack))
+                                               ret = GnuStream::R_DUPLICATE;
+
+                               seenIDs.add(pack.id);
+
+
+                               if (ret == GnuStream::R_PROCESS)
+                               {
+                                       GnuID routeID;
+                                       ret = gnuStream.processPacket(pack,this,routeID);
+
+                                       if (flowControl && (ret == GnuStream::R_BROADCAST))
+                                               ret = GnuStream::R_DROP;
+
+                               }
+
+                               switch(ret)
+                               {
+                                       case GnuStream::R_BROADCAST:
+                                               if (servMgr->broadcast(pack,this))
+                                                       stats.add(Stats::NUMBROADCASTED);
+                                               else
+                                                       stats.add(Stats::NUMDROPPED);
+                                               break;
+                                       case GnuStream::R_ROUTE:
+                                               if (servMgr->route(pack,routeID,NULL))
+                                                       stats.add(Stats::NUMROUTED);
+                                               else
+                                                       stats.add(Stats::NUMDROPPED);
+                                               break;
+                                       case GnuStream::R_ACCEPTED:
+                                               stats.add(Stats::NUMACCEPTED);
+                                               break;
+                                       case GnuStream::R_DUPLICATE:
+                                               stats.add(Stats::NUMDUP);
+                                               break;
+                                       case GnuStream::R_DEAD:
+                                               stats.add(Stats::NUMDEAD);
+                                               break;
+                                       case GnuStream::R_DISCARD:
+                                               stats.add(Stats::NUMDISCARDED);
+                                               break;
+                                       case GnuStream::R_BADVERSION:
+                                               stats.add(Stats::NUMOLD);
+                                               break;
+                                       case GnuStream::R_DROP:
+                                               stats.add(Stats::NUMDROPPED);
+                                               break;
+                               }
+
+
+                               LOG_NETWORK("packet in: %s-%s, %d bytes, %d hops, %d ttl, from %s",GNU_FUNC_STR(pack.func),GnuStream::getRouteStr(ret),pack.len,pack.hops,pack.ttl,ipstr);
+
+
+
+                       }else{
+                               LOG_ERROR("Bad packet");
+                       }
+               }
+
+
+               GnuPacket *p;
+
+               if ((p=outPacketsPri.curr()))                           // priority packet
+               {
+                       gnuStream.sendPacket(*p);
+                       seenIDs.add(p->id);
+                       outPacketsPri.next();
+               } else if ((p=outPacketsNorm.curr()))           // or.. normal packet
+               {
+                       gnuStream.sendPacket(*p);
+                       seenIDs.add(p->id);
+                       outPacketsNorm.next();
+               }
+
+               int lpt =  sys->getTime()-lastPacket;
+
+               if (!doneBigPing)
+               {
+                       if ((sys->getTime()-lastPing) > 15)
+                       {
+                               gnuStream.ping(7);
+                               lastPing = sys->getTime();
+                               doneBigPing = true;
+                       }
+               }else{
+                       if (lpt > packetTimeoutSecs)
+                       {
+                               
+                               if ((sys->getTime()-lastPing) > packetTimeoutSecs)
+                               {
+                                       gnuStream.ping(1);
+                                       lastPing = sys->getTime();
+                               }
+
+                       }
+               }
+               if (lpt > abortTimeoutSecs)
+                       throw TimeoutException();
+
+
+               unsigned int totIn = sock->totalBytesIn-lastTotalIn;
+               unsigned int totOut = sock->totalBytesOut-lastTotalOut;
+
+               unsigned int bytes = totIn+totOut;
+
+               lastTotalIn = sock->totalBytesIn;
+               lastTotalOut = sock->totalBytesOut;
+
+               const int serventBandwidth = 1000;
+
+               int delay = sys->idleSleepTime;
+               if ((bytes) && (serventBandwidth >= 8))
+                       delay = (bytes*1000)/(serventBandwidth/8);      // set delay relative packetsize
+
+               if (delay < (int)sys->idleSleepTime)
+                       delay = sys->idleSleepTime;
+               //LOG("delay %d, in %d, out %d",delay,totIn,totOut);
+
+               sys->sleep(delay);
+       }
+
+}
+
+
+// -----------------------------------
+void Servent::processRoot()
+{
+       try 
+       {
+       
+               gnuStream.init(sock);
+               setStatus(S_CONNECTED);
+
+               gnuStream.ping(2);
+
+               unsigned int lastConnect = sys->getTime();
+
+               while (thread.active && sock->active())
+               {
+                       if (gnuStream.readPacket(pack))
+                       {
+                               char ipstr[64];
+                               sock->host.toStr(ipstr);
+                               
+                               LOG_NETWORK("packet in: %d from %s",pack.func,ipstr);
+
+
+                               if (pack.func == GNU_FUNC_PING)         // if ping then pong back some hosts and close
+                               {
+                                       
+                                       Host hl[32];
+                                       int cnt = servMgr->getNewestServents(hl,32,sock->host); 
+                                       if (cnt)
+                                       {
+                                               int start = sys->rnd() % cnt;
+                                               int max = cnt>8?8:cnt;
+
+                                               for(int i=0; i<max; i++)
+                                               {
+                                                       GnuPacket pong;
+                                                       pack.hops = 1;
+                                                       pong.initPong(hl[start],false,pack);
+                                                       gnuStream.sendPacket(pong);
+
+                                                       char ipstr[64];
+                                                       hl[start].toStr(ipstr);
+
+                                                       //LOG_NETWORK("Pong %d: %s",start+1,ipstr);
+                                                       start = (start+1) % cnt;
+                                               }
+                                               char str[64];
+                                               sock->host.toStr(str);
+                                               LOG_NETWORK("Sent %d pong(s) to %s",max,str);
+                                       }else
+                                       {
+                                               LOG_NETWORK("No Pongs to send");
+                                               //return;
+                                       }
+                               }else if (pack.func == GNU_FUNC_PONG)           // pong?
+                               {
+                                       MemoryStream pong(pack.data,pack.len);
+
+                                       int ip,port;
+                                       port = pong.readShort();
+                                       ip = pong.readLong();
+                                       ip = SWAP4(ip);
+
+
+                                       Host h(ip,port);
+                                       if ((ip) && (port) && (h.globalIP()))
+                                       {
+
+                                               LOG_NETWORK("added pong: %d.%d.%d.%d:%d",ip>>24&0xff,ip>>16&0xff,ip>>8&0xff,ip&0xff,port);
+                                               servMgr->addHost(h,ServHost::T_SERVENT,sys->getTime());
+                                       }
+                                       //return;
+                               } else if (pack.func == GNU_FUNC_HIT)
+                               {
+                                       MemoryStream data(pack.data,pack.len);
+                                       ChanHit hit;
+                                       gnuStream.readHit(data,hit,pack.hops,pack.id);
+                               }
+
+                               //if (gnuStream.packetsIn > 5)  // die if we get too many packets
+                               //      return;
+                       }
+
+                       if((sys->getTime()-lastConnect > 60))
+                               break;
+               }
+
+
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("Relay: %s",e.msg);
+       }
+
+       
+}      
+
+// -----------------------------------
+int Servent::givProc(ThreadInfo *thread)
+{
+//     thread->lock();
+       Servent *sv = (Servent*)thread->data;
+       try 
+       {
+               sv->handshakeGiv(sv->givID);
+               sv->handshakeIncoming();
+
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("GIV: %s",e.msg);
+       }
+
+       sv->kill();
+       sys->endThread(thread);
+       return 0;
+}
+
+// -----------------------------------
+void Servent::handshakeOutgoingPCP(AtomStream &atom, Host &rhost, GnuID &rid, String &agent, bool isTrusted)
+{
+
+       bool nonFW = (servMgr->getFirewall() != ServMgr::FW_ON);
+       bool testFW = (servMgr->getFirewall() == ServMgr::FW_UNKNOWN);
+
+       bool sendBCID = isTrusted && chanMgr->isBroadcasting();
+
+       char tbuf[1024];
+       MemoryStream mem(tbuf, sizeof(tbuf));
+       AtomStream atom2(mem);
+       atom2.writeParent(PCP_HELO,3 + (testFW?1:0) + (nonFW?1:0) + (sendBCID?1:0));
+               atom2.writeString(PCP_HELO_AGENT,PCX_AGENT);
+               atom2.writeInt(PCP_HELO_VERSION,PCP_CLIENT_VERSION);
+               atom2.writeBytes(PCP_HELO_SESSIONID,servMgr->sessionID.id,16);
+               if (nonFW)
+                       atom2.writeShort(PCP_HELO_PORT,servMgr->serverHost.port);
+               if (testFW)
+                       atom2.writeShort(PCP_HELO_PING,servMgr->serverHost.port);
+               if (sendBCID)
+                       atom2.writeBytes(PCP_HELO_BCID,chanMgr->broadcastID.id,16);
+       atom.io.write(tbuf, mem.getPosition());
+
+
+       LOG_DEBUG("PCP outgoing waiting for OLEH..");
+
+       int numc,numd;
+       ID4 id = atom.read(numc,numd);
+       if (id != PCP_OLEH)
+       {
+               LOG_DEBUG("PCP outgoing reply: %s",id.getString().str());
+               atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_BADRESPONSE);
+               throw StreamException("Got unexpected PCP response");
+       }
+
+
+
+       char arg[64];
+
+       GnuID clientID;
+       clientID.clear();
+       rid.clear();
+       int version=0;
+       int disable=0;
+
+       Host thisHost;
+
+       // read OLEH response
+       for(int i=0; i<numc; i++)
+       {
+               int c,dlen;
+               ID4 id = atom.read(c,dlen);
+
+               if (id == PCP_HELO_AGENT)
+               {
+                       atom.readString(arg,sizeof(arg),dlen);
+                       agent.set(arg);
+
+               }else if (id == PCP_HELO_REMOTEIP)
+               {
+                       thisHost.ip = atom.readInt();
+
+               }else if (id == PCP_HELO_PORT)
+               {
+                       thisHost.port = atom.readShort();
+
+               }else if (id == PCP_HELO_VERSION)
+               {
+                       version = atom.readInt();
+
+               }else if (id == PCP_HELO_DISABLE)
+               {
+                       disable = atom.readInt();
+
+               }else if (id == PCP_HELO_SESSIONID)
+               {
+                       atom.readBytes(rid.id,16);
+                       if (rid.isSame(servMgr->sessionID))
+                               throw StreamException("Servent loopback");
+
+               }else
+               {
+                       LOG_DEBUG("PCP handshake skip: %s",id.getString().str());
+                       atom.skip(c,dlen);
+               }
+
+    }
+
+
+       // update server ip/firewall status
+       if (isTrusted)
+       {
+               if (thisHost.isValid())
+               {
+                       if ((servMgr->serverHost.ip != thisHost.ip) && (servMgr->forceIP.isEmpty()))
+                       {
+                               char ipstr[64];
+                               thisHost.toStr(ipstr);
+                               LOG_DEBUG("Got new ip: %s",ipstr);
+                               servMgr->serverHost.ip = thisHost.ip;
+                       }
+
+                       if (servMgr->getFirewall() == ServMgr::FW_UNKNOWN)
+                       {
+                               if (thisHost.port && thisHost.globalIP())
+                                       servMgr->setFirewall(ServMgr::FW_OFF);
+                               else
+                                       servMgr->setFirewall(ServMgr::FW_ON);
+                       }
+               }
+
+               if (disable == 1)
+               {
+                       LOG_ERROR("client disabled: %d",disable);
+                       servMgr->isDisabled = true;             
+               }else
+               {
+                       servMgr->isDisabled = false;            
+               }
+       }
+
+
+
+       if (!rid.isSet())
+       {
+               atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_NOTIDENTIFIED);
+               throw StreamException("Remote host not identified");
+       }
+
+       LOG_DEBUG("PCP Outgoing handshake complete.");
+
+}
+
+// -----------------------------------
+void Servent::handshakeIncomingPCP(AtomStream &atom, Host &rhost, GnuID &rid, String &agent)
+{
+       int numc,numd;
+       ID4 id = atom.read(numc,numd);
+
+
+       if (id != PCP_HELO)
+       {
+               LOG_DEBUG("PCP incoming reply: %s",id.getString().str());
+               atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_BADRESPONSE);
+               throw StreamException("Got unexpected PCP response");
+       }
+
+       char arg[64];
+
+       ID4 osType;
+
+       int version=0;
+
+       int pingPort=0;
+
+       GnuID bcID;
+       GnuID clientID;
+
+       bcID.clear();
+       clientID.clear();
+
+       rhost.port = 0;
+
+       for(int i=0; i<numc; i++)
+       {
+
+               int c,dlen;
+               ID4 id = atom.read(c,dlen);
+
+               if (id == PCP_HELO_AGENT)
+               {
+                       atom.readString(arg,sizeof(arg),dlen);
+                       agent.set(arg);
+
+               }else if (id == PCP_HELO_VERSION)
+               {
+                       version = atom.readInt();
+
+               }else if (id == PCP_HELO_SESSIONID)
+               {
+                       atom.readBytes(rid.id,16);
+                       if (rid.isSame(servMgr->sessionID))
+                               throw StreamException("Servent loopback");
+
+               }else if (id == PCP_HELO_BCID)
+               {
+                       atom.readBytes(bcID.id,16);
+
+               }else if (id == PCP_HELO_OSTYPE)
+               {
+                       osType = atom.readInt();
+               }else if (id == PCP_HELO_PORT)
+               {
+                       rhost.port = atom.readShort();
+               }else if (id == PCP_HELO_PING)
+               {
+                       pingPort = atom.readShort();
+               }else
+               {
+                       LOG_DEBUG("PCP handshake skip: %s",id.getString().str());
+                       atom.skip(c,dlen);
+               }
+
+    }
+
+       if (version)
+               LOG_DEBUG("Incoming PCP is %s : v%d", agent.cstr(),version);
+
+
+       if (!rhost.globalIP() && servMgr->serverHost.globalIP())
+               rhost.ip = servMgr->serverHost.ip;
+
+       if (pingPort)
+       {
+               char ripStr[64];
+               rhost.toStr(ripStr);
+               LOG_DEBUG("Incoming firewalled test request: %s ", ripStr);
+               rhost.port = pingPort;
+               if (!rhost.globalIP() || !pingHost(rhost,rid))
+                       rhost.port = 0;
+       }
+
+       if (servMgr->isRoot)
+       {
+               if (bcID.isSet())
+               {
+                       if (bcID.getFlags() & 1)        // private
+                       {
+                               BCID *bcid = servMgr->findValidBCID(bcID);
+                               if (!bcid || (bcid && !bcid->valid))
+                               {
+                                       atom.writeParent(PCP_OLEH,1);
+                                       atom.writeInt(PCP_HELO_DISABLE,1);
+                                       throw StreamException("Client is banned");
+                               }
+                       }
+               }
+       }
+
+
+       char tbuf[1024];
+       MemoryStream mem(tbuf, sizeof(tbuf));
+       AtomStream atom2(mem);
+       atom2.writeParent(PCP_OLEH,5);
+               atom2.writeString(PCP_HELO_AGENT,PCX_AGENT);
+               atom2.writeBytes(PCP_HELO_SESSIONID,servMgr->sessionID.id,16);
+               atom2.writeInt(PCP_HELO_VERSION,PCP_CLIENT_VERSION);
+               atom2.writeInt(PCP_HELO_REMOTEIP,rhost.ip);
+               atom2.writeShort(PCP_HELO_PORT,rhost.port);
+
+       if (version)
+       {
+               if (version < PCP_CLIENT_MINVERSION)
+               {
+                       atom2.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_BADAGENT);
+                       atom.io.write(tbuf, mem.getPosition());
+                       throw StreamException("Agent is not valid");
+               }
+       }
+
+       if (!rid.isSet())
+       {
+               atom2.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_NOTIDENTIFIED);
+               atom.io.write(tbuf, mem.getPosition());
+               throw StreamException("Remote host not identified");
+       }
+
+
+
+       if (servMgr->isRoot)
+       {
+               servMgr->writeRootAtoms(atom2,false);
+       }
+
+       atom.io.write(tbuf, mem.getPosition());
+
+       LOG_DEBUG("PCP Incoming handshake complete.");
+
+}
+
+// -----------------------------------
+void Servent::processIncomingPCP(bool suggestOthers)
+{
+       PCPStream::readVersion(*sock);
+
+
+       AtomStream atom(*sock);
+       Host rhost = sock->host;
+
+       handshakeIncomingPCP(atom,rhost,remoteID,agent);
+
+
+       bool alreadyConnected = (servMgr->findConnection(Servent::T_COUT,remoteID)!=NULL)
+                                                       || (servMgr->findConnection(Servent::T_CIN,remoteID)!=NULL);
+       bool unavailable = servMgr->controlInFull();
+       bool offair = !servMgr->isRoot && !chanMgr->isBroadcasting();
+
+       char rstr[64];
+       rhost.toStr(rstr);
+
+       if (unavailable || alreadyConnected || offair)
+       {
+               int error;
+
+               if (alreadyConnected)
+                       error = PCP_ERROR_QUIT+PCP_ERROR_ALREADYCONNECTED;
+               else if (unavailable)
+                       error = PCP_ERROR_QUIT+PCP_ERROR_UNAVAILABLE;
+               else if (offair)
+                       error = PCP_ERROR_QUIT+PCP_ERROR_OFFAIR;
+               else 
+                       error = PCP_ERROR_QUIT;
+
+
+               if (suggestOthers)
+               {
+
+                       ChanHit best;
+                       ChanHitSearch chs;
+
+                       int cnt=0;
+                       for(int i=0; i<8; i++)
+                       {
+                               best.init();
+
+                               // find best hit on this network                        
+                               if (!rhost.globalIP())
+                               {
+                                       chs.init();
+                                       chs.matchHost = servMgr->serverHost;
+                                       chs.waitDelay = 2;
+                                       chs.excludeID = remoteID;
+                                       chs.trackersOnly = true;
+                                       chs.useBusyControls = false;
+                                       if (chanMgr->pickHits(chs))
+                                               best = chs.best[0];
+                               }
+
+                               // find best hit on same network                        
+                               if (!best.host.ip)
+                               {
+                                       chs.init();
+                                       chs.matchHost = rhost;
+                                       chs.waitDelay = 2;
+                                       chs.excludeID = remoteID;
+                                       chs.trackersOnly = true;
+                                       chs.useBusyControls = false;
+                                       if (chanMgr->pickHits(chs))
+                                               best = chs.best[0];
+                               }
+
+                               // else find best hit on other networks
+                               if (!best.host.ip)
+                               {
+                                       chs.init();
+                                       chs.waitDelay = 2;
+                                       chs.excludeID = remoteID;
+                                       chs.trackersOnly = true;
+                                       chs.useBusyControls = false;
+                                       if (chanMgr->pickHits(chs))
+                                               best = chs.best[0];
+                               }
+
+                               if (!best.host.ip)
+                                       break;
+                               
+                               GnuID noID;
+                               noID.clear();
+                               best.writeAtoms(atom,noID);
+                               cnt++;
+                       }
+                       if (cnt)
+                       {
+                               LOG_DEBUG("Sent %d tracker(s) to %s",cnt,rstr);
+                       }
+                       else if (rhost.port)
+                       {
+                               // send push request to best firewalled tracker on other network
+                               chs.init();
+                               chs.waitDelay = 30;
+                               chs.excludeID = remoteID;
+                               chs.trackersOnly = true;
+                               chs.useFirewalled = true;
+                               chs.useBusyControls = false;
+                               if (chanMgr->pickHits(chs))
+                               {
+                                       best = chs.best[0];
+                                       GnuID noID;
+                                       noID.clear();
+                                       int cnt = servMgr->broadcastPushRequest(best,rhost,noID,Servent::T_CIN);
+                                       LOG_DEBUG("Broadcasted tracker push request to %d clients for %s",cnt,rstr);
+                               }
+                       }else
+                       {
+                               LOG_DEBUG("No available trackers");
+                       }
+               }
+
+
+               LOG_ERROR("Sending QUIT to incoming: %d",error);
+
+               atom.writeInt(PCP_QUIT,error);
+               return;         
+       }
+       
+
+       type = T_CIN;
+       setStatus(S_CONNECTED);
+
+       atom.writeInt(PCP_OK,0);
+
+       // ask for update
+       atom.writeParent(PCP_ROOT,1);
+               atom.writeParent(PCP_ROOT_UPDATE,0);
+
+       pcpStream = new PCPStream(remoteID);
+
+       int error = 0;
+       BroadcastState bcs;
+       while (!error && thread.active && !sock->eof())
+       {
+               error = pcpStream->readPacket(*sock,bcs);
+               sys->sleepIdle();
+
+               if (!servMgr->isRoot && !chanMgr->isBroadcasting())
+                       error = PCP_ERROR_OFFAIR;
+               if (peercastInst->isQuitting)
+                       error = PCP_ERROR_SHUTDOWN;
+       }
+
+       pcpStream->flush(*sock);
+
+       error += PCP_ERROR_QUIT;
+       atom.writeInt(PCP_QUIT,error);
+
+       LOG_DEBUG("PCP Incoming to %s closed: %d",rstr,error);
+
+}
+
+// -----------------------------------
+int Servent::outgoingProc(ThreadInfo *thread)
+{
+//     thread->lock();
+       LOG_DEBUG("COUT started");
+
+       Servent *sv = (Servent*)thread->data;
+               
+       GnuID noID;
+       noID.clear();
+       sv->pcpStream = new PCPStream(noID);
+
+       while (sv->thread.active)
+       {
+               sv->setStatus(S_WAIT);
+
+               if (chanMgr->isBroadcasting() && servMgr->autoServe)
+               {
+                       ChanHit bestHit;
+                       ChanHitSearch chs;
+                       char ipStr[64];
+
+                       do
+                       {
+                               bestHit.init();
+
+                               if (servMgr->rootHost.isEmpty())
+                                       break;
+
+                               if (sv->pushSock)
+                               {
+                                       sv->sock = sv->pushSock;
+                                       sv->pushSock = NULL;
+                                       bestHit.host = sv->sock->host;
+                                       break;
+                               }
+
+                               GnuID noID;
+                               noID.clear();
+                               ChanHitList *chl = chanMgr->findHitListByID(noID);
+                               if (chl)
+                               {
+                                       // find local tracker
+                                       chs.init();
+                                       chs.matchHost = servMgr->serverHost;
+                                       chs.waitDelay = MIN_TRACKER_RETRY;
+                                       chs.excludeID = servMgr->sessionID;
+                                       chs.trackersOnly = true;
+                                       if (!chl->pickHits(chs))
+                                       {
+                                               // else find global tracker
+                                               chs.init();
+                                               chs.waitDelay = MIN_TRACKER_RETRY;
+                                               chs.excludeID = servMgr->sessionID;
+                                               chs.trackersOnly = true;
+                                               chl->pickHits(chs);
+                                       }
+
+                                       if (chs.numResults)
+                                       {
+                                               bestHit = chs.best[0];
+                                       }
+                               }
+
+
+                               unsigned int ctime = sys->getTime();
+
+                               if ((!bestHit.host.ip) && ((ctime-chanMgr->lastYPConnect) > MIN_YP_RETRY))
+                               {
+                                       bestHit.host.fromStrName(servMgr->rootHost.cstr(),DEFAULT_PORT);
+                                       bestHit.yp = true;
+                                       chanMgr->lastYPConnect = ctime;
+                               }
+                               sys->sleepIdle();
+
+                       }while (!bestHit.host.ip && (sv->thread.active));
+
+
+                       if (!bestHit.host.ip)           // give up
+                       {
+                               LOG_ERROR("COUT giving up");
+                               break;
+                       }
+
+
+                       bestHit.host.toStr(ipStr);
+
+                       int error=0;
+                       try 
+                       {
+
+                               LOG_DEBUG("COUT to %s: Connecting..",ipStr);
+
+                               if (!sv->sock)
+                               {
+                                       sv->setStatus(S_CONNECTING);
+                                       sv->sock = sys->createSocket();
+                                       if (!sv->sock)
+                                               throw StreamException("Unable to create socket");
+                                       sv->sock->open(bestHit.host);
+                                       sv->sock->connect();
+
+                               }
+
+                               sv->sock->setReadTimeout(30000);
+                               AtomStream atom(*sv->sock);
+
+                               sv->setStatus(S_HANDSHAKE);
+
+                               Host rhost = sv->sock->host;
+                               atom.writeInt(PCP_CONNECT,1);
+                               handshakeOutgoingPCP(atom,rhost,sv->remoteID,sv->agent,bestHit.yp);
+
+                               sv->setStatus(S_CONNECTED);
+
+                               LOG_DEBUG("COUT to %s: OK",ipStr);
+
+                               sv->pcpStream->init(sv->remoteID);
+
+                               BroadcastState bcs;
+                               bcs.servent_id = sv->servent_id;
+                               error = 0;
+                               while (!error && sv->thread.active && !sv->sock->eof() && servMgr->autoServe)
+                               {
+                                       error = sv->pcpStream->readPacket(*sv->sock,bcs);
+
+                                       sys->sleepIdle();
+
+                                       if (!chanMgr->isBroadcasting())
+                                               error = PCP_ERROR_OFFAIR;
+                                       if (peercastInst->isQuitting)
+                                               error = PCP_ERROR_SHUTDOWN;
+
+                                       if (sv->pcpStream->nextRootPacket)
+                                               if (sys->getTime() > (sv->pcpStream->nextRootPacket+30))
+                                                       error = PCP_ERROR_NOROOT;
+                               }
+                               sv->setStatus(S_CLOSING);
+
+                               sv->pcpStream->flush(*sv->sock);
+
+                               error += PCP_ERROR_QUIT;
+                               atom.writeInt(PCP_QUIT,error);
+
+                               LOG_ERROR("COUT to %s closed: %d",ipStr,error);
+
+                       }catch(TimeoutException &e)
+                       {
+                               LOG_ERROR("COUT to %s: timeout (%s)",ipStr,e.msg);
+                               sv->setStatus(S_TIMEOUT);
+                       }catch(StreamException &e)
+                       {
+                               LOG_ERROR("COUT to %s: %s",ipStr,e.msg);
+                               sv->setStatus(S_ERROR);
+                       }
+
+                       try
+                       {
+                               if (sv->sock)
+                               {
+                                       sv->sock->close();
+                                       delete sv->sock;
+                                       sv->sock = NULL;
+                               }
+
+                       }catch(StreamException &) {}
+
+                       // don`t discard this hit if we caused the disconnect (stopped broadcasting)
+                       if (error != (PCP_ERROR_QUIT+PCP_ERROR_OFFAIR))
+                               chanMgr->deadHit(bestHit);
+
+               }
+
+               sys->sleepIdle();
+       }
+
+       sv->kill();
+       sys->endThread(thread);
+       LOG_DEBUG("COUT ended");
+       return 0;
+}
+// -----------------------------------
+int Servent::incomingProc(ThreadInfo *thread)
+{
+//     thread->lock();
+
+       Servent *sv = (Servent*)thread->data;
+       
+       char ipStr[64];
+       sv->sock->host.toStr(ipStr);
+
+       try 
+       {
+               sv->handshakeIncoming();
+       }catch(HTTPException &e)
+       {
+               try
+               {
+                       sv->sock->writeLine(e.msg);
+                       if (e.code == 401)
+                               sv->sock->writeLine("WWW-Authenticate: Basic realm=\"PeerCast\"");
+                       sv->sock->writeLine("");
+               }catch(StreamException &){}
+               LOG_ERROR("Incoming from %s: %s",ipStr,e.msg);
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("Incoming from %s: %s",ipStr,e.msg);
+       }
+
+
+       sv->kill();
+       sys->endThread(thread);
+       return 0;
+}
+// -----------------------------------
+void Servent::processServent()
+{
+       setStatus(S_HANDSHAKE);
+
+       handshakeIn();
+
+       if (!sock)
+               throw StreamException("Servent has no socket");
+
+       processGnutella();
+}
+
+// -----------------------------------
+void Servent::processStream(bool doneHandshake,ChanInfo &chanInfo)
+{      
+       if (!doneHandshake)
+       {
+               setStatus(S_HANDSHAKE);
+
+               if (!handshakeStream(chanInfo))
+                       return;
+       }
+
+       if (chanInfo.id.isSet())
+       {
+
+               chanID = chanInfo.id;
+
+               LOG_CHANNEL("Sending channel: %s ",ChanInfo::getProtocolStr(outputProtocol));
+
+               if (!waitForChannelHeader(chanInfo))
+                       throw StreamException("Channel not ready");
+
+               servMgr->totalStreams++;
+
+               Host host = sock->host;
+               host.port = 0;  // force to 0 so we ignore the incoming port
+
+               Channel *ch = chanMgr->findChannelByID(chanID);
+               if (!ch)
+                       throw StreamException("Channel not found");
+
+               if (outputProtocol == ChanInfo::SP_HTTP)
+               {
+                       if ((addMetadata) && (chanMgr->icyMetaInterval))
+                               sendRawMetaChannel(chanMgr->icyMetaInterval);
+                       else 
+                               sendRawChannel(true,true);
+
+               }else if (outputProtocol == ChanInfo::SP_MMS)
+               {
+                       if (nsSwitchNum)
+                       {
+                               sendRawChannel(true,true);
+                       }else
+                       {
+                               sendRawChannel(true,false);
+                       }
+
+               }else if (outputProtocol  == ChanInfo::SP_PCP)
+               {
+                       sendPCPChannel();
+
+               } else if (outputProtocol  == ChanInfo::SP_PEERCAST)
+               {
+                       sendPeercastChannel();
+               }
+       }
+
+       setStatus(S_CLOSING);
+}
+
+// -----------------------------------------
+#if 0
+// debug
+               FileStream file;
+               file.openReadOnly("c://test.mp3");
+
+               LOG_DEBUG("raw file read");
+               char buf[4000];
+               int cnt=0;
+               while (!file.eof())
+               {
+                       LOG_DEBUG("send %d",cnt++);
+                       file.read(buf,sizeof(buf));
+                       sock->write(buf,sizeof(buf));
+
+               }
+               file.close();
+               LOG_DEBUG("raw file sent");
+
+       return;
+// debug
+#endif
+// -----------------------------------
+bool Servent::waitForChannelHeader(ChanInfo &info)
+{
+       for(int i=0; i<30*10; i++)
+       {
+               Channel *ch = chanMgr->findChannelByID(info.id);
+               if (!ch)
+                       return false;
+
+               if (ch->isPlaying() && (ch->rawData.writePos>0))
+                       return true;
+
+               if (!thread.active || !sock->active())
+                       break;
+               sys->sleep(100);
+       }
+       return false;
+}
+// -----------------------------------
+void Servent::sendRawChannel(bool sendHead, bool sendData)
+{
+       try
+       {
+
+               sock->setWriteTimeout(DIRECT_WRITE_TIMEOUT*1000);
+
+               Channel *ch = chanMgr->findChannelByID(chanID);
+               if (!ch)
+                       throw StreamException("Channel not found");
+
+               setStatus(S_CONNECTED);
+
+               LOG_DEBUG("Starting Raw stream of %s at %d",ch->info.name.cstr(),streamPos);
+
+               if (sendHead)
+               {
+                       ch->headPack.writeRaw(*sock);
+                       streamPos = ch->headPack.pos + ch->headPack.len;
+                       LOG_DEBUG("Sent %d bytes header ",ch->headPack.len);
+               }
+
+               if (sendData)
+               {
+
+                       unsigned int streamIndex = ch->streamIndex;
+                       unsigned int connectTime = sys->getTime();
+                       unsigned int lastWriteTime = connectTime;
+
+                       while ((thread.active) && sock->active())
+                       {
+                               ch = chanMgr->findChannelByID(chanID);
+
+                               if (ch)
+                               {
+
+                                       if (streamIndex != ch->streamIndex)
+                                       {
+                                               streamIndex = ch->streamIndex;
+                                               streamPos = ch->headPack.pos;
+                                               LOG_DEBUG("sendRaw got new stream index");
+                                       }
+
+                                       ChanPacket rawPack;
+                                       if (ch->rawData.findPacket(streamPos,rawPack))
+                                       {
+                                               if (syncPos != rawPack.sync)
+                                                       LOG_ERROR("Send skip: %d",rawPack.sync-syncPos);
+                                               syncPos = rawPack.sync+1;
+
+                                               if ((rawPack.type == ChanPacket::T_DATA) || (rawPack.type == ChanPacket::T_HEAD))
+                                               {
+                                                       rawPack.writeRaw(*sock);
+                                                       lastWriteTime = sys->getTime();
+                                               }
+
+                                               if (rawPack.pos < streamPos)
+                                                       LOG_DEBUG("raw: skip back %d",rawPack.pos-streamPos);
+                                               streamPos = rawPack.pos+rawPack.len;
+                                       } else if (sock->readReady()) {
+                                               char c;
+                                               int error = sock->readUpto(&c, 1);
+                                               if (error == 0) sock->close();
+                                       }
+                               }
+
+                               if ((sys->getTime()-lastWriteTime) > DIRECT_WRITE_TIMEOUT)
+                                       throw TimeoutException();
+
+                               sys->sleepIdle();
+                       }
+               }
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("Stream channel: %s",e.msg);
+       }
+}
+
+#if 0
+// -----------------------------------
+void Servent::sendRawMultiChannel(bool sendHead, bool sendData)
+{
+       try
+       {
+               unsigned int chanStreamIndex[ChanMgr::MAX_CHANNELS];
+               unsigned int chanStreamPos[ChanMgr::MAX_CHANNELS];
+               GnuID chanIDs[ChanMgr::MAX_CHANNELS];
+               int numChanIDs=0;
+               for(int i=0; i<ChanMgr::MAX_CHANNELS; i++)
+               {
+                       Channel *ch = &chanMgr->channels[i];
+                       if (ch->isPlaying())
+                               chanIDs[numChanIDs++]=ch->info.id;
+               }
+
+
+
+               setStatus(S_CONNECTED);
+
+
+               if (sendHead)
+               {
+                       for(int i=0; i<numChanIDs; i++)
+                       {
+                               Channel *ch = chanMgr->findChannelByID(chanIDs[i]);
+                               if (ch)
+                               {
+                                       LOG_DEBUG("Starting RawMulti stream: %s",ch->info.name.cstr());
+                                       ch->headPack.writeRaw(*sock);
+                                       chanStreamPos[i] = ch->headPack.pos + ch->headPack.len;
+                                       chanStreamIndex[i] = ch->streamIndex;
+                                       LOG_DEBUG("Sent %d bytes header",ch->headPack.len);
+
+                               }
+                       }
+               }
+
+               if (sendData)
+               {
+
+                       unsigned int connectTime=sys->getTime();
+
+                       while ((thread.active) && sock->active())
+                       {
+
+                               for(int i=1; i<numChanIDs; i++)
+                               {
+                                       Channel *ch = chanMgr->findChannelByID(chanIDs[i]);
+                                       if (ch)
+                                       {
+                                               if (chanStreamIndex[i] != ch->streamIndex)
+                                               {
+                                                       chanStreamIndex[i] = ch->streamIndex;
+                                                       chanStreamPos[i] = ch->headPack.pos;
+                                                       LOG_DEBUG("sendRawMulti got new stream index for chan %d",i);
+                                               }
+
+                                               ChanPacket rawPack;
+                                               if (ch->rawData.findPacket(chanStreamPos[i],rawPack))
+                                               {
+                                                       if ((rawPack.type == ChanPacket::T_DATA) || (rawPack.type == ChanPacket::T_HEAD))
+                                                               rawPack.writeRaw(*sock);
+
+
+                                                       if (rawPack.pos < chanStreamPos[i])
+                                                               LOG_DEBUG("raw: skip back %d",rawPack.pos-chanStreamPos[i]);
+                                                       chanStreamPos[i] = rawPack.pos+rawPack.len;
+
+
+                                                       //LOG("raw at %d: %d %d",streamPos,ch->rawData.getStreamPos(ch->rawData.firstPos),ch->rawData.getStreamPos(ch->rawData.lastPos));
+                                               }                                               
+                                       }
+                                       break;
+                               }
+                               
+
+                               sys->sleepIdle();
+                       }
+               }
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("Stream channel: %s",e.msg);
+       }
+}
+#endif
+
+// -----------------------------------
+void Servent::sendRawMetaChannel(int interval)
+{
+
+       try
+       {
+               Channel *ch = chanMgr->findChannelByID(chanID);
+               if (!ch)
+                       throw StreamException("Channel not found");
+
+               sock->setWriteTimeout(DIRECT_WRITE_TIMEOUT*1000);
+
+               setStatus(S_CONNECTED);
+
+               LOG_DEBUG("Starting Raw Meta stream of %s (metaint: %d) at %d",ch->info.name.cstr(),interval,streamPos);
+
+
+               String lastTitle,lastURL;
+
+               int             lastMsgTime=sys->getTime();
+               bool    showMsg=true;
+
+               char buf[16384];
+               int bufPos=0;
+
+               if ((interval > sizeof(buf)) || (interval < 1))
+                       throw StreamException("Bad ICY Meta Interval value");
+
+               unsigned int connectTime = sys->getTime();
+               unsigned int lastWriteTime = connectTime;
+
+               streamPos = 0;          // raw meta channel has no header (its MP3)
+
+               while ((thread.active) && sock->active())
+               {
+                       ch = chanMgr->findChannelByID(chanID);
+
+                       if (ch)
+                       {
+
+                               ChanPacket rawPack;
+                               if (ch->rawData.findPacket(streamPos,rawPack))
+                               {
+
+                                       if (syncPos != rawPack.sync)
+                                               LOG_ERROR("Send skip: %d",rawPack.sync-syncPos);
+                                       syncPos = rawPack.sync+1;
+
+                                       MemoryStream mem(rawPack.data,rawPack.len);
+
+                                       if (rawPack.type == ChanPacket::T_DATA)
+                                       {
+
+                                               int len = rawPack.len;
+                                               char *p = rawPack.data;
+                                               while (len)
+                                               {
+                                                       int rl = len;
+                                                       if ((bufPos+rl) > interval)
+                                                               rl = interval-bufPos;
+                                                       memcpy(&buf[bufPos],p,rl);
+                                                       bufPos+=rl;
+                                                       p+=rl;
+                                                       len-=rl;
+
+                                                       if (bufPos >= interval)
+                                                       {
+                                                               bufPos = 0;     
+                                                               sock->write(buf,interval);
+                                                               lastWriteTime = sys->getTime();
+
+                                                               if (chanMgr->broadcastMsgInterval)
+                                                                       if ((sys->getTime()-lastMsgTime) >= chanMgr->broadcastMsgInterval)
+                                                                       {
+                                                                               showMsg ^= true;
+                                                                               lastMsgTime = sys->getTime();
+                                                                       }
+
+                                                               String *metaTitle = &ch->info.track.title;
+                                                               if (!ch->info.comment.isEmpty() && (showMsg))
+                                                                       metaTitle = &ch->info.comment;
+
+
+                                                               if (!metaTitle->isSame(lastTitle) || !ch->info.url.isSame(lastURL))
+                                                               {
+
+                                                                       char tmp[1024];
+                                                                       String title,url;
+
+                                                                       title = *metaTitle;
+                                                                       url = ch->info.url;
+
+                                                                       title.convertTo(String::T_META);
+                                                                       url.convertTo(String::T_META);
+
+                                                                       sprintf(tmp,"StreamTitle='%s';StreamUrl='%s';\0",title.cstr(),url.cstr());
+                                                                       int len = ((strlen(tmp) + 15+1) / 16);
+                                                                       sock->writeChar(len);
+                                                                       sock->write(tmp,len*16);
+
+                                                                       lastTitle = *metaTitle;
+                                                                       lastURL = ch->info.url;
+
+                                                                       LOG_DEBUG("StreamTitle: %s, StreamURL: %s",lastTitle.cstr(),lastURL.cstr());
+
+                                                               }else
+                                                               {
+                                                                       sock->writeChar(0);                                     
+                                                               }
+
+                                                       }
+                                               }
+                                       }
+                                       streamPos = rawPack.pos + rawPack.len;
+                               }
+                       }
+                       if ((sys->getTime()-lastWriteTime) > DIRECT_WRITE_TIMEOUT)
+                               throw TimeoutException();
+
+                       sys->sleepIdle();
+
+               }
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("Stream channel: %s",e.msg);
+       }
+}
+// -----------------------------------
+void Servent::sendPeercastChannel()
+{
+       try
+       {
+               setStatus(S_CONNECTED);
+
+               Channel *ch = chanMgr->findChannelByID(chanID);
+               if (!ch)
+                       throw StreamException("Channel not found");
+
+               LOG_DEBUG("Starting PeerCast stream: %s",ch->info.name.cstr());
+
+               sock->writeTag("PCST");
+
+               ChanPacket pack;
+
+               ch->headPack.writePeercast(*sock);
+
+               pack.init(ChanPacket::T_META,ch->insertMeta.data,ch->insertMeta.len,ch->streamPos);
+               pack.writePeercast(*sock);
+       
+               streamPos = 0;
+               unsigned int syncPos=0;
+               while ((thread.active) && sock->active())
+               {
+                       ch = chanMgr->findChannelByID(chanID);
+                       if (ch)
+                       {
+
+                               ChanPacket rawPack;
+                               if (ch->rawData.findPacket(streamPos,rawPack))
+                               {
+                                       if ((rawPack.type == ChanPacket::T_DATA) || (rawPack.type == ChanPacket::T_HEAD))
+                                       {
+                                               sock->writeTag("SYNC");
+                                               sock->writeShort(4);
+                                               sock->writeShort(0);
+                                               sock->write(&syncPos,4);
+                                               syncPos++;
+
+                                               rawPack.writePeercast(*sock);
+                                       }
+                                       streamPos = rawPack.pos + rawPack.len;
+                               }
+                       }
+                       sys->sleepIdle();
+               }
+
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("Stream channel: %s",e.msg);
+       }
+}
+
+//WLock canStreamLock;
+
+// -----------------------------------
+void Servent::sendPCPChannel()
+{
+       bool skipCheck = false;
+
+       Channel *ch = chanMgr->findChannelByID(chanID);
+       if (!ch)
+               throw StreamException("Channel not found");
+
+       AtomStream atom(*sock);
+
+       pcpStream = new PCPStream(remoteID);
+       int error=0;
+
+       try
+       {
+
+               LOG_DEBUG("Starting PCP stream of channel at %d",streamPos);
+
+
+//             setStatus(S_CONNECTED);
+
+               //canStreamLock.on();
+               //thread.active = canStream(ch);
+               //setStatus(S_CONNECTED);
+               //canStreamLock.off();
+
+               lastSkipTime = 0;
+               lastSkipCount = 0;
+               waitPort = 0;
+
+               if (thread.active){
+                       atom.writeParent(PCP_CHAN,3 + ((sendHeader)?1:0));
+                               atom.writeBytes(PCP_CHAN_ID,chanID.id,16);
+                               ch->info.writeInfoAtoms(atom);
+                               ch->info.writeTrackAtoms(atom);
+                               if (sendHeader)
+                               {
+                                       atom.writeParent(PCP_CHAN_PKT,3);
+                                               atom.writeID4(PCP_CHAN_PKT_TYPE,PCP_CHAN_PKT_HEAD);
+                                               atom.writeInt(PCP_CHAN_PKT_POS,ch->headPack.pos);
+                                               atom.writeBytes(PCP_CHAN_PKT_DATA,ch->headPack.data,ch->headPack.len);
+
+                                       streamPos = ch->headPack.pos+ch->headPack.len;
+                                       LOG_DEBUG("Sent %d bytes header",ch->headPack.len);
+                               }
+               }
+
+               unsigned int streamIndex = ch->streamIndex;
+
+               ChanPacket rawPack;
+               char pbuf[ChanPacket::MAX_DATALEN*3];
+               MemoryStream mems(pbuf,sizeof(pbuf));
+               AtomStream atom2(mems);
+
+               while (thread.active)
+               {
+
+                       Channel *ch = chanMgr->findChannelByID(chanID);
+
+                       if (ch)
+                       {
+
+                               if (streamIndex != ch->streamIndex)
+                               {
+                                       streamIndex = ch->streamIndex;
+                                       streamPos = ch->headPack.pos;
+                                       LOG_DEBUG("sendPCPStream got new stream index");                                                
+                               }
+
+                               mems.rewind();
+
+                               if (ch->rawData.findPacket(streamPos,rawPack))
+                               {
+                                       if ((streamPos < rawPack.pos) && !rawPack.skip){
+                                               if (skipCheck){
+                                                       char tmp[32];
+                                                       getHost().IPtoStr(tmp);
+                                                       LOG_NETWORK("##### send skipping ##### %d (%d, %d) -> %s", (rawPack.pos - streamPos), streamPos, rawPack.pos, tmp);
+
+                                                       if (sys->getTime() == lastSkipTime) {
+                                                               LOG_DEBUG("##### skip all buffer");
+                                                               streamPos = ch->rawData.getLatestPos();
+                                                               continue;
+                                                       }
+
+                                                       lastSkipTime = sys->getTime();
+                                                       lastSkipCount++;
+                                               } else {
+                                                       skipCheck = true;
+                                               }
+                                       }
+
+                                       if (rawPack.type == ChanPacket::T_HEAD)
+                                       {
+                                               atom2.writeParent(PCP_CHAN,2);
+                                                       atom2.writeBytes(PCP_CHAN_ID,chanID.id,16);
+                                                       atom2.writeParent(PCP_CHAN_PKT,3);
+                                                               atom2.writeID4(PCP_CHAN_PKT_TYPE,PCP_CHAN_PKT_HEAD);
+                                                               atom2.writeInt(PCP_CHAN_PKT_POS,rawPack.pos);
+                                                               atom2.writeBytes(PCP_CHAN_PKT_DATA,rawPack.data,rawPack.len);
+
+                                               sock->write(pbuf, mems.getPosition());
+                                       }else if (rawPack.type == ChanPacket::T_DATA)
+                                       {
+                                               atom2.writeParent(PCP_CHAN,2);
+                                                       atom2.writeBytes(PCP_CHAN_ID,chanID.id,16);
+                                                       atom2.writeParent(PCP_CHAN_PKT,3);
+                                                               atom2.writeID4(PCP_CHAN_PKT_TYPE,PCP_CHAN_PKT_DATA);
+                                                               atom2.writeInt(PCP_CHAN_PKT_POS,rawPack.pos);
+                                                               atom2.writeBytes(PCP_CHAN_PKT_DATA,rawPack.data,rawPack.len);
+
+#ifdef WIN32
+                                               sock->bufferingWrite(pbuf, mems.getPosition());
+                                               lastSkipTime = sock->bufList.lastSkipTime;
+                                               lastSkipCount = sock->bufList.skipCount;
+#else
+                                               sock->write(pbuf, mems.getPosition());
+#endif
+                                       }
+
+                                       if (rawPack.pos < streamPos)
+                                               LOG_DEBUG("pcp: skip back %d",rawPack.pos-streamPos);
+
+                                       //LOG_DEBUG("Sending %d-%d (%d,%d,%d)",rawPack.pos,rawPack.pos+rawPack.len,ch->streamPos,ch->rawData.getLatestPos(),ch->rawData.getOldestPos());
+
+                                       streamPos = rawPack.pos+rawPack.len;
+                               }
+                       } else {
+                               pcpStream->flush(*sock);
+                               throw StreamException("Channel not found");
+                       }
+
+#ifdef WIN32
+                       sock->bufferingWrite(NULL, 0);
+                       lastSkipTime = sock->bufList.lastSkipTime;
+                       lastSkipCount = sock->bufList.skipCount;
+#endif
+                       BroadcastState bcs;
+                       bcs.servent_id = servent_id;
+//                     error = pcpStream->readPacket(*sock,bcs);
+                       do {
+                               error = pcpStream->readPacket(*sock,bcs);
+                               if (error)
+                                       throw StreamException("PCP exception");
+                       } while (sock->readReady() || pcpStream->outData.numPending());
+
+                       sys->sleepIdle();
+
+               }
+
+               LOG_DEBUG("PCP channel stream closed normally.");
+
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("Stream channel: %s",e.msg);
+       }
+
+       try
+       {
+               atom.writeInt(PCP_QUIT,error);
+       }catch(StreamException &) {}
+
+}
+
+// -----------------------------------
+int Servent::serverProc(ThreadInfo *thread)
+{
+//     thread->lock();
+
+
+       Servent *sv = (Servent*)thread->data;
+
+       try 
+       {
+               if (!sv->sock)
+                       throw StreamException("Server has no socket");
+
+               sv->setStatus(S_LISTENING);
+
+
+               char servIP[64];
+               sv->sock->host.toStr(servIP);
+
+               if (servMgr->isRoot)
+                       LOG_DEBUG("Root Server started: %s",servIP);
+               else
+                       LOG_DEBUG("Server started: %s",servIP);
+               
+
+               while ((thread->active) && (sv->sock->active()))
+               {
+                       if (servMgr->numActiveOnPort(sv->sock->host.port) < servMgr->maxServIn)
+                       {
+                               ClientSocket *cs = sv->sock->accept();
+                               if (cs)
+                               {       
+                                       LOG_DEBUG("accepted incoming");
+                                       Servent *ns = servMgr->allocServent();
+                                       if (ns)
+                                       {
+                                               servMgr->lastIncoming = sys->getTime();
+                                               ns->servPort = sv->sock->host.port;
+                                               ns->networkID = servMgr->networkID;
+                                               ns->initIncoming(cs,sv->allow);
+                                       }else
+                                               LOG_ERROR("Out of servents");
+                               }
+                       }
+                       sys->sleep(100);
+               }
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("Server Error: %s:%d",e.msg,e.err);
+       }
+
+       
+       LOG_DEBUG("Server stopped");
+
+       sv->kill();
+       sys->endThread(thread);
+       return 0;
+}
+// -----------------------------------
+bool   Servent::writeVariable(Stream &s, const String &var)
+{
+       char buf[1024];
+
+       if (var == "type")
+               strcpy(buf,getTypeStr());
+       else if (var == "status")
+               strcpy(buf,getStatusStr());
+       else if (var == "address")
+       {
+               if (servMgr->enableGetName) //JP-EX s
+               {
+                       getHost().toStr(buf);
+                       char h_ip[64];
+                       Host h = getHost();
+                       h.toStr(h_ip);
+
+/*                     ChanHitList *hits[ChanMgr::MAX_HITLISTS];
+                       int numHits=0;
+                       for(int i=0; i<ChanMgr::MAX_HITLISTS; i++)
+                       {
+                               ChanHitList *chl = &chanMgr->hitlists[i];
+                               if (chl->isUsed())
+                                       hits[numHits++] = chl;
+                       }
+                       bool ishit,isfw;
+                       ishit = isfw = false;
+                       int numRelay = 0;
+                       if (numHits) 
+                       {
+                               for(int k=0; k<numHits; k++)
+                               {
+                                       ChanHitList *chl = hits[k];
+                                       if (chl->isUsed())
+                                       {
+                                               for (int j=0; j<ChanHitList::MAX_HITS; j++)
+                                               {
+                                                       ChanHit *hit = &chl->hits[j];
+                                                       if (hit->host.isValid() && (h.ip == hit->host.ip))
+                                                       {
+                                                               ishit = true;
+                                                               if (hit->firewalled)
+                                                                       isfw = true;
+                                                               numRelay += hit->numRelays;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       strcpy(buf,"");
+                       if (ishit == true)
+                       {
+                               if (isfw == true)
+                               {
+                                       if (numRelay== 0)
+                                               strcat(buf,"<font color=red>");
+                                       else 
+                                               strcat(buf,"<font color=orange>");
+                               }
+                               else
+                                       strcat(buf,"<font color=green>");
+                       }
+                       strcat(buf,h_ip);
+                       char h_name[128];
+                       if (ClientSocket::getHostname(h_name,h.ip))
+                       {
+                               strcat(buf,"[");
+                               strcat(buf,h_name);
+                               strcat(buf,"]");
+                       }
+                       if (ishit == true) 
+                       {
+                               strcat(buf,"</font>");
+                       }
+               } //JP-EX e*/
+
+
+                       bool isfw = false;
+                       bool isRelay = true;
+                       int numRelay = 0;
+                       ChanHitList *chl = chanMgr->findHitListByID(chanID);
+                       if (chl){
+                               ChanHit *hit = chl->hit;
+                               while(hit){
+                                       if (hit->host.isValid() && (h.ip == hit->host.ip)){
+                                               isfw = hit->firewalled;
+                                               isRelay = hit->relay;
+                                               numRelay = hit->numRelays;
+                                               break;
+                                       }
+                                       hit = hit->next;
+                               }
+                       }
+                       strcpy(buf, "");
+                       if (isfw){
+                               if (numRelay == 0){
+                                       strcat(buf,"<font color=red>");
+                               } else {
+                                       strcat(buf,"<font color=orange>");
+                               }
+                       } else {
+                               if (!isRelay){
+                                       if (numRelay==0){
+                                               strcpy(buf,"<font color=purple>");
+                                       } else {
+                                               strcpy(buf,"<font color=blue>");
+                                       }
+                               } else {
+                                       strcpy(buf,"<font color=green>");
+                               }
+                       }
+                       strcat(buf,h_ip);
+                       char h_name[128];
+                       if (ClientSocket::getHostname(h_name,h.ip))
+                       {
+                               strcat(buf,"[");
+                               strcat(buf,h_name);
+                               strcat(buf,"]");
+                       }
+                       strcat(buf,"</font>");
+               }
+               else 
+                       getHost().toStr(buf);
+       }
+       else if (var == "agent")
+               strcpy(buf,agent.cstr());
+       else if (var == "bitrate")
+       {
+               if (sock)
+               {
+                       unsigned int tot = sock->bytesInPerSec+sock->bytesOutPerSec;
+                       sprintf(buf,"%.1f",BYTES_TO_KBPS(tot));
+               }else
+                       strcpy(buf,"0");
+       }else if (var == "uptime")
+       {
+               String uptime;
+               if (lastConnect)
+                       uptime.setFromStopwatch(sys->getTime()-lastConnect);
+               else
+                       uptime.set("-");
+               strcpy(buf,uptime.cstr());
+       }else if (var.startsWith("gnet."))
+       {
+
+               float ctime = (float)(sys->getTime()-lastConnect);
+               if (var == "gnet.packetsIn")
+                       sprintf(buf,"%d",gnuStream.packetsIn);
+               else if (var == "gnet.packetsInPerSec")
+                       sprintf(buf,"%.1f",ctime>0?((float)gnuStream.packetsIn)/ctime:0);
+               else if (var == "gnet.packetsOut")
+                       sprintf(buf,"%d",gnuStream.packetsOut);
+               else if (var == "gnet.packetsOutPerSec")
+                       sprintf(buf,"%.1f",ctime>0?((float)gnuStream.packetsOut)/ctime:0);
+               else if (var == "gnet.normQueue")
+                       sprintf(buf,"%d",outPacketsNorm.numPending());
+               else if (var == "gnet.priQueue")
+                       sprintf(buf,"%d",outPacketsPri.numPending());
+               else if (var == "gnet.flowControl")
+                       sprintf(buf,"%d",flowControl?1:0);
+               else if (var == "gnet.routeTime")
+               {
+                       int nr = seenIDs.numUsed();
+                       unsigned int tim = sys->getTime()-seenIDs.getOldest();
+               
+                       String tstr;
+                       tstr.setFromStopwatch(tim);
+
+                       if (nr)
+                               strcpy(buf,tstr.cstr());
+                       else
+                               strcpy(buf,"-");
+               }
+               else
+                       return false;
+
+       }else
+               return false;
+
+       s.writeString(buf);
+
+       return true;
+}
diff --git a/PeerCast.root/PeerCast/core/common/servent.h b/PeerCast.root/PeerCast/core/common/servent.h
new file mode 100644 (file)
index 0000000..b1c2241
--- /dev/null
@@ -0,0 +1,298 @@
+// ------------------------------------------------
+// File : servent.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+#ifndef _SERVENT_H
+#define _SERVENT_H
+
+// ----------------------------------
+#include "socket.h"
+#include "sys.h"
+#include "gnutella.h"
+#include "channel.h"
+#include "http.h"
+#include "rtsp.h"
+#include "pcp.h"
+
+class HTML;
+
+class AtomStream;
+
+// ----------------------------------
+// Servent handles the actual connection between clients
+class Servent
+{
+public:
+
+       enum 
+       {
+               MAX_HASH = 500,                 // max. amount of packet hashes Servents can store
+               MAX_OUTPACKETS = 32             // max. output packets per queue (normal/priority)
+       };
+
+    enum TYPE                                  
+    {
+               T_NONE,                                 // Not allocated
+        T_INCOMING,                            // Unknown incoming
+        T_SERVER,                              // The main server 
+               T_RELAY,                                // Outgoing relay
+               T_DIRECT,                               // Outgoing direct connection
+               T_COUT,                                 // PCP out connection
+               T_CIN,                                  // PCP in connection
+               T_PGNU                                  // old protocol connection              
+    };
+
+    enum STATUS
+    {
+        S_NONE,
+        S_CONNECTING,
+        S_PROTOCOL,
+        S_HANDSHAKE,
+        S_CONNECTED,
+        S_CLOSING,
+               S_LISTENING,
+               S_TIMEOUT,
+               S_REFUSED,
+               S_VERIFIED,
+               S_ERROR,
+               S_WAIT,
+               S_FREE
+    };
+
+       enum PROTOCOL
+       {
+               P_UNKNOWN,
+               P_GNUTELLA06,
+               P_PCP
+       };
+
+
+       enum SORT
+       {
+               SORT_NAME = 0,
+               SORT_BITRATE,
+               SORT_LISTENERS,
+               SORT_HOSTS,
+               SORT_TYPE,
+               SORT_GENRE
+       };
+
+       enum ALLOW
+       {
+               ALLOW_HTML              = 0x01,
+               ALLOW_BROADCAST = 0x02,
+               ALLOW_NETWORK   = 0x04,
+               ALLOW_DIRECT    = 0x08,
+               ALLOW_ALL               = 0xff
+       };
+
+       Servent(int);
+       ~Servent();
+
+       void    reset();
+    bool       initServer(Host &);
+    void       initIncoming(ClientSocket *,unsigned int);
+    void       initOutgoing(TYPE);
+       void    initGIV(Host &, GnuID &);
+       void    initPCP(Host &);
+
+       void    checkFree();
+
+
+
+
+       //      funcs for handling status/type
+       void    setStatus(STATUS);
+       static char *   getTypeStr(Servent::TYPE t) {return typeMsgs[t];}
+       char *  getTypeStr() {return getTypeStr(type);}
+       char *  getStatusStr() {return statusMsgs[status];}
+       int             getOutput();
+       void    addBytes(unsigned int);
+       bool    isOlderThan(Servent *s)
+       {
+               if (s)
+               {
+                       unsigned int t = sys->getTime();
+                       return ((t-lastConnect) > (t-s->lastConnect));
+               }else
+                       return true;
+       }
+
+
+
+       // static funcs that do the actual work in the servent thread
+       static  THREAD_PROC             serverProc(ThreadInfo *);
+       static  THREAD_PROC             outgoingProc(ThreadInfo *);
+       static  THREAD_PROC             incomingProc(ThreadInfo *);
+       static  THREAD_PROC             givProc(ThreadInfo *);
+       static  THREAD_PROC             pcpProc(ThreadInfo *);
+       static  THREAD_PROC             fetchProc(ThreadInfo *);
+
+       static bool     pingHost(Host &,GnuID &);
+
+       bool    getLocalURL(char *);
+       bool    getLocalTypeURL(char *, ChanInfo::TYPE);
+
+       // various types of handshaking are needed
+       void    handshakePLS(ChanHitList **, int, bool);
+       void    handshakePLS(ChanInfo &, bool);
+
+       void    handshakeHTML(char *);
+       void    handshakeXML();
+       void    handshakeCMD(char *);
+       bool    handshakeAuth(HTTP &,const char *,bool);
+       void    handshakeIn();
+       void    handshakeOut();
+
+
+       void    processOutPCP();
+       void    processOutChannel();
+
+       bool    handshakeStream(ChanInfo &);
+       void    handshakeGiv(GnuID &);
+
+       void    handshakeICY(Channel::SRC_TYPE,bool);
+       void    handshakeIncoming();
+       void    handshakePOST();
+       void    handshakeRTSP(RTSP &);
+       void    handshakeHTTP(HTTP &,bool);
+
+       void    handshakeRemoteFile(const char *);
+       void    handshakeLocalFile(const char *);
+
+       static void     handshakeOutgoingPCP(AtomStream &,Host &,GnuID &,String &,bool);
+       static void     handshakeIncomingPCP(AtomStream &,Host &,GnuID &,String &);
+
+       void    processIncomingPCP(bool);
+
+       bool    waitForChannelHeader(ChanInfo &);
+       ChanInfo        findChannel(char *str,ChanInfo &);
+
+       bool    writeVariable(Stream &, const String &);
+
+
+       // the "mainloop" of servents 
+       void    processGnutella();
+       void    processRoot();
+       void    processServent();
+       void    processStream(bool,ChanInfo &);
+       void    processPCP(bool,bool);
+
+       bool    procAtoms(AtomStream &);
+       void    procRootAtoms(AtomStream &,int);
+       void    procHeloAtoms(AtomStream &,int,bool);
+       void    procGetAtoms(AtomStream &,int);
+
+       void    triggerChannel(char *,ChanInfo::PROTOCOL,bool);
+       void    sendPeercastChannel();
+       void    sendRawChannel(bool,bool);
+//     void    sendRawMultiChannel(bool,bool);
+       void    sendRawMetaChannel(int);
+       void    sendPCPChannel();
+       void    checkPCPComms(Channel *, AtomStream &);
+
+       static void     readICYHeader(HTTP &, ChanInfo &, char *);
+       bool    canStream(Channel *);
+
+       bool    isConnected() {return status == S_CONNECTED;}
+       bool    isListening() {return status == S_LISTENING;}
+
+       bool    isAllowed(int);
+       bool    isFiltered(int);
+
+       // connection handling funcs
+       void    createSocket();
+       void    kill();
+       void    abort();
+       bool    isPrivate();
+       bool    isLocal();
+
+
+       Host    getHost();
+
+       bool    outputPacket(GnuPacket &,bool);
+       bool    hasSeenPacket(GnuPacket &p) {return seenIDs.contains(p.id);}
+       bool    acceptGIV(ClientSocket *);
+       bool    sendPacket(ChanPacket &,GnuID &,GnuID &,GnuID &,Servent::TYPE);
+
+
+       TYPE type;
+       STATUS status;
+
+       static char *statusMsgs[],*typeMsgs[];
+       GnuStream gnuStream;
+       GnuPacket pack;
+       unsigned int    lastConnect,lastPing,lastPacket;
+       String  agent;
+
+       GnuIDList       seenIDs;
+       GnuID   networkID;
+       int             serventIndex;
+
+       GnuID   remoteID;
+
+       GnuID   chanID;
+
+       GnuID   givID;
+
+       ThreadInfo      thread;
+
+
+       char    loginPassword[64];
+       char    loginMount[64];
+
+       bool    priorityConnect;
+       bool    addMetadata;
+       int             nsSwitchNum;
+
+       unsigned        int allow;
+
+    ClientSocket *sock,*pushSock;
+
+       WLock   lock;
+
+       bool    sendHeader;
+       unsigned int syncPos,streamPos;
+       int             servPort;
+
+       ChanInfo::PROTOCOL      outputProtocol;
+
+       GnuPacketBuffer outPacketsNorm,outPacketsPri;
+
+       unsigned int bytesPerSecond;
+       bool    flowControl;
+
+       Servent *next;
+
+       PCPStream *pcpStream;
+       Cookie  cookie;
+
+       int servent_id;
+       unsigned int lastSkipTime;
+       unsigned int lastSkipCount;
+       unsigned int waitPort;
+
+       int channel_id;
+};
+
+extern char *nextCGIarg(char *cp, char *cmd, char *arg);
+
+
+#endif
+
diff --git a/PeerCast.root/PeerCast/core/common/servhs.cpp b/PeerCast.root/PeerCast/core/common/servhs.cpp
new file mode 100644 (file)
index 0000000..8e352bf
--- /dev/null
@@ -0,0 +1,1954 @@
+// ------------------------------------------------
+// File : servhs.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             Servent handshaking, TODO: should be in its own class
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+#include <stdlib.h>
+#include "servent.h"
+#include "servmgr.h"
+#include "html.h"
+#include "stats.h"
+#include "peercast.h"
+#include "pcp.h"
+#include "version2.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// -----------------------------------
+static void termArgs(char *str)
+{
+       if (str)
+       {
+               int slen = strlen(str);
+               for(int i=0; i<slen; i++)
+                       if (str[i]=='&') str[i] = 0;
+       }
+}
+// -----------------------------------
+char *nextCGIarg(char *cp, char *cmd, char *arg)
+{
+       if (!*cp)
+               return NULL;
+
+       int cnt=0;
+
+       // fetch command
+       while (*cp)
+       {
+               char c = *cp++;
+               if (c == '=')
+                       break;
+               else
+                       *cmd++ = c;
+
+               cnt++;
+               if (cnt >= (MAX_CGI_LEN-1))
+                       break;
+       }
+       *cmd = 0;
+
+       cnt=0;
+       // fetch arg
+       while (*cp)
+       {
+               char c = *cp++;
+               if (c == '&')
+                       break;
+               else
+                       *arg++ = c;
+
+               cnt++;
+               if (cnt >= (MAX_CGI_LEN-1))
+                       break;
+       }
+       *arg = 0;
+
+       return cp;
+}
+// -----------------------------------
+bool getCGIargBOOL(char *a)
+{
+       return (strcmp(a,"1")==0);
+}
+// -----------------------------------
+int getCGIargINT(char *a)
+{
+       return atoi(a);
+}
+
+// -----------------------------------
+void Servent::handshakeHTTP(HTTP &http, bool isHTTP)
+{
+       char *in = http.cmdLine;
+
+       if (http.isRequest("GET /"))
+       {
+               char *fn = in+4;
+
+               char *pt = strstr(fn,HTTP_PROTO1);
+               if (pt)
+                       pt[-1] = 0;
+
+               if (strncmp(fn,"/admin?",7)==0)
+               {
+                       if (!isAllowed(ALLOW_HTML))
+                               throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+
+                       LOG_DEBUG("Admin client");
+                       handshakeCMD(fn+7);
+
+               }else if (strncmp(fn,"/http/",6)==0)
+               {
+                       String dirName = fn+6;
+
+                       if (!isAllowed(ALLOW_HTML))
+                               throw HTTPException(HTTP_SC_UNAVAILABLE,503);                   
+
+                       if (!handshakeAuth(http,fn,false))
+                               throw HTTPException(HTTP_SC_UNAUTHORIZED,401);                  
+
+
+                       handshakeRemoteFile(dirName);
+
+
+               }else if (strncmp(fn,"/html/",6)==0)
+               {
+                       String dirName = fn+1;
+
+                       if (!isAllowed(ALLOW_HTML))
+                               throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+                       if (handshakeAuth(http,fn,true))
+                               handshakeLocalFile(dirName);
+
+
+               }else if (strncmp(fn,"/admin/?",8)==0)
+               {
+                       if (!isAllowed(ALLOW_HTML))
+                               throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+                       LOG_DEBUG("Admin client");
+                       handshakeCMD(fn+8);
+
+               }else if (strncmp(fn,"/admin.cgi",10)==0)
+               {
+                       if (!isAllowed(ALLOW_BROADCAST))
+                               throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+                       char *pwdArg = getCGIarg(fn,"pass=");
+                       char *songArg = getCGIarg(fn,"song=");
+                       char *mountArg = getCGIarg(fn,"mount=");
+                       char *urlArg = getCGIarg(fn,"url=");
+
+                       if (pwdArg && songArg)
+                       {
+                               int i;
+                               int slen = strlen(fn);
+                               for(i=0; i<slen; i++)
+                                       if (fn[i]=='&') fn[i] = 0;
+
+                               Channel *c=chanMgr->channel;
+                               while (c)
+                               {
+                                       if ((c->status == Channel::S_BROADCASTING) &&
+                                          (c->info.contentType == ChanInfo::T_MP3) )
+                                       {
+                                               // if we have a mount point then check for it, otherwise update all channels.
+                                               bool match=true;
+
+                                               if (mountArg)
+                                                       match = strcmp(c->mount,mountArg)==0;
+
+                                               if (match)
+                                               {
+                                                       ChanInfo newInfo = c->info;
+                                                       newInfo.track.title.set(songArg,String::T_ESC);
+                                                       newInfo.track.title.convertTo(String::T_UNICODE);
+
+                                                       if (urlArg)
+                                                               if (urlArg[0])
+                                                                       newInfo.track.contact.set(urlArg,String::T_ESC);
+                                                       LOG_CHANNEL("Channel Shoutcast update: %s",songArg);
+                                                       c->updateInfo(newInfo);
+                                               }
+                                       }
+                                       c=c->next;
+                               }
+                       }
+
+               }else if (strncmp(fn,"/pls/",5)==0)
+               {
+
+                       if (!sock->host.isLocalhost())
+                               if (!isAllowed(ALLOW_DIRECT) || !isFiltered(ServFilter::F_DIRECT))
+                                       throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+                       
+                       ChanInfo info;
+                       if (servMgr->getChannel(fn+5,info,isPrivate()))
+                               handshakePLS(info,false);
+                       else
+                               throw HTTPException(HTTP_SC_NOTFOUND,404);
+
+               }else if (strncmp(fn,"/stream/",8)==0)
+               {
+
+                       if (!sock->host.isLocalhost())
+                               if (!isAllowed(ALLOW_DIRECT) || !isFiltered(ServFilter::F_DIRECT))
+                                       throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+                       triggerChannel(fn+8,ChanInfo::SP_HTTP,isPrivate());
+
+                       
+               }else if (strncmp(fn,"/channel/",9)==0)
+               {
+
+                       if (!sock->host.isLocalhost())
+                               if (!isAllowed(ALLOW_NETWORK) || !isFiltered(ServFilter::F_NETWORK))
+                                       throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+                       triggerChannel(fn+9,ChanInfo::SP_PCP,false);
+
+               }else 
+               {
+                       while (http.nextHeader());
+                       http.writeLine(HTTP_SC_FOUND);
+                       http.writeLineF("Location: /%s/index.html",servMgr->htmlPath);
+                       http.writeLine("");
+               }
+       }
+       else if (http.isRequest("POST /"))
+       {
+               char *fn = in+5;
+
+               char *pt = strstr(fn,HTTP_PROTO1);
+               if (pt)
+                       pt[-1] = 0;
+
+               if (strncmp(fn,"/pls/",5)==0)
+               {
+
+                       if (!sock->host.isLocalhost())
+                               if (!isAllowed(ALLOW_DIRECT) || !isFiltered(ServFilter::F_DIRECT))
+                                       throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+                       
+                       ChanInfo info;
+                       if (servMgr->getChannel(fn+5,info,isPrivate()))
+                               handshakePLS(info,false);
+                       else
+                               throw HTTPException(HTTP_SC_NOTFOUND,404);
+
+               }else if (strncmp(fn,"/stream/",8)==0)
+               {
+
+                       if (!sock->host.isLocalhost())
+                               if (!isAllowed(ALLOW_DIRECT) || !isFiltered(ServFilter::F_DIRECT))
+                                       throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+                       triggerChannel(fn+8,ChanInfo::SP_HTTP,isPrivate());
+
+               }else if (strncmp(fn,"/admin",7)==0)
+               {
+                       if (!isAllowed(ALLOW_HTML))
+                               throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+
+                       LOG_DEBUG("Admin client");
+                       while(http.nextHeader()){
+                               LOG_DEBUG("%s",http.cmdLine);
+                       }
+                       char buf[8192];
+                       if (sock->readLine(buf, sizeof(buf)) != 0){
+                               handshakeCMD(buf);
+                       }
+
+               }else 
+               {
+                       while (http.nextHeader());
+                       http.writeLine(HTTP_SC_FOUND);
+                       http.writeLineF("Location: /%s/index.html",servMgr->htmlPath);
+                       http.writeLine("");
+               }
+       }else if (http.isRequest("GIV"))
+       {
+               HTTP http(*sock);
+       
+               while (http.nextHeader()) ;
+
+               if (!isAllowed(ALLOW_NETWORK))
+                       throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+               GnuID id;
+               id.clear();
+
+               char *idstr = strstr(in,"/");
+               if (idstr)
+                       id.fromStr(idstr+1);
+
+               char ipstr[64];
+               sock->host.toStr(ipstr);
+
+               if (id.isSet())
+               {
+                       // at the moment we don`t really care where the GIV came from, so just give to chan. no. if its waiting.
+                       Channel *ch = chanMgr->findChannelByID(id);
+
+                       if (!ch)
+                               throw HTTPException(HTTP_SC_NOTFOUND,404);
+
+                       if (!ch->acceptGIV(sock))
+                               throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+               
+                       LOG_DEBUG("Accepted GIV channel %s from: %s",idstr,ipstr);
+
+                       sock=NULL;                                      // release this servent but dont close socket.  
+               }else 
+               {
+
+                       if (!servMgr->acceptGIV(sock))
+                               throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+                       LOG_DEBUG("Accepted GIV PCP from: %s",ipstr);
+                       sock=NULL;                                      // release this servent but dont close socket.  
+               }
+
+       }else if (http.isRequest(PCX_PCP_CONNECT))
+       {
+
+               if (!isAllowed(ALLOW_NETWORK) || !isFiltered(ServFilter::F_NETWORK))
+                       throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+               
+               processIncomingPCP(true);
+
+       }else if (http.isRequest("PEERCAST CONNECT"))
+       {
+               if (!isAllowed(ALLOW_NETWORK) || !isFiltered(ServFilter::F_NETWORK))
+                       throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+               LOG_DEBUG("PEERCAST client");
+               processServent();
+
+       }else if (http.isRequest("SOURCE"))
+       {
+               if (!isAllowed(ALLOW_BROADCAST))
+                       throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+               char *mount = NULL;
+
+               char *ps;
+               if (ps=strstr(in,"ICE/1.0"))
+               {
+                       mount = in+7;
+                       *ps = 0;
+                       LOG_DEBUG("ICE 1.0 client to %s",mount?mount:"unknown");
+               }else{
+                       mount = in+strlen(in);
+                       while (*--mount)
+                               if (*mount == '/')
+                               {
+                                       mount[-1] = 0; // password preceeds
+                                       break;
+                               }
+                       strcpy(loginPassword,in+7);
+                       
+                       LOG_DEBUG("ICY client: %s %s",loginPassword,mount?mount:"unknown");
+               }
+
+               if (mount)
+                       strcpy(loginMount,mount);
+
+               handshakeICY(Channel::SRC_ICECAST,isHTTP);
+               sock = NULL;    // socket is taken over by channel, so don`t close it
+
+       }else if (http.isRequest(servMgr->password))
+       {
+               if (!isAllowed(ALLOW_BROADCAST))
+                       throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+               strcpy(loginPassword,servMgr->password);        // pwd already checked
+
+               sock->writeLine("OK2");
+               sock->writeLine("icy-caps:11");
+               sock->writeLine("");
+               LOG_DEBUG("ShoutCast client");
+
+               handshakeICY(Channel::SRC_SHOUTCAST,isHTTP);
+               sock = NULL;    // socket is taken over by channel, so don`t close it
+
+       }else
+       {
+               throw HTTPException(HTTP_SC_BADREQUEST,400);
+       }
+
+}
+// -----------------------------------
+bool Servent::canStream(Channel *ch)
+{
+       if (ch==NULL)
+               return false;
+
+       if (servMgr->isDisabled)
+               return false;
+
+       if (!isPrivate())
+       {
+               Channel *c = chanMgr->channel;
+               int noRelay = 0;
+               unsigned int needRate = 0;
+               unsigned int allRate = 0;
+               while(c){
+                       if (c->isPlaying()){
+                               allRate += c->info.bitrate * c->localRelays();
+                               if ((c != ch) && (c->localRelays() == 0)){
+                                       if(!isIndexTxt(c))      // for PCRaw (relay)
+                                               noRelay++;
+                                       needRate+=c->info.bitrate;
+                               }
+                       }
+                       c = c->next;
+               }
+               int diff = servMgr->maxRelays - servMgr->numStreams(Servent::T_RELAY,false);
+               if (ch->localRelays()){
+                       if (noRelay > diff){
+                               noRelay = diff;
+                       }
+               } else {
+                       noRelay = 0;
+                       needRate = 0;
+               }
+
+               // for PCRaw (relay) start.
+               bool force_off = true;
+
+               if(isIndexTxt(ch))
+                       force_off = false;
+               // for PCRaw (relay) end.
+
+               LOG_DEBUG("Relay check: Max=%d Now=%d Need=%d ch=%d",
+                       servMgr->maxBitrateOut, allRate, needRate, ch->info.bitrate);
+               if  (   !ch->isPlaying()
+                               || ch->isFull()
+//                             || servMgr->bitrateFull(needRate+ch->getBitrate())
+                               || (allRate + needRate + ch->info.bitrate > servMgr->maxBitrateOut)
+                               || ((type == T_RELAY) && servMgr->relaysFull() && force_off)    // for PCRaw (relay) (force_off)
+                               || ((type == T_RELAY) && (((servMgr->numStreams(Servent::T_RELAY,false) + noRelay) >= servMgr->maxRelays)) && force_off)        // for PCRaw (relay) (force_off)
+                               || ((type == T_DIRECT) && servMgr->directFull())
+               ){
+                       LOG_DEBUG("Relay check: NG");
+                       return false;
+               }
+       }
+
+       LOG_DEBUG("Relay check: OK");
+       return true;
+}
+// -----------------------------------
+void Servent::handshakeIncoming()
+{
+
+       setStatus(S_HANDSHAKE);
+
+       char buf[2048];
+       sock->readLine(buf,sizeof(buf));
+
+       char sb[64];
+       sock->host.toStr(sb);
+
+
+       if (stristr(buf,RTSP_PROTO1))
+       {
+               LOG_DEBUG("RTSP from %s '%s'",sb,buf);
+               RTSP rtsp(*sock);
+               rtsp.initRequest(buf);
+               handshakeRTSP(rtsp);
+       }else if (stristr(buf,HTTP_PROTO1))
+       {
+               LOG_DEBUG("HTTP from %s '%s'",sb,buf);
+               HTTP http(*sock);
+               http.initRequest(buf);
+               handshakeHTTP(http,true);
+       }else
+       {
+               LOG_DEBUG("Connect from %s '%s'",sb,buf);
+               HTTP http(*sock);
+               http.initRequest(buf);
+               handshakeHTTP(http,false);
+       }
+
+}
+// -----------------------------------
+void Servent::triggerChannel(char *str, ChanInfo::PROTOCOL proto,bool relay)   
+{
+
+       ChanInfo info;
+//     WLockBlock lb(&(chanMgr->channellock));
+
+//     LOG_DEBUG("----------triggerChannel LOCK ON");
+//     lb.on();
+       servMgr->getChannel(str,info,relay);
+//     LOG_DEBUG("==========triggerChannel LOCK OFF");
+//     lb.off();
+
+       if (proto == ChanInfo::SP_PCP)
+               type = T_RELAY;
+       else
+               type = T_DIRECT;
+
+       outputProtocol = proto;
+
+       processStream(false,info);
+
+}
+// -----------------------------------
+void writePLSHeader(Stream &s, PlayList::TYPE type)
+{
+       s.writeLine(HTTP_SC_OK);
+       s.writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT);
+
+       const char *content;
+       switch(type)
+       {
+               case PlayList::T_PLS:
+                       content = MIME_XM3U;
+                       break;
+               case PlayList::T_ASX:
+                       content = MIME_ASX;
+                       break;
+               case PlayList::T_RAM:
+                       content = MIME_RAM;
+                       break;
+               default:
+                       content = MIME_TEXT;
+                       break;
+       }
+       s.writeLineF("%s %s",HTTP_HS_CONTENT,content);
+    s.writeLine("Content-Disposition: inline");
+    s.writeLine("Cache-Control: private" );
+       s.writeLineF("%s %s",HTTP_HS_CONNECTION,"close");
+
+       s.writeLine("");
+}
+
+// -----------------------------------
+void Servent::handshakePLS(ChanInfo &info, bool doneHandshake)
+{
+       char url[256];
+
+       char in[128];
+
+       if (!doneHandshake)
+               while (sock->readLine(in,128));
+
+
+       if (getLocalTypeURL(url,info.contentType))
+       {
+
+               PlayList::TYPE type;
+
+               if ((info.contentType == ChanInfo::T_WMA) || (info.contentType == ChanInfo::T_WMV))
+                       type = PlayList::T_ASX;
+               else if (info.contentType == ChanInfo::T_OGM)
+                       type = PlayList::T_RAM;
+               else
+                       type = PlayList::T_PLS;
+
+               writePLSHeader(*sock,type);
+
+               PlayList *pls;
+
+               pls = new PlayList(type,1);
+
+               pls->addChannel(url,info);
+
+               pls->write(*sock);
+
+               delete pls;
+       }
+}
+// -----------------------------------
+void Servent::handshakePLS(ChanHitList **cl, int num, bool doneHandshake)
+{
+       char url[256];
+       char in[128];
+
+       if (!doneHandshake)
+               while (sock->readLine(in,128));
+
+       if (getLocalURL(url))
+       {
+               writePLSHeader(*sock,PlayList::T_SCPLS);
+
+               PlayList *pls;
+
+               pls = new PlayList(PlayList::T_SCPLS,num);
+
+               for(int i=0; i<num; i++)
+                       pls->addChannel(url,cl[i]->info);
+
+               pls->write(*sock);
+
+               delete pls;
+       }
+}
+// -----------------------------------
+bool Servent::getLocalURL(char *str)
+{
+       if (!sock)
+               throw StreamException("Not connected");
+
+
+       char ipStr[64];
+
+       Host h;
+       
+       if (sock->host.localIP())
+               h = sock->getLocalHost();
+       else
+               h = servMgr->serverHost;
+
+       h.port = servMgr->serverHost.port;
+
+       h.toStr(ipStr);
+
+       sprintf(str,"http://%s",ipStr);                 
+       return true;
+}
+
+// -----------------------------------
+bool Servent::getLocalTypeURL(char *str, ChanInfo::TYPE type)
+{
+       if (!sock)
+               throw StreamException("Not connected");
+
+
+       char ipStr[64];
+
+       Host h;
+       
+       if (sock->host.localIP())
+               h = sock->getLocalHost();
+       else
+               h = servMgr->serverHost;
+
+       h.port = servMgr->serverHost.port;
+
+       h.toStr(ipStr);
+       switch(type) {
+               case ChanInfo::T_WMA:
+               case ChanInfo::T_WMV:
+                       sprintf(str,"mms://%s",ipStr);  
+                       break;
+               default:
+                       sprintf(str,"http://%s",ipStr); 
+       }
+       return true;
+}
+// -----------------------------------
+// Warning: testing RTSP/RTP stuff below.
+// .. moved over to seperate app now.
+// -----------------------------------
+void Servent::handshakePOST()
+{
+       char tmp[1024];
+    while (sock->readLine(tmp,sizeof(tmp)))
+               LOG_DEBUG("POST: %s",tmp);
+
+       throw HTTPException(HTTP_SC_BADREQUEST,400);
+}
+
+
+// -----------------------------------
+void Servent::handshakeRTSP(RTSP &rtsp)
+{
+       throw HTTPException(HTTP_SC_BADREQUEST,400);
+}
+// -----------------------------------
+bool Servent::handshakeAuth(HTTP &http,const char *args,bool local)
+{
+       char user[1024],pass[1024];
+       user[0] = pass[0] = 0;
+
+       char *pwd  = getCGIarg(args, "pass=");
+
+       if ((pwd) && strlen(servMgr->password))
+       {
+               String tmp = pwd;
+               char *as = strstr(tmp.cstr(),"&");
+               if (as) *as = 0;
+               if (strcmp(tmp,servMgr->password)==0)
+               {
+                   while (http.nextHeader());
+                       return true;
+               }
+       }
+
+       Cookie gotCookie;
+       cookie.clear();
+
+    while (http.nextHeader())
+       {
+               char *arg = http.getArgStr();
+               if (!arg)
+                       continue;
+
+               switch (servMgr->authType)
+               {
+                       case ServMgr::AUTH_HTTPBASIC:
+                               if (http.isHeader("Authorization"))
+                                       http.getAuthUserPass(user,pass);
+                               break;
+                       case ServMgr::AUTH_COOKIE:
+                               if (http.isHeader("Cookie"))
+                               {
+                                       LOG_DEBUG("Got cookie: %s",arg);
+                                       char *idp=arg;
+                                       while ((idp = strstr(idp,"id=")))
+                                       {
+                                               idp+=3;
+                                               gotCookie.set(idp,sock->host.ip);
+                                               if (servMgr->cookieList.contains(gotCookie))
+                                               {
+                                                       LOG_DEBUG("Cookie found");
+                                                       cookie = gotCookie;
+                                                       break;
+                                               }
+
+                                       }
+                               }
+                               break;
+               }
+       }
+
+       if (sock->host.isLocalhost())
+               return true;
+
+
+       switch (servMgr->authType)
+       {
+               case ServMgr::AUTH_HTTPBASIC:
+                               
+                       if ((strcmp(pass,servMgr->password)==0) && strlen(servMgr->password))
+                               return true;
+                       break;
+               case ServMgr::AUTH_COOKIE:
+                       if (servMgr->cookieList.contains(cookie))
+                               return true;
+                       break;
+       }
+
+
+
+       if (servMgr->authType == ServMgr::AUTH_HTTPBASIC)
+       {
+               http.writeLine(HTTP_SC_UNAUTHORIZED);
+               http.writeLine("WWW-Authenticate: Basic realm=\"PeerCast Admin\"");
+       }else if (servMgr->authType == ServMgr::AUTH_COOKIE)
+       {
+               String file = servMgr->htmlPath;
+               file.append("/login.html");
+               if (local)
+                       handshakeLocalFile(file);
+               else
+                       handshakeRemoteFile(file);
+       }
+       
+
+       return false;
+}
+
+// -----------------------------------
+void Servent::handshakeCMD(char *cmd)
+{
+       char result[MAX_CGI_LEN];
+       char arg[MAX_CGI_LEN];
+       char curr[MAX_CGI_LEN];
+
+       char    jumpStr[128];
+       char    *jumpArg=NULL;
+       bool    retHTML=true;
+       strcpy(result,"OK");
+
+       HTTP http(*sock);
+       HTML html("",*sock);
+
+
+       if (!handshakeAuth(http,cmd,true))
+               return;
+
+       try
+       {
+               if (cmpCGIarg(cmd,"cmd=","redirect"))
+               {
+                       char *j = getCGIarg(cmd,"url=");
+                       if (j)
+                       {
+                               termArgs(cmd);
+                               String url;
+                               url.set(j,String::T_ESC);
+                               url.convertTo(String::T_ASCII);
+
+                               if (!url.contains("http://"))
+                                       url.prepend("http://");
+
+                               html.setRefreshURL(url.cstr());
+                               html.startHTML();
+                                       html.addHead();
+                                       html.startBody();
+                                               html.startTagEnd("h3","Please wait...");
+                                       html.end();
+                               html.end();
+
+                       }
+               }else{
+
+                       if (cmpCGIarg(cmd,"cmd=","viewxml"))
+                       {
+
+                               handshakeXML();
+                               retHTML = false;
+                       }else if (cmpCGIarg(cmd,"cmd=","clearlog"))
+                       {
+                               sys->logBuf->clear();
+                               sprintf(jumpStr,"/%s/viewlog.html",servMgr->htmlPath);                                  
+                               jumpArg = jumpStr;
+
+                       }else if (cmpCGIarg(cmd,"cmd=","save"))
+                       {
+
+                               peercastInst->saveSettings();
+
+                               sprintf(jumpStr,"/%s/settings.html",servMgr->htmlPath);                                 
+                               jumpArg = jumpStr;
+                       }else if (cmpCGIarg(cmd,"cmd=","reg"))
+                       {
+                               char idstr[128];
+                               chanMgr->broadcastID.toStr(idstr);
+                               sprintf(jumpStr,"http://www.peercast.org/register/?id=%s",idstr);                                       
+                               jumpArg = jumpStr;
+                       }else if (cmpCGIarg(cmd,"cmd=","edit_bcid"))
+                       {
+                               char *cp = cmd;
+                               GnuID id;
+                               BCID *bcid;
+                               while (cp=nextCGIarg(cp,curr,arg))
+                               {
+                                       if (strcmp(curr,"id")==0)
+                                               id.fromStr(arg);
+                                       else if (strcmp(curr,"del")==0)
+                                               servMgr->removeValidBCID(id);
+                                       else if (strcmp(curr,"valid")==0)
+                                       {
+                                               bcid = servMgr->findValidBCID(id);
+                                               if (bcid)
+                                                       bcid->valid = getCGIargBOOL(arg);
+                                       }
+                               }
+                               peercastInst->saveSettings();
+                               sprintf(jumpStr,"/%s/bcid.html",servMgr->htmlPath);                                     
+                               jumpArg = jumpStr;
+
+                       }else if (cmpCGIarg(cmd,"cmd=","add_bcid"))
+                       {
+                               BCID *bcid = new BCID();
+
+                               char *cp = cmd;
+                               bool result=false;
+                               while (cp=nextCGIarg(cp,curr,arg))
+                               {
+                                       if (strcmp(curr,"id")==0)
+                                               bcid->id.fromStr(arg);
+                                       else if (strcmp(curr,"name")==0)
+                                               bcid->name.set(arg);
+                                       else if (strcmp(curr,"email")==0)
+                                               bcid->email.set(arg);
+                                       else if (strcmp(curr,"url")==0)
+                                               bcid->url.set(arg);
+                                       else if (strcmp(curr,"valid")==0)
+                                               bcid->valid = getCGIargBOOL(arg);
+                                       else if (strcmp(curr,"result")==0)
+                                               result = true;
+
+                               }
+       
+                               LOG_DEBUG("Adding BCID : %s",bcid->name.cstr());                        
+                               servMgr->addValidBCID(bcid);
+                               peercastInst->saveSettings();
+                               if (result)
+                               {
+                                       http.writeLine(HTTP_SC_OK);
+                                       http.writeLine("");
+                                       http.writeString("OK");
+                               }else
+                               {
+                                       sprintf(jumpStr,"/%s/bcid.html",servMgr->htmlPath);                                     
+                                       jumpArg = jumpStr;
+                               }
+
+
+                       }else if (cmpCGIarg(cmd,"cmd=","apply"))
+                       {       
+                               //servMgr->numFilters = 0;
+                               ServFilter *currFilter=servMgr->filters;
+                               bool beginfilt = false;
+
+                               bool brRoot=false;
+                               bool getUpd=false;
+                               int showLog=0;
+                               int allowServer1=0;
+                               int allowServer2=0;
+                               int newPort=servMgr->serverHost.port;
+                               int enableGetName = 0;
+                               int allowConnectPCST = 0;
+
+                               char *cp = cmd;
+                               while (cp=nextCGIarg(cp,curr,arg))
+                               {
+                                       // server
+                                       if (strcmp(curr,"serveractive")==0)
+                                               servMgr->autoServe = getCGIargBOOL(arg);
+                                       else if (strcmp(curr,"port")==0)
+                                               newPort = getCGIargINT(arg);
+                                       else if (strcmp(curr,"icymeta")==0)
+                                       {
+                                               int iv = getCGIargINT(arg);
+                                               if (iv < 0) iv = 0;
+                                               else if (iv > 16384) iv = 16384;
+
+                                               chanMgr->icyMetaInterval = iv;
+
+                                       }else if (strcmp(curr,"passnew")==0)
+                                               strcpy(servMgr->password,arg);
+                                       else if (strcmp(curr,"root")==0)
+                                               servMgr->isRoot = getCGIargBOOL(arg);
+                                       else if (strcmp(curr,"brroot")==0)
+                                               brRoot = getCGIargBOOL(arg);
+                                       else if (strcmp(curr,"getupd")==0)
+                                               getUpd = getCGIargBOOL(arg);
+                                       else if (strcmp(curr,"huint")==0)
+                                               chanMgr->setUpdateInterval(getCGIargINT(arg));
+                                       else if (strcmp(curr,"forceip")==0)
+                                               servMgr->forceIP = arg;
+                                       else if (strcmp(curr,"htmlPath")==0)
+                                       {
+                                               strcpy(servMgr->htmlPath,"html/");
+                                               strcat(servMgr->htmlPath,arg);
+                                       }else if (strcmp(curr,"djmsg")==0)
+                                       {
+                                               String msg;
+                                               msg.set(arg,String::T_ESC);
+                                               msg.convertTo(String::T_UNICODE);
+                                               chanMgr->setBroadcastMsg(msg);
+                                       }
+                                       else if (strcmp(curr,"pcmsg")==0)
+                                       {
+                                               servMgr->rootMsg.set(arg,String::T_ESC);
+                                               servMgr->rootMsg.convertTo(String::T_UNICODE);
+                                       }else if (strcmp(curr,"minpgnu")==0)
+                                               servMgr->minGnuIncoming = atoi(arg);
+                                       else if (strcmp(curr,"maxpgnu")==0)
+                                               servMgr->maxGnuIncoming = atoi(arg);
+                                       
+
+
+                                       // connections
+                                       else if (strcmp(curr,"maxcin")==0)
+                                               servMgr->maxControl = getCGIargINT(arg);
+
+                                       else if (strcmp(curr,"maxup")==0)
+                                               servMgr->maxBitrateOut = getCGIargINT(arg);
+                                       else if (strcmp(curr,"maxrelays")==0)
+                                               servMgr->setMaxRelays(getCGIargINT(arg));
+                                       else if (strcmp(curr,"maxdirect")==0)
+                                               servMgr->maxDirect = getCGIargINT(arg);
+                                       else if (strcmp(curr,"maxrelaypc")==0)
+                                               chanMgr->maxRelaysPerChannel = getCGIargINT(arg);
+                                       else if (strncmp(curr,"filt_",5)==0)
+                                       {
+                                               if (!beginfilt) {
+                                                       servMgr->numFilters = 0;
+                                                       beginfilt = true;
+                                               }
+                                               char *fs = curr+5;
+                                               {
+                                                       if (strncmp(fs,"ip",2)==0)              // ip must be first
+                                                       {
+                                                               currFilter = &servMgr->filters[servMgr->numFilters];
+                                                               currFilter->init();     
+                                                               currFilter->host.fromStrIP(arg,DEFAULT_PORT);
+                                                               if ((currFilter->host.ip) && (servMgr->numFilters < (ServMgr::MAX_FILTERS-1)))
+                                                               {
+                                                                       servMgr->numFilters++;
+                                                                       servMgr->filters[servMgr->numFilters].init();   // clear new entry
+                                                               }
+
+                                                       }else if (strncmp(fs,"bn",2)==0)
+                                                               currFilter->flags |= ServFilter::F_BAN;
+                                                       else if (strncmp(fs,"pr",2)==0)
+                                                               currFilter->flags |= ServFilter::F_PRIVATE;
+                                                       else if (strncmp(fs,"nw",2)==0)
+                                                               currFilter->flags |= ServFilter::F_NETWORK;
+                                                       else if (strncmp(fs,"di",2)==0)
+                                                               currFilter->flags |= ServFilter::F_DIRECT;
+                                               }
+                                       }
+
+                                       // client
+                                       else if (strcmp(curr,"clientactive")==0)
+                                               servMgr->autoConnect = getCGIargBOOL(arg);
+                                       else if (strcmp(curr,"yp")==0)
+                                       {
+                                               if (!PCP_FORCE_YP)
+                                               {
+                                                       String str(arg,String::T_ESC);
+                                                       str.convertTo(String::T_ASCII);
+                                                       servMgr->rootHost = str;
+                                               }
+                                       }
+                                       else if (strcmp(curr,"yp2")==0)
+                                       {
+                                               if (!PCP_FORCE_YP)
+                                               {
+                                                       String str(arg,String::T_ESC);
+                                                       str.convertTo(String::T_ASCII);
+                                                       servMgr->rootHost2 = str;
+                                               }
+                                       }
+                                       else if (strcmp(curr,"deadhitage")==0)
+                                               chanMgr->deadHitAge = getCGIargINT(arg);
+                                       else if (strcmp(curr,"refresh")==0)
+                                               servMgr->refreshHTML = getCGIargINT(arg);
+                                       else if (strcmp(curr,"auth")==0)
+                                       {
+                                               if (strcmp(arg,"cookie")==0)
+                                                       servMgr->authType = ServMgr::AUTH_COOKIE;
+                                               else if (strcmp(arg,"http")==0)
+                                                       servMgr->authType = ServMgr::AUTH_HTTPBASIC;
+
+                                       }else if (strcmp(curr,"expire")==0)
+                                       {
+                                               if (strcmp(arg,"session")==0)
+                                                       servMgr->cookieList.neverExpire = false;
+                                               else if (strcmp(arg,"never")==0)
+                                                       servMgr->cookieList.neverExpire = true;
+                                       }
+
+                                       else if (strcmp(curr,"logDebug")==0)
+                                               showLog |= atoi(arg)?(1<<LogBuffer::T_DEBUG):0;
+                                       else if (strcmp(curr,"logErrors")==0)
+                                               showLog |= atoi(arg)?(1<<LogBuffer::T_ERROR):0;
+                                       else if (strcmp(curr,"logNetwork")==0)
+                                               showLog |= atoi(arg)?(1<<LogBuffer::T_NETWORK):0;
+                                       else if (strcmp(curr,"logChannel")==0)
+                                               showLog |= atoi(arg)?(1<<LogBuffer::T_CHANNEL):0;
+
+                                       else if (strcmp(curr,"allowHTML1")==0)
+                                               allowServer1 |= atoi(arg)?(ALLOW_HTML):0;
+                                       else if (strcmp(curr,"allowNetwork1")==0)
+                                               allowServer1 |= atoi(arg)?(ALLOW_NETWORK):0;
+                                       else if (strcmp(curr,"allowBroadcast1")==0)
+                                               allowServer1 |= atoi(arg)?(ALLOW_BROADCAST):0;
+                                       else if (strcmp(curr,"allowDirect1")==0)
+                                               allowServer1 |= atoi(arg)?(ALLOW_DIRECT):0;
+
+                                       else if (strcmp(curr,"allowHTML2")==0)
+                                               allowServer2 |= atoi(arg)?(ALLOW_HTML):0;
+                                       else if (strcmp(curr,"allowBroadcast2")==0)
+                                               allowServer2 |= atoi(arg)?(ALLOW_BROADCAST):0;
+
+                                       // JP-EX
+                                       else if (strcmp(curr, "autoRelayKeep") ==0)
+                                                       servMgr->autoRelayKeep = getCGIargINT(arg);
+                                       else if (strcmp(curr, "autoMaxRelaySetting") ==0)
+                                                       servMgr->autoMaxRelaySetting = getCGIargINT(arg);
+                                       else if (strcmp(curr, "autoBumpSkipCount") ==0)
+                                                       servMgr->autoBumpSkipCount = getCGIargINT(arg);
+                                       else if (strcmp(curr, "kickPushStartRelays") ==0)
+                                                       servMgr->kickPushStartRelays = getCGIargINT(arg);
+                                       else if (strcmp(curr, "kickPushInterval") ==0)
+                                                       servMgr->kickPushInterval = getCGIargINT(arg);
+                                       else if (strcmp(curr, "allowConnectPCST") ==0)
+                                               allowConnectPCST = atoi(arg) ? 1 : 0;
+                                       else if (strcmp(curr, "enableGetName") ==0)
+                                               enableGetName = atoi(arg)? 1 : 0;
+                                       else if (strcmp(curr, "autoPort0Kick") ==0)
+                                               servMgr->autoPort0Kick = getCGIargBOOL(arg);
+                                       else if (strcmp(curr, "allowOnlyVP") ==0)
+                                               servMgr->allowOnlyVP = getCGIargBOOL(arg);
+                                       else if (strcmp(curr, "kickKeepTime") ==0)
+                                               servMgr->kickKeepTime = getCGIargINT(arg);
+
+                                       else if (strcmp(curr, "maxRelaysIndexTxt") ==0)         // for PCRaw (relay)
+                                               servMgr->maxRelaysIndexTxt = getCGIargINT(arg);
+                               }
+
+
+
+                               servMgr->showLog = showLog;
+                               servMgr->allowServer1 = allowServer1;
+                               servMgr->allowServer2 = allowServer2;
+                               servMgr->enableGetName = enableGetName;
+                               servMgr->allowConnectPCST = allowConnectPCST;
+                               if (!(servMgr->allowServer1 & ALLOW_HTML) && !(servMgr->allowServer2 & ALLOW_HTML))
+                                       servMgr->allowServer1 |= ALLOW_HTML;
+
+                               if (servMgr->serverHost.port != newPort)
+                               {
+                                       Host lh(ClientSocket::getIP(NULL),newPort);
+                                       char ipstr[64];
+                                       lh.toStr(ipstr);
+                                       sprintf(jumpStr,"http://%s/%s/settings.html",ipstr,servMgr->htmlPath);                                  
+
+                                       servMgr->serverHost.port = newPort;
+                                       servMgr->restartServer=true;
+                                       //html.setRefresh(3);
+                                       //html.setRefreshURL(jumpStr);
+                                       //html.startHTML();
+                                       //html.addHead();
+                                       //      html.startBody();
+                                       //              html.startTagEnd("h1","Please wait...");
+                                       //      html.end();
+                                       //html.end();
+
+                                       
+
+                                       //char ipstr[64];
+                                       //servMgr->serverHost.toStr(ipstr);
+                                       //sprintf(jumpStr,"/%s/settings.html",ipstr,servMgr->htmlPath);                                 
+                                       jumpArg = jumpStr;
+
+                               }else
+                               {
+                                       sprintf(jumpStr,"/%s/settings.html",servMgr->htmlPath);                                 
+                                       jumpArg = jumpStr;
+                               }
+
+                               peercastInst->saveSettings();
+
+                               peercastApp->updateSettings();
+
+                               if ((servMgr->isRoot) && (brRoot))
+                                       servMgr->broadcastRootSettings(getUpd);
+
+
+
+                               
+
+                       }else if (cmpCGIarg(cmd,"cmd=","fetch"))
+                       {
+
+                               ChanInfo info;
+                               String curl;
+
+                               char *cp = cmd;
+                               while (cp=nextCGIarg(cp,curr,arg))
+                               {
+                                       if (strcmp(curr,"url")==0)
+                                       {
+                                               curl.set(arg,String::T_ESC);
+                                               curl.convertTo(String::T_UNICODE);
+                                       }else if (strcmp(curr,"name")==0)
+                                       {
+                                               info.name.set(arg,String::T_ESC);
+                                               info.name.convertTo(String::T_UNICODE);
+                                       }else if (strcmp(curr,"desc")==0)
+                                       {
+                                               info.desc.set(arg,String::T_ESC);
+                                               info.desc.convertTo(String::T_UNICODE);
+                                       }else if (strcmp(curr,"genre")==0)
+                                       {
+                                               info.genre.set(arg,String::T_ESC);
+                                               info.genre.convertTo(String::T_UNICODE);
+                                       }else if (strcmp(curr,"contact")==0)
+                                       {
+                                               info.url.set(arg,String::T_ESC);
+                                               info.url.convertTo(String::T_UNICODE);
+                                       }else if (strcmp(curr,"bitrate")==0)
+                                       {
+                                               info.bitrate = atoi(arg);
+                                       }else if (strcmp(curr,"type")==0)
+                                       {
+                                               info.contentType = ChanInfo::getTypeFromStr(arg);
+                                       }
+
+                               }
+                               
+                               info.bcID = chanMgr->broadcastID;
+
+                               Channel *c = chanMgr->createChannel(info,NULL);
+                               if (c)
+                                       c->startURL(curl.cstr());
+
+
+                               sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath);                                   
+                               jumpArg = jumpStr;
+
+                       }else if (cmpCGIarg(cmd,"cmd=","stopserv"))
+                       {
+
+                               char *cp = cmd;
+                               while (cp=nextCGIarg(cp,curr,arg))
+                               {
+                                       if (strcmp(curr,"index")==0)
+                                       {
+                                               Servent *s = servMgr->findServentByIndex(atoi(arg));
+                                               if (s)
+                                                       s->abort();
+                                       }
+                               }
+                               sprintf(jumpStr,"/%s/connections.html",servMgr->htmlPath);                                      
+                               jumpArg = jumpStr;
+
+
+                       }else if (cmpCGIarg(cmd,"cmd=","hitlist"))
+                       {                       
+                                       
+                               bool stayConnected=hasCGIarg(cmd,"relay");
+
+                               int index = 0;
+                               ChanHitList *chl = chanMgr->hitlist;                            
+                               while (chl)
+                               {
+                                       if (chl->isUsed())
+                                       {
+                                               char tmp[64];
+                                               sprintf(tmp,"c%d=",index);
+                                               if (cmpCGIarg(cmd,tmp,"1"))
+                                               {
+                                                       Channel *c;
+                                                       if (!(c=chanMgr->findChannelByID(chl->info.id)))
+                                                       {
+                                                               c = chanMgr->createChannel(chl->info,NULL);
+                                                               if (!c)
+                                                                       throw StreamException("out of channels");
+                                                               c->stayConnected = stayConnected;
+                                                               c->startGet();
+                                                       }
+                                               }
+                                       }
+                                       chl = chl->next;
+                                       index++;
+                               }
+
+                               char *findArg = getCGIarg(cmd,"keywords=");
+
+                               if (hasCGIarg(cmd,"relay"))
+                               {
+                                       sys->sleep(500);
+                                       sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath);                                   
+                                       jumpArg = jumpStr;
+                               }
+                       }else if (cmpCGIarg(cmd,"cmd=","clear"))
+                       {
+                               char *cp = cmd;
+                               while (cp=nextCGIarg(cp,curr,arg))
+                               {
+                                       if (strcmp(curr,"hostcache")==0)
+                                               servMgr->clearHostCache(ServHost::T_SERVENT);
+                                       else if (strcmp(curr,"hitlists")==0)
+                                               chanMgr->clearHitLists();
+                                       else if (strcmp(curr,"packets")==0)
+                                       {
+                                               stats.clearRange(Stats::PACKETSSTART,Stats::PACKETSEND);
+                                               servMgr->numVersions = 0;
+                                       }
+                               }
+
+                               sprintf(jumpStr,"/%s/index.html",servMgr->htmlPath);                                    
+                               jumpArg = jumpStr;
+
+                       }else if (cmpCGIarg(cmd,"cmd=","upgrade"))
+                       {
+                               if (servMgr->downloadURL[0])
+                               {
+                                       sprintf(jumpStr,"/admin?cmd=redirect&url=%s",servMgr->downloadURL);
+                                       jumpArg = jumpStr;
+                               }
+
+
+
+
+                       }else if (cmpCGIarg(cmd,"cmd=","connect"))
+                       {                       
+                                       
+
+                               Servent *s = servMgr->servents;
+                               {
+                                       char tmp[64];
+                                       sprintf(tmp,"c%d=",s->serventIndex);
+                                       if (cmpCGIarg(cmd,tmp,"1"))
+                                       {
+                                               if (hasCGIarg(cmd,"stop"))
+                                                       s->thread.active = false;
+                                       }
+                                       s=s->next;
+                               }
+                               sprintf(jumpStr,"/%s/connections.html",servMgr->htmlPath);                                      
+                               jumpArg = jumpStr;
+
+                       }else if (cmpCGIarg(cmd,"cmd=","shutdown"))
+                       {
+                               servMgr->shutdownTimer = 1;
+
+                       }else if (cmpCGIarg(cmd,"cmd=","stop"))
+                       {
+                               GnuID id;
+                               char *cp = cmd;
+                               while (cp=nextCGIarg(cp,curr,arg))
+                               {
+                                       if (strcmp(curr,"id")==0)
+                                               id.fromStr(arg);
+                               }
+
+                               Channel *c = chanMgr->findChannelByID(id);
+                               if (c){
+                                       c->thread.active = false;
+                                       c->thread.finish = true;
+                               }
+
+                               sys->sleep(500);
+                               sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath);                                   
+                               jumpArg = jumpStr;
+
+                       }else if (cmpCGIarg(cmd,"cmd=","bump"))
+                       {
+                               GnuID id;
+                               char *cp = cmd;
+                               while (cp=nextCGIarg(cp,curr,arg))
+                               {
+                                       if (strcmp(curr,"id")==0)
+                                               id.fromStr(arg);
+                               }
+
+                               Channel *c = chanMgr->findChannelByID(id);
+                               if (c)
+                                       c->bump = true;
+
+                               sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath);                                   
+                               jumpArg = jumpStr;
+
+                       }else if (cmpCGIarg(cmd,"cmd=","keep"))
+                       {
+                               GnuID id;
+                               char *cp = cmd;
+                               while (cp=nextCGIarg(cp,curr,arg))
+                               {
+                                       if (strcmp(curr,"id")==0)
+                                               id.fromStr(arg);
+                               }
+
+                               Channel *c = chanMgr->findChannelByID(id);
+                               if (c)
+                               { //JP-Patch
+                                       //c->stayConnected = true;
+                                       if (!c->stayConnected)
+                                       {
+                                               //if (servMgr->getFirewall() == ServMgr::FW_OFF)
+                                               c->stayConnected = true;
+                                       }
+                                       else
+                                               c->stayConnected = false;
+                               } //JP-Patch
+
+                               sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath);                                   
+                               jumpArg = jumpStr;
+
+                       }else if (cmpCGIarg(cmd,"cmd=","relay"))
+                       {
+                               ChanInfo info;
+                               char *cp = cmd;
+                               while (cp=nextCGIarg(cp,curr,arg))
+                               {
+                                       if (strcmp(curr,"id")==0)
+                                               info.id.fromStr(arg);
+                               }
+
+
+                               if (!chanMgr->findChannelByID(info.id))
+                               {
+
+                                       ChanHitList *chl = chanMgr->findHitList(info);
+                                       if (!chl)
+                                               throw StreamException("channel not found");
+
+
+                                       Channel *c = chanMgr->createChannel(chl->info,NULL);
+                                       if (!c)
+                                               throw StreamException("out of channels");
+
+                                       c->stayConnected = true;
+                                       c->startGet();
+                               }
+
+                               sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath);                                   
+                               jumpArg = jumpStr;
+
+
+                       }else if (cmpCGIarg(cmd,"net=","add"))
+                       {
+                               
+                               GnuID id;
+                               id.clear();
+                               while (cmd=nextCGIarg(cmd,curr,arg))
+                               {
+                                       if (strcmp(curr,"ip")==0)
+                                       {
+                                               Host h;
+                                               h.fromStrIP(arg,DEFAULT_PORT);
+                                               if (servMgr->addOutgoing(h,id,true))
+                                                       LOG_NETWORK("Added connection: %s",arg);
+
+                                       }else if (strcmp(curr,"id")==0)
+                                       {
+                                               id.fromStr(arg);
+                                       }
+
+                               }
+
+                       }else if (cmpCGIarg(cmd,"cmd=","logout"))
+                       {
+                               jumpArg = "/";
+                               servMgr->cookieList.remove(cookie);
+
+                       }else if (cmpCGIarg(cmd,"cmd=","login"))
+                       {
+                               GnuID id;
+                               char idstr[64];
+                               id.generate();
+                               id.toStr(idstr);
+
+                               cookie.set(idstr,sock->host.ip);
+                               servMgr->cookieList.add(cookie);        
+
+                               http.writeLine(HTTP_SC_FOUND);
+                               if (servMgr->cookieList.neverExpire)
+                                       http.writeLineF("%s id=%s; path=/; expires=\"Mon, 01-Jan-3000 00:00:00 GMT\";",HTTP_HS_SETCOOKIE,idstr);
+                               else
+                                       http.writeLineF("%s id=%s; path=/;",HTTP_HS_SETCOOKIE,idstr);
+                               http.writeLineF("Location: /%s/index.html",servMgr->htmlPath);
+                               http.writeLine("");
+
+                       }else if (cmpCGIarg(cmd,"cmd=","setmeta"))
+                       {
+                               char *cp = cmd;
+                               while (cp=nextCGIarg(cp,curr,arg))
+                               {
+                                       if (strcmp(curr,"name")==0)
+                                       {
+/*                                             String chname;
+                                               chname.set(arg,String::T_ESC);
+                                               chname.convertTo(String::T_ASCII);
+                                               for(int i=0; i<ChanMgr::MAX_CHANNELS; i++)
+                                               {
+                                                       Channel *c = &chanMgr->channels[i];
+                                                       if ((c->isActive()) && (c->status == Channel::S_BROADCASTING) && (strcmp(c->info.name.cstr(),chname.cstr())==0)) 
+                                                       {       
+                                                               ChanInfo newInfo = c->info;
+
+                                                               while (cmd=nextCGIarg(cmd,curr,arg))
+                                                               {
+                                                                       String chmeta;
+                                                                       chmeta.set(arg,String::T_ESC);
+                                                                       chmeta.convertTo(String::T_ASCII);
+                                                                       if (strcmp(curr,"desc")==0)
+                                                                               newInfo.desc = chmeta.cstr();
+                                                                       else if (strcmp(curr,"url")==0)
+                                                                               newInfo.url = chmeta.cstr();
+                                                                       else if (strcmp(curr,"genre")==0)
+                                                                               newInfo.genre = chmeta.cstr();
+                                                                       else if (strcmp(curr,"comment")==0)
+                                                                               newInfo.comment = chmeta.cstr();
+                                                                       else if (strcmp(curr,"t_contact")==0)
+                                                                               newInfo.track.contact = chmeta.cstr();
+                                                                       else if (strcmp(curr,"t_title")==0)
+                                                                               newInfo.track.title = chmeta.cstr();
+                                                                       else if (strcmp(curr,"t_artist")==0)
+                                                                               newInfo.track.artist = chmeta.cstr();
+                                                                       else if (strcmp(curr,"t_album")==0)
+                                                                               newInfo.track.album = chmeta.cstr();
+                                                                       else if (strcmp(curr,"t_genre")==0)
+                                                                               newInfo.track.genre = chmeta.cstr();
+                                                               }
+                                                               c->updateInfo(newInfo);
+                                                               char idstr[64];
+                                                               newInfo.id.toStr(idstr);
+                                                               sprintf(jumpStr,"/%s/relayinfo.html?id=%s",servMgr->htmlPath,idstr);
+                                                               jumpArg = jumpStr;
+                                                               break;
+                                                       }
+                                               }*/
+                                               String chname;
+                                               chname.set(arg,String::T_ESC);
+                                               chname.convertTo(String::T_ASCII);
+
+                                               Channel *c = chanMgr->findChannelByName(chname.cstr());
+                                               if (c && (c->isActive()) && (c->status == Channel::S_BROADCASTING)){
+                                                       ChanInfo newInfo = c->info;
+                                                       while (cmd=nextCGIarg(cmd,curr,arg))
+                                                       {
+                                                               String chmeta;
+                                                               chmeta.set(arg,String::T_ESC);
+                                                               chmeta.convertTo(String::T_ASCII);
+                                                               if (strcmp(curr,"desc")==0)
+                                                                       newInfo.desc = chmeta.cstr();
+                                                               else if (strcmp(curr,"url")==0)
+                                                                       newInfo.url = chmeta.cstr();
+                                                               else if (strcmp(curr,"genre")==0)
+                                                                       newInfo.genre = chmeta.cstr();
+                                                               else if (strcmp(curr,"comment")==0)
+                                                                       newInfo.comment = chmeta.cstr();
+                                                               else if (strcmp(curr,"t_contact")==0)
+                                                                       newInfo.track.contact = chmeta.cstr();
+                                                               else if (strcmp(curr,"t_title")==0)
+                                                                       newInfo.track.title = chmeta.cstr();
+                                                               else if (strcmp(curr,"t_artist")==0)
+                                                                       newInfo.track.artist = chmeta.cstr();
+                                                               else if (strcmp(curr,"t_album")==0)
+                                                                       newInfo.track.album = chmeta.cstr();
+                                                               else if (strcmp(curr,"t_genre")==0)
+                                                                       newInfo.track.genre = chmeta.cstr();
+                                                       }
+                                                       c->updateInfo(newInfo);
+                                                       char idstr[64];
+                                                       newInfo.id.toStr(idstr);
+                                                       sprintf(jumpStr,"/%s/relayinfo.html?id=%s",servMgr->htmlPath,idstr);
+                                                       jumpArg = jumpStr;
+                                               }
+                                       }
+                               }
+                               if (!jumpArg)
+                               {
+                                       jumpArg = "/";
+                               }
+                
+                       }else{
+
+                               sprintf(jumpStr,"/%s/index.html",servMgr->htmlPath);                                    
+                               jumpArg = jumpStr;
+                       }
+               }
+
+       }catch(StreamException &e)
+       {
+               html.startTagEnd("h1","ERROR - %s",e.msg);
+               LOG_ERROR("html: %s",e.msg);
+       }
+
+
+       if (retHTML)
+       {
+               if (jumpArg)
+               {
+                       String jmp(jumpArg,String::T_HTML);
+                       jmp.convertTo(String::T_ASCII);
+                       html.locateTo(jmp.cstr());
+               }
+       }
+
+
+}
+// -----------------------------------
+static XML::Node *createChannelXML(Channel *c)
+{
+       XML::Node *n = c->info.createChannelXML();
+       n->add(c->createRelayXML(true));
+       n->add(c->info.createTrackXML());
+//     n->add(c->info.createServentXML());
+       return n;
+}
+// -----------------------------------
+static XML::Node *createChannelXML(ChanHitList *chl)
+{
+       XML::Node *n = chl->info.createChannelXML();
+       n->add(chl->createXML());
+       n->add(chl->info.createTrackXML());
+//     n->add(chl->info.createServentXML());
+       return n;
+}
+// -----------------------------------
+void Servent::handshakeXML()
+{
+       int i;
+                               
+
+
+       XML xml;
+
+       XML::Node *rn = new XML::Node("peercast");
+       xml.setRoot(rn);
+
+
+       rn->add(new XML::Node("servent uptime=\"%d\"",servMgr->getUptime()));
+
+       rn->add(new XML::Node("bandwidth out=\"%d\" in=\"%d\"",
+               stats.getPerSecond(Stats::BYTESOUT)-stats.getPerSecond(Stats::LOCALBYTESOUT),
+               stats.getPerSecond(Stats::BYTESIN)-stats.getPerSecond(Stats::LOCALBYTESIN)
+               ));
+
+       rn->add(new XML::Node("connections total=\"%d\" relays=\"%d\" direct=\"%d\"",servMgr->totalConnected(),servMgr->numStreams(Servent::T_RELAY,true),servMgr->numStreams(Servent::T_DIRECT,true)));
+
+       XML::Node *an = new XML::Node("channels_relayed total=\"%d\"",chanMgr->numChannels());
+       rn->add(an);
+
+       Channel *c = chanMgr->channel;
+       while (c)
+       {
+               if (c->isActive())
+                       an->add(createChannelXML(c));
+               c=c->next;
+       }
+
+
+       // add public channels
+       {
+               XML::Node *fn = new XML::Node("channels_found total=\"%d\"",chanMgr->numHitLists());
+               rn->add(fn);
+
+               ChanHitList *chl = chanMgr->hitlist;
+               while (chl)
+               {
+                       if (chl->isUsed())
+                               fn->add(createChannelXML(chl));
+                       chl = chl->next;
+               }
+       }
+
+
+#if 0
+       if (servMgr->isRoot)
+       {
+               // add private channels
+               {
+                       XML::Node *pn = new XML::Node("priv_channels");
+                       rn->add(pn);
+
+                       ChanHitList *chl = chanMgr->hitlist;
+                       while (chl)
+                       {
+                               if (chl->isUsed())
+                                       if (chl->info.isPrivate())
+                                               pn->add(createChannelXML(chl));
+                               chl = chl->next;
+                       }
+               }
+       }
+#endif
+
+       XML::Node *hc = new XML::Node("host_cache");
+       for(i=0; i<ServMgr::MAX_HOSTCACHE; i++)
+       {
+               ServHost *sh = &servMgr->hostCache[i];
+               if (sh->type != ServHost::T_NONE)
+               {
+                       char ipstr[64];
+                       sh->host.toStr(ipstr);
+
+                       hc->add(new XML::Node("host ip=\"%s\" type=\"%s\" time=\"%d\"",ipstr,ServHost::getTypeStr(sh->type),sh->time));
+
+               }
+       }
+       rn->add(hc);
+
+
+    sock->writeLine(HTTP_SC_OK);
+       sock->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT);
+    sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XML);
+       sock->writeLine("Connection: close");
+
+    sock->writeLine("");
+
+       xml.write(*sock);
+
+}
+// -----------------------------------
+void Servent::readICYHeader(HTTP &http, ChanInfo &info, char *pwd)
+{
+       char *arg = http.getArgStr();
+       if (!arg) return;
+
+       if (http.isHeader("x-audiocast-name") || http.isHeader("icy-name") || http.isHeader("ice-name"))
+       {
+               info.name.set(arg,String::T_ASCII);
+               info.name.convertTo(String::T_UNICODE);
+
+       }else if (http.isHeader("x-audiocast-url") || http.isHeader("icy-url") || http.isHeader("ice-url"))
+               info.url.set(arg,String::T_ASCII);
+       else if (http.isHeader("x-audiocast-bitrate") || (http.isHeader("icy-br")) || http.isHeader("ice-bitrate") || http.isHeader("icy-bitrate"))
+               info.bitrate = atoi(arg);
+       else if (http.isHeader("x-audiocast-genre") || http.isHeader("ice-genre") || http.isHeader("icy-genre"))
+       {
+               info.genre.set(arg,String::T_ASCII);
+               info.genre.convertTo(String::T_UNICODE);
+
+       }else if (http.isHeader("x-audiocast-description") || http.isHeader("ice-description"))
+       {
+               info.desc.set(arg,String::T_ASCII);
+               info.desc.convertTo(String::T_UNICODE);
+
+       }else if (http.isHeader("Authorization"))
+               http.getAuthUserPass(NULL,pwd);
+       else if (http.isHeader(PCX_HS_CHANNELID))
+               info.id.fromStr(arg);
+       else if (http.isHeader("ice-password"))
+       {
+               if (pwd)
+                       if (strlen(arg) < 64)
+                               strcpy(pwd,arg);
+       }else if (http.isHeader("content-type"))
+       {
+               if (stristr(arg,MIME_OGG))
+                       info.contentType = ChanInfo::T_OGG;
+               else if (stristr(arg,MIME_XOGG))
+                       info.contentType = ChanInfo::T_OGG;
+
+               else if (stristr(arg,MIME_MP3))
+                       info.contentType = ChanInfo::T_MP3;
+               else if (stristr(arg,MIME_XMP3))
+                       info.contentType = ChanInfo::T_MP3;
+
+               else if (stristr(arg,MIME_WMA))
+                       info.contentType = ChanInfo::T_WMA;
+               else if (stristr(arg,MIME_WMV))
+                       info.contentType = ChanInfo::T_WMV;
+               else if (stristr(arg,MIME_ASX))
+                       info.contentType = ChanInfo::T_ASX;
+
+               else if (stristr(arg,MIME_NSV))
+                       info.contentType = ChanInfo::T_NSV;
+               else if (stristr(arg,MIME_RAW))
+                       info.contentType = ChanInfo::T_RAW;
+
+               else if (stristr(arg,MIME_MMS))
+                       info.srcProtocol = ChanInfo::SP_MMS;
+               else if (stristr(arg,MIME_XPCP))
+                       info.srcProtocol = ChanInfo::SP_PCP;
+               else if (stristr(arg,MIME_XPEERCAST))
+                       info.srcProtocol = ChanInfo::SP_PEERCAST;
+
+               else if (stristr(arg,MIME_XSCPLS))
+                       info.contentType = ChanInfo::T_PLS;
+               else if (stristr(arg,MIME_PLS))
+                       info.contentType = ChanInfo::T_PLS;
+               else if (stristr(arg,MIME_XPLS))
+                       info.contentType = ChanInfo::T_PLS;
+               else if (stristr(arg,MIME_M3U))
+                       info.contentType = ChanInfo::T_PLS;
+               else if (stristr(arg,MIME_MPEGURL))
+                       info.contentType = ChanInfo::T_PLS;
+               else if (stristr(arg,MIME_TEXT))
+                       info.contentType = ChanInfo::T_PLS;
+
+
+       }
+
+}
+
+// -----------------------------------
+void Servent::handshakeICY(Channel::SRC_TYPE type, bool isHTTP)
+{
+       ChanInfo info;
+
+       HTTP http(*sock);
+
+       // default to mp3 for shoutcast DSP (doesn`t send content-type)
+       if (type == Channel::SRC_SHOUTCAST)
+               info.contentType = ChanInfo::T_MP3;
+
+       while (http.nextHeader())
+       {
+               LOG_DEBUG("ICY %s",http.cmdLine);
+               readICYHeader(http,info,loginPassword);
+       }
+
+
+               
+       // check password before anything else, if needed
+       if (strcmp(servMgr->password,loginPassword)!=0)
+       {
+               if (!sock->host.isLocalhost() || strlen(loginPassword))
+                       throw HTTPException(HTTP_SC_UNAUTHORIZED,401);
+       }
+
+               
+       // we need a valid IP address before we start
+       servMgr->checkFirewall();
+
+
+       // attach channel ID to name, channel ID is also encoded with IP address 
+       // to help prevent channel hijacking. 
+
+
+       info.id = chanMgr->broadcastID;
+       info.id.encode(NULL,info.name.cstr(),loginMount,info.bitrate);
+
+       LOG_DEBUG("Incoming source: %s : %s",info.name.cstr(),ChanInfo::getTypeStr(info.contentType));
+
+
+       if (isHTTP)
+               sock->writeStringF("%s\n\n",HTTP_SC_OK);
+       else
+               sock->writeLine("OK");
+
+       Channel *c = chanMgr->findChannelByID(info.id);
+       if (c)
+       {
+               LOG_CHANNEL("ICY channel already active, closing old one");
+               c->thread.shutdown();
+       }
+
+
+       info.comment = chanMgr->broadcastMsg;
+       info.bcID = chanMgr->broadcastID;
+
+       c = chanMgr->createChannel(info,loginMount);
+       if (!c)
+               throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+       c->startICY(sock,type);
+}
+
+
+// -----------------------------------
+void Servent::handshakeLocalFile(const char *fn)
+{
+       HTTP http(*sock);
+       String fileName;
+       
+       if (servMgr->getModulePath) //JP-EX
+       {
+               peercastApp->getDirectory();
+               fileName = servMgr->modulePath;
+       }else
+               fileName = peercastApp->getPath();
+       
+       fileName.append(fn);
+
+       LOG_DEBUG("Writing HTML file: %s",fileName.cstr());
+
+       HTML html("",*sock);
+
+       char *args = strstr(fileName.cstr(),"?");
+       if (args)
+               *args++=0;
+
+       if (fileName.contains(".htm"))
+       {
+               html.writeOK(MIME_HTML);
+               html.writeTemplate(fileName.cstr(),args);
+
+       }else if (fileName.contains(".css"))
+       {
+               html.writeOK(MIME_CSS);
+               html.writeRawFile(fileName.cstr());
+       }else if (fileName.contains(".jpg"))
+       {
+               html.writeOK(MIME_JPEG);
+               html.writeRawFile(fileName.cstr());
+       }else if (fileName.contains(".gif"))
+       {
+               html.writeOK(MIME_GIF);
+               html.writeRawFile(fileName.cstr());
+       }else if (fileName.contains(".png"))
+       {
+               html.writeOK(MIME_PNG);
+               html.writeRawFile(fileName.cstr());
+       }
+}
+
+// -----------------------------------
+void Servent::handshakeRemoteFile(const char *dirName)
+{
+       ClientSocket *rsock = sys->createSocket();
+       if (!rsock)
+               throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+
+       const char *hostName = "www.peercast.org";      // hardwired for "security"
+
+       Host host;
+       host.fromStrName(hostName,80);
+
+
+       rsock->open(host);
+       rsock->connect();
+
+       HTTP rhttp(*rsock);
+
+       rhttp.writeLineF("GET /%s HTTP/1.0",dirName);
+       rhttp.writeLineF("%s %s",HTTP_HS_HOST,hostName);
+       rhttp.writeLineF("%s %s",HTTP_HS_CONNECTION,"close");
+       rhttp.writeLineF("%s %s",HTTP_HS_ACCEPT,"*/*");
+       rhttp.writeLine("");
+
+       String contentType;
+       bool isTemplate = false;
+       while (rhttp.nextHeader())
+       {
+               char *arg = rhttp.getArgStr();
+               if (arg) 
+               {
+                       if (rhttp.isHeader("content-type"))
+                               contentType = arg;
+               }
+       }
+
+       MemoryStream mem(100*1024);
+       while (!rsock->eof())
+       {
+               int len=0;
+               char buf[4096];
+               len = rsock->readUpto(buf,sizeof(buf));
+               if (len==0)
+                       break;
+               else
+                       mem.write(buf,len);
+
+       }
+       rsock->close();
+
+       int fileLen = mem.getPosition();
+       mem.len = fileLen;
+       mem.rewind();
+
+
+       if (contentType.contains(MIME_HTML))
+               isTemplate = true;
+
+       sock->writeLine(HTTP_SC_OK);
+       sock->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT);
+       sock->writeLineF("%s %s",HTTP_HS_CACHE,"no-cache");
+       sock->writeLineF("%s %s",HTTP_HS_CONNECTION,"close");
+       sock->writeLineF("%s %s",HTTP_HS_CONTENT,contentType.cstr());
+
+       sock->writeLine("");
+
+       if (isTemplate)
+       {
+               HTML html("",*sock);
+               html.readTemplate(mem,sock,0);
+       }else
+               sock->write(mem.buf,fileLen);
+
+       mem.free2();
+}
diff --git a/PeerCast.root/PeerCast/core/common/servmgr.cpp b/PeerCast.root/PeerCast/core/common/servmgr.cpp
new file mode 100644 (file)
index 0000000..7f72944
--- /dev/null
@@ -0,0 +1,2608 @@
+// ------------------------------------------------
+// File : servmgr.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             Management class for handling multiple servent connections.
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include <stdlib.h>
+#include "servent.h"
+#include "servmgr.h"
+#include "inifile.h"
+#include "stats.h"
+#include "peercast.h"
+#include "pcp.h"
+#include "atom.h"
+#include "version2.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+ThreadInfo ServMgr::serverThread,ServMgr::idleThread;
+
+// -----------------------------------
+ServMgr::ServMgr()
+{
+       validBCID = NULL;
+
+       authType = AUTH_COOKIE;
+       cookieList.init();
+
+       serventNum = 0;
+
+       startTime = sys->getTime();
+
+       allowServer1 = Servent::ALLOW_ALL;
+       allowServer2 = Servent::ALLOW_BROADCAST;
+
+       clearHostCache(ServHost::T_NONE);
+       password[0]=0;
+
+       allowGnutella = false;
+       useFlowControl = true;
+
+       maxServIn = 50;
+       minGnuIncoming = 10;
+       maxGnuIncoming = 20;
+
+       lastIncoming = 0;
+
+       maxBitrateOut = 540; //JP-Patch 0-> 540
+       maxRelays = MIN_RELAYS;
+       maxDirect = 0;
+       refreshHTML = 1800;
+
+       networkID.clear();
+
+       notifyMask = 0xffff;
+
+       tryoutDelay = 10;
+       numVersions = 0;
+
+       sessionID.generate();
+
+       isDisabled = false;
+       isRoot = false;
+
+       forceIP.clear();
+
+       strcpy(connectHost,"connect1.peercast.org");
+       strcpy(htmlPath,"html/ja");
+
+       rootHost = "yp.peercast.org";
+       rootHost2 = "";
+
+       serverHost.fromStrIP("127.0.0.1",DEFAULT_PORT);
+
+       firewalled = FW_UNKNOWN;                
+       allowDirect = true;
+       autoConnect = true;
+       forceLookup = true;
+       autoServe = true;
+       forceNormal = false;
+
+       maxControl = 3;
+
+       queryTTL = 7;
+
+       totalStreams = 0;
+       firewallTimeout = 30;
+       pauseLog = false;
+       showLog = 0;
+
+       shutdownTimer = 0;
+
+       downloadURL[0] = 0;
+       rootMsg.clear();
+
+
+       restartServer=false;
+
+       setFilterDefaults();
+
+       servents = NULL;
+
+       modulePath[0] = 0; //JP-EX
+       kickPushStartRelays = 1; //JP-EX
+       kickPushInterval = 60; //JP-EX
+       kickPushTime = 0; //JP-EX
+       autoRelayKeep = 2; //JP-EX
+       autoMaxRelaySetting = 0; //JP-EX
+       autoBumpSkipCount = 50; //JP-EX
+       enableGetName = 1; //JP-EX
+       allowConnectPCST = 0; //JP-EX
+       getModulePath = true; //JP-EX
+       clearPLS = false; //JP-EX
+       writeLogFile = false; //JP-EX
+
+       autoPort0Kick = false;
+       allowOnlyVP = false;
+       kickKeepTime = 0;
+       vpDebug = false;
+       saveIniChannel = true;
+       saveGuiPos = false;
+       keepDownstreams = true;
+
+       chanLog="";
+
+       maxRelaysIndexTxt = 1;  // for PCRaw (relay)
+}
+// -----------------------------------
+BCID *ServMgr::findValidBCID(int index)
+{
+       int cnt = 0;
+       BCID *bcid = validBCID;
+       while (bcid)
+       {
+               if (cnt == index)
+                       return bcid;
+               cnt++;
+               bcid=bcid->next;
+       }
+       return 0;
+}
+// -----------------------------------
+BCID *ServMgr::findValidBCID(GnuID &id)
+{
+       BCID *bcid = validBCID;
+       while (bcid)
+       {
+               if (bcid->id.isSame(id))
+                       return bcid;
+               bcid=bcid->next;
+       }
+       return 0;
+}
+// -----------------------------------
+void ServMgr::removeValidBCID(GnuID &id)
+{
+       BCID *bcid = validBCID,*prev=0;
+       while (bcid)
+       {
+               if (bcid->id.isSame(id))
+               {
+                       if (prev)
+                               prev->next = bcid->next;
+                       else
+                               validBCID = bcid->next;
+                       return;
+               }
+               prev = bcid;
+               bcid=bcid->next;
+       }
+}
+// -----------------------------------
+void ServMgr::addValidBCID(BCID *bcid)
+{
+       removeValidBCID(bcid->id);
+
+       bcid->next = validBCID;
+       validBCID = bcid;
+}
+
+// -----------------------------------
+void   ServMgr::connectBroadcaster()
+{
+       if (!rootHost.isEmpty())
+       {
+               if (!numUsed(Servent::T_COUT))
+               {
+                       Servent *sv = allocServent();
+                       if (sv)
+                       {
+                               sv->initOutgoing(Servent::T_COUT);
+                               sys->sleep(3000);
+                       }
+               }
+       }
+}
+// -----------------------------------
+void   ServMgr::addVersion(unsigned int ver)
+{
+       for(int i=0; i<numVersions; i++)
+               if (clientVersions[i] == ver)
+               {
+                       clientCounts[i]++;
+                       return;
+               }
+
+       if (numVersions < MAX_VERSIONS)
+       {
+               clientVersions[numVersions] = ver;
+               clientCounts[numVersions] = 1;
+               numVersions++;
+       }
+}
+
+// -----------------------------------
+void ServMgr::setFilterDefaults()
+{
+       numFilters = 0;
+
+       filters[numFilters].host.fromStrIP("255.255.255.255",0);
+//     filters[numFilters].flags = ServFilter::F_NETWORK|ServFilter::F_DIRECT;
+       filters[numFilters].flags = ServFilter::F_NETWORK;
+
+       numFilters++;
+
+}
+
+// -----------------------------------
+void   ServMgr::setPassiveSearch(unsigned int t)
+{
+//     if ((t > 0) && (t < 60))
+//             t = 60;
+//     passiveSearch = t;
+}
+// -----------------------------------
+bool ServMgr::seenHost(Host &h, ServHost::TYPE type,unsigned int time)
+{
+       time = sys->getTime()-time;
+
+       for(int i=0; i<MAX_HOSTCACHE; i++)
+               if (hostCache[i].type == type)
+                       if (hostCache[i].host.ip == h.ip)
+                               if (hostCache[i].time >= time)
+                                       return true;
+       return false;
+}
+
+// -----------------------------------
+void ServMgr::addHost(Host &h, ServHost::TYPE type, unsigned int time)
+{
+       int i;
+       if (!h.isValid())
+               return;
+
+       ServHost *sh=NULL;
+
+       for(i=0; i<MAX_HOSTCACHE; i++)
+               if (hostCache[i].type == type)
+                       if (hostCache[i].host.isSame(h))
+                       {
+                               sh = &hostCache[i];
+                               break;
+                       }
+
+       char str[64];
+       h.toStr(str);
+
+       if (!sh)
+               LOG_DEBUG("New host: %s - %s",str,ServHost::getTypeStr(type));
+       else
+               LOG_DEBUG("Old host: %s - %s",str,ServHost::getTypeStr(type));
+
+       h.value = 0;    // make sure dead count is zero
+       if (!sh)
+       {
+
+
+               // find empty slot
+               for(i=0; i<MAX_HOSTCACHE; i++)
+                       if (hostCache[i].type == ServHost::T_NONE)
+                       {
+                               sh = &hostCache[i];
+                               break;
+                       }
+
+               // otherwise, find oldest host and replace
+               if (!sh)
+                       for(i=0; i<MAX_HOSTCACHE; i++)
+                               if (hostCache[i].type != ServHost::T_NONE)
+                               {
+                                       if (sh)
+                                       {
+                                               if (hostCache[i].time < sh->time)
+                                                       sh = &hostCache[i];
+                                       }else{
+                                               sh = &hostCache[i];
+                                       }
+                               }
+       }
+
+       if (sh)
+               sh->init(h,type,time);
+}
+
+// -----------------------------------
+void ServMgr::deadHost(Host &h,ServHost::TYPE t)
+{
+       for(int i=0; i<MAX_HOSTCACHE; i++)
+               if (hostCache[i].type == t)
+                       if (hostCache[i].host.ip == h.ip)
+                               if (hostCache[i].host.port == h.port)
+                                       hostCache[i].init();
+}
+// -----------------------------------
+void ServMgr::clearHostCache(ServHost::TYPE type)
+{
+       for(int i=0; i<MAX_HOSTCACHE; i++)
+               if ((hostCache[i].type == type) || (type == ServHost::T_NONE))
+                       hostCache[i].init();
+}
+       
+// -----------------------------------
+unsigned int ServMgr::numHosts(ServHost::TYPE type)
+{
+       unsigned int cnt = 0;
+       for(int i=0; i<MAX_HOSTCACHE; i++)
+               if ((hostCache[i].type == type) || (type == ServHost::T_NONE))
+                       cnt++;
+       return cnt;
+}
+// -----------------------------------
+int ServMgr::getNewestServents(Host *hl,int max,Host &rh)
+{
+       int cnt=0;
+       for(int i=0; i<max; i++)
+       {
+               // find newest host not in list
+               ServHost *sh=NULL;
+               for(int j=0; j<MAX_HOSTCACHE; j++)
+               {
+                       // find newest servent
+                       if (hostCache[j].type == ServHost::T_SERVENT)
+                               if (!(rh.globalIP() && !hostCache[j].host.globalIP()))
+                               {
+                                       // and not in list already
+                                       bool found=false;
+                                       for(int k=0; k<cnt; k++)
+                                               if (hl[k].isSame(hostCache[j].host))
+                                               {
+                                                       found=true; 
+                                                       break;
+                                               }
+
+                                       if (!found)
+                                       {
+                                               if (!sh)
+                                               {
+                                                       sh = &hostCache[j];
+                                               }else{
+                                                       if (hostCache[j].time > sh->time)
+                                                               sh = &hostCache[j];
+                                               }
+                                       }
+                               }
+               }
+
+               // add to list
+               if (sh)
+                       hl[cnt++]=sh->host;
+       }
+       
+       return cnt;
+}
+// -----------------------------------
+ServHost ServMgr::getOutgoingServent(GnuID &netid)
+{
+       ServHost host;
+
+       Host lh(ClientSocket::getIP(NULL),0);
+
+       // find newest host not in list
+       ServHost *sh=NULL;
+       for(int j=0; j<MAX_HOSTCACHE; j++)
+       {
+               ServHost *hc=&hostCache[j];
+               // find newest servent not already connected.
+               if (hc->type == ServHost::T_SERVENT)
+               {
+                       if (!((lh.globalIP() && !hc->host.globalIP()) || lh.isSame(hc->host)))
+                       {
+#if 0
+                               if (!findServent(Servent::T_OUTGOING,hc->host,netid))
+                               {
+                                       if (!sh)
+                                       {
+                                               sh = hc;
+                                       }else{
+                                               if (hc->time > sh->time)
+                                                       sh = hc;
+                                       }
+                               }
+#endif
+                       }
+               }
+       }
+
+       if (sh)
+               host = *sh;
+
+       return host;
+}
+// -----------------------------------
+Servent *ServMgr::findOldestServent(Servent::TYPE type, bool priv)
+{
+       Servent *oldest=NULL;
+
+       Servent *s = servents;
+       while (s)
+       {
+               if (s->type == type)
+                       if (s->thread.active)
+                               if (s->isOlderThan(oldest))
+                                       if (s->isPrivate() == priv)
+                                               oldest = s;
+               s=s->next;
+       }
+       return oldest;
+}
+// -----------------------------------
+Servent *ServMgr::findServent(Servent::TYPE type, Host &host, GnuID &netid)
+{
+       lock.on();
+       Servent *s = servents;
+       while (s)
+       {
+               if (s->type == type)
+               {
+                       Host h = s->getHost();
+                       if (h.isSame(host) && s->networkID.isSame(netid))
+                       {
+                               lock.off();
+                               return s;
+                       }
+               }
+               s=s->next;
+       }
+       lock.off();
+       return NULL;
+
+}
+
+// -----------------------------------
+Servent *ServMgr::findServent(unsigned int ip, unsigned short port, GnuID &netid)
+{
+       lock.on();
+       Servent *s = servents;
+       while (s)
+       {
+               if (s->type != Servent::T_NONE)
+               {
+                       Host h = s->getHost();
+                       if ((h.ip == ip) && (h.port == port) && (s->networkID.isSame(netid)))
+                       {
+                               lock.off();
+                               return s;
+                       }
+               }
+               s=s->next;
+       }
+       lock.off();
+       return NULL;
+
+}
+
+// -----------------------------------
+Servent *ServMgr::findServent(Servent::TYPE t)
+{
+       Servent *s = servents;
+       while (s)
+       {
+               if (s->type == t)
+                       return s;
+               s=s->next;
+       }
+       return NULL;
+}
+// -----------------------------------
+Servent *ServMgr::findServentByIndex(int id)
+{
+       Servent *s = servents;
+       int cnt=0;
+       while (s)
+       {
+               if (cnt == id)
+                       return s;
+                       cnt++;
+               s=s->next;
+       }
+       return NULL;
+}
+
+// -----------------------------------
+Servent *ServMgr::findServentByServentID(int id)
+{
+       Servent *s = servents;
+       while (s)
+       {
+               if (id == s->servent_id){
+                       return s;
+               }
+               s=s->next;
+       }
+       return NULL;
+}
+
+// -----------------------------------
+Servent *ServMgr::allocServent()
+{
+       lock.on();
+
+       Servent *s = servents;
+       while (s)
+       {
+               if (s->status == Servent::S_FREE)
+                       break;
+               s=s->next;
+       }
+
+       if (!s)
+       {
+               s = new Servent(++serventNum);
+               s->next = servents;
+               servents = s;
+
+               LOG_DEBUG("allocated servent %d",serventNum);
+       }else
+               LOG_DEBUG("reused servent %d",s->serventIndex);
+
+
+       s->reset();
+
+       lock.off();
+
+       return s;
+}
+// --------------------------------------------------
+void   ServMgr::closeConnections(Servent::TYPE type)
+{
+       Servent *sv = servents;
+       while (sv)
+       {
+               if (sv->isConnected())
+                       if (sv->type == type)
+                               sv->thread.active = false;
+               sv=sv->next;
+       }
+}
+
+// -----------------------------------
+unsigned int ServMgr::numConnected(int type,bool priv,unsigned int uptime)
+{
+       unsigned int cnt=0;
+
+       unsigned int ctime=sys->getTime();
+       Servent *s = servents;
+       while (s)
+       {
+               if (s->thread.active)
+                       if (s->isConnected())
+                               if (s->type == type)
+                                       if (s->isPrivate()==priv)
+                                               if ((ctime-s->lastConnect) >= uptime)
+                                                       cnt++;
+
+               s=s->next;
+       }
+       return cnt;
+}
+// -----------------------------------
+unsigned int ServMgr::numConnected()
+{
+       unsigned int cnt=0;
+
+       Servent *s = servents;
+       while (s)
+       {
+               if (s->thread.active)
+                       if (s->isConnected())
+                               cnt++;
+
+               s=s->next;
+       }
+       return cnt;
+}
+// -----------------------------------
+unsigned int ServMgr::numServents()
+{
+       unsigned int cnt=0;
+
+       Servent *s = servents;
+       while (s)
+       {
+               cnt++;
+               s=s->next;
+       }
+       return cnt;
+}
+
+// -----------------------------------
+unsigned int ServMgr::numUsed(int type)
+{
+       unsigned int cnt=0;
+
+       Servent *s = servents;
+       while (s)
+       {
+               if (s->type == type)
+                       cnt++;
+               s=s->next;
+       }
+       return cnt;
+}
+// -----------------------------------
+unsigned int ServMgr::numActiveOnPort(int port)
+{
+       unsigned int cnt=0;
+
+       Servent *s = servents;
+       while (s)
+       {
+               if (s->thread.active && s->sock && (s->servPort == port))
+                       cnt++;
+               s=s->next;
+       }
+       return cnt;
+}
+// -----------------------------------
+unsigned int ServMgr::numActive(Servent::TYPE tp)
+{
+       unsigned int cnt=0;
+
+       Servent *s = servents;
+       while (s)
+       {
+               if (s->thread.active && s->sock && (s->type == tp))
+                       cnt++;
+               s=s->next;
+       }
+       return cnt;
+}
+
+// -----------------------------------
+unsigned int ServMgr::totalOutput(bool all)
+{
+       unsigned int tot = 0;
+       Servent *s = servents;
+       while (s)
+       {
+               if (s->isConnected())
+                       if (all || !s->isPrivate())
+                               if (s->sock)
+                                       tot += s->sock->bytesOutPerSec;
+               s=s->next;
+       }
+
+       return tot;
+}
+
+// -----------------------------------
+unsigned int ServMgr::totalInput(bool all)
+{
+       unsigned int tot = 0;
+       Servent *s = servents;
+       while (s)
+       {
+               if (s->isConnected())
+                       if (all || !s->isPrivate())
+                               if (s->sock)
+                                       tot += s->sock->bytesInPerSec;
+               s=s->next;
+       }
+
+       return tot;
+}
+
+// -----------------------------------
+unsigned int ServMgr::numOutgoing()
+{
+       int cnt=0;
+
+       Servent *s = servents;
+       while (s)
+       {
+//             if ((s->type == Servent::T_INCOMING) ||
+//                 (s->type == Servent::T_OUTGOING)) 
+//                     cnt++;
+               s=s->next;
+       }
+       return cnt;
+}
+
+// -----------------------------------
+bool ServMgr::seenPacket(GnuPacket &p)
+{
+       Servent *s = servents;
+       while (s)
+       {
+               if (s->isConnected())
+                       if (s->seenIDs.contains(p.id))
+                               return true;
+               s=s->next;
+       }
+       return false;
+}
+
+// -----------------------------------
+void ServMgr::quit()
+{
+       LOG_DEBUG("ServMgr is quitting..");
+
+       serverThread.shutdown();
+
+       idleThread.shutdown();
+
+       Servent *s = servents;
+       while (s)
+       {
+               try
+               {
+                       if (s->thread.active)
+                       {
+                               s->thread.shutdown();
+                       }
+
+               }catch(StreamException &)
+               {
+               }
+               s=s->next;
+       }
+}
+
+// -----------------------------------
+int ServMgr::broadcast(GnuPacket &pack,Servent *src)
+{
+       int cnt=0;
+       if (pack.ttl)
+       {
+               Servent *s = servents;
+               while (s)
+               {
+
+                       if (s != src)
+                               if (s->isConnected())
+                                       if (s->type == Servent::T_PGNU)
+                                               if (!s->seenIDs.contains(pack.id))
+                                               {
+
+                                                       if (src)
+                                                               if (!src->networkID.isSame(s->networkID))
+                                                                       continue;
+
+                                                       if (s->outputPacket(pack,false))
+                                                               cnt++;
+                                               }
+                       s=s->next;
+               }
+       }
+
+       LOG_NETWORK("broadcast: %s (%d) to %d servents",GNU_FUNC_STR(pack.func),pack.ttl,cnt);
+
+       return cnt;
+}
+// -----------------------------------
+int ServMgr::route(GnuPacket &pack, GnuID &routeID, Servent *src)
+{
+       int cnt=0;
+       if (pack.ttl)
+       {
+               Servent *s = servents;
+               while (s)
+               {
+                       if (s != src)
+                               if (s->isConnected())
+                                       if (s->type == Servent::T_PGNU)
+                                               if (!s->seenIDs.contains(pack.id))
+                                                       if (s->seenIDs.contains(routeID))
+                                                       {
+                                                               if (src)
+                                                                       if (!src->networkID.isSame(s->networkID))
+                                                                               continue;
+
+                                                               if (s->outputPacket(pack,true))
+                                                                       cnt++;
+                                                       }
+                       s=s->next;
+               }
+
+       }
+
+       LOG_NETWORK("route: %s (%d) to %d servents",GNU_FUNC_STR(pack.func),pack.ttl,cnt);
+       return cnt;
+}
+// -----------------------------------
+bool ServMgr::checkForceIP()
+{
+       if (!forceIP.isEmpty())
+       {
+               unsigned int newIP = ClientSocket::getIP(forceIP.cstr());
+               if (serverHost.ip != newIP)
+               {
+                       serverHost.ip = newIP;
+                       char ipstr[64];
+                       serverHost.IPtoStr(ipstr);
+                       LOG_DEBUG("Server IP changed to %s",ipstr);
+                       return true;
+               }
+       }
+       return false;
+}
+
+// -----------------------------------
+void ServMgr::checkFirewall()
+{
+       if ((getFirewall() == FW_UNKNOWN) && !servMgr->rootHost.isEmpty())
+       {
+
+               LOG_DEBUG("Checking firewall..");
+               Host host;
+               host.fromStrName(servMgr->rootHost.cstr(),DEFAULT_PORT);
+
+               ClientSocket *sock = sys->createSocket();
+               if (!sock)
+                       throw StreamException("Unable to create socket");
+               sock->setReadTimeout(30000);
+               sock->open(host);
+               sock->connect();
+
+               AtomStream atom(*sock);
+
+               atom.writeInt(PCP_CONNECT,1);
+
+               GnuID remoteID;
+               String agent;
+               Servent::handshakeOutgoingPCP(atom,sock->host,remoteID,agent,true);
+
+               atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT);
+
+               sock->close();
+               delete sock;
+       }
+}
+
+// -----------------------------------
+void ServMgr::setFirewall(FW_STATE state)
+{
+       if (firewalled != state)
+       {
+               char *str;
+               switch (state)
+               {
+                       case FW_ON:
+                               str = "ON";
+                               break;
+                       case FW_OFF:
+                               str = "OFF";
+                               break;
+                       case FW_UNKNOWN:
+                       default:
+                               str = "UNKNOWN";
+                               break;
+               }
+
+               LOG_DEBUG("Firewall is set to %s",str);
+               firewalled = state;
+       }
+}
+// -----------------------------------
+bool ServMgr::isFiltered(int fl, Host &h)
+{
+       for(int i=0; i<numFilters; i++)
+               if (filters[i].flags & fl)
+                       if (h.isMemberOf(filters[i].host))
+                               return true;
+
+       return false;
+}
+
+#if 0
+// -----------------------------------
+bool ServMgr::canServeHost(Host &h)
+{
+       if (server)
+       {
+               Host sh = server->getHost();
+
+               if (sh.globalIP() || (sh.localIP() && h.localIP()))
+                       return true;            
+       }
+       return false;
+}
+#endif
+
+// --------------------------------------------------
+void writeServerSettings(IniFile &iniFile, unsigned int a)
+{
+       iniFile.writeBoolValue("allowHTML",a & Servent::ALLOW_HTML);
+       iniFile.writeBoolValue("allowBroadcast",a & Servent::ALLOW_BROADCAST);
+       iniFile.writeBoolValue("allowNetwork",a & Servent::ALLOW_NETWORK);
+       iniFile.writeBoolValue("allowDirect",a & Servent::ALLOW_DIRECT);
+}
+// --------------------------------------------------
+void writeFilterSettings(IniFile &iniFile, ServFilter &f)
+{
+       char ipstr[64];
+       f.host.IPtoStr(ipstr);
+       iniFile.writeStrValue("ip",ipstr);
+       iniFile.writeBoolValue("private",f.flags & ServFilter::F_PRIVATE);
+       iniFile.writeBoolValue("ban",f.flags & ServFilter::F_BAN);
+       iniFile.writeBoolValue("network",f.flags & ServFilter::F_NETWORK);
+       iniFile.writeBoolValue("direct",f.flags & ServFilter::F_DIRECT);
+}
+
+// --------------------------------------------------
+static void  writeServHost(IniFile &iniFile, ServHost &sh)
+{
+       iniFile.writeSection("Host");
+
+       char ipStr[64];
+       sh.host.toStr(ipStr);
+       iniFile.writeStrValue("type",ServHost::getTypeStr(sh.type));
+       iniFile.writeStrValue("address",ipStr);
+       iniFile.writeIntValue("time",sh.time);
+
+       iniFile.writeLine("[End]");
+}
+
+#ifdef WIN32
+extern bool guiFlg;
+extern WINDOWPLACEMENT winPlace;
+extern HWND guiWnd;
+#endif
+
+// --------------------------------------------------
+void ServMgr::saveSettings(const char *fn)
+{
+       IniFile iniFile;
+       if (!iniFile.openWriteReplace(fn))
+       {
+               LOG_ERROR("Unable to open ini file");
+       }else{
+               LOG_DEBUG("Saving settings to:  %s",fn);
+
+               char idStr[64];
+
+               iniFile.writeSection("Server");
+               iniFile.writeIntValue("serverPort",servMgr->serverHost.port);
+               iniFile.writeBoolValue("autoServe",servMgr->autoServe);
+               iniFile.writeStrValue("forceIP",servMgr->forceIP);
+               iniFile.writeBoolValue("isRoot",servMgr->isRoot);
+               iniFile.writeIntValue("maxBitrateOut",servMgr->maxBitrateOut);
+               iniFile.writeIntValue("maxRelays",servMgr->maxRelays);
+               iniFile.writeIntValue("maxDirect",servMgr->maxDirect);
+               iniFile.writeIntValue("maxRelaysPerChannel",chanMgr->maxRelaysPerChannel);
+               iniFile.writeIntValue("firewallTimeout",firewallTimeout);
+               iniFile.writeBoolValue("forceNormal",forceNormal);
+               iniFile.writeStrValue("rootMsg",rootMsg.cstr());
+               iniFile.writeStrValue("authType",servMgr->authType==ServMgr::AUTH_COOKIE?"cookie":"http-basic");
+               iniFile.writeStrValue("cookiesExpire",servMgr->cookieList.neverExpire==true?"never":"session");
+               iniFile.writeStrValue("htmlPath",servMgr->htmlPath);
+               iniFile.writeIntValue("minPGNUIncoming",servMgr->minGnuIncoming);
+               iniFile.writeIntValue("maxPGNUIncoming",servMgr->maxGnuIncoming);
+               iniFile.writeIntValue("maxServIn",servMgr->maxServIn);
+               iniFile.writeStrValue("chanLog",servMgr->chanLog.cstr());
+
+               networkID.toStr(idStr);
+               iniFile.writeStrValue("networkID",idStr);
+
+
+               iniFile.writeSection("Broadcast");
+               iniFile.writeIntValue("broadcastMsgInterval",chanMgr->broadcastMsgInterval);
+               iniFile.writeStrValue("broadcastMsg",chanMgr->broadcastMsg.cstr());
+               iniFile.writeIntValue("icyMetaInterval",chanMgr->icyMetaInterval);
+               chanMgr->broadcastID.toStr(idStr);
+               iniFile.writeStrValue("broadcastID",idStr);             
+               iniFile.writeIntValue("hostUpdateInterval",chanMgr->hostUpdateInterval);
+               iniFile.writeIntValue("maxControlConnections",servMgr->maxControl);
+               iniFile.writeStrValue("rootHost",servMgr->rootHost.cstr());
+
+               iniFile.writeSection("Client");
+               iniFile.writeIntValue("refreshHTML",refreshHTML);
+               iniFile.writeIntValue("relayBroadcast",servMgr->relayBroadcast);
+               iniFile.writeIntValue("minBroadcastTTL",chanMgr->minBroadcastTTL);
+               iniFile.writeIntValue("maxBroadcastTTL",chanMgr->maxBroadcastTTL);
+               iniFile.writeIntValue("pushTries",chanMgr->pushTries);
+               iniFile.writeIntValue("pushTimeout",chanMgr->pushTimeout);
+               iniFile.writeIntValue("maxPushHops",chanMgr->maxPushHops);
+               iniFile.writeIntValue("autoQuery",chanMgr->autoQuery);
+               iniFile.writeIntValue("queryTTL",servMgr->queryTTL);
+
+
+               iniFile.writeSection("Privacy");
+               iniFile.writeStrValue("password",servMgr->password);
+               iniFile.writeIntValue("maxUptime",chanMgr->maxUptime);
+
+               //JP-EX
+               iniFile.writeSection("Extend");
+               iniFile.writeIntValue("autoRelayKeep",servMgr->autoRelayKeep);
+               iniFile.writeIntValue("autoMaxRelaySetting",servMgr->autoMaxRelaySetting);
+               iniFile.writeIntValue("autoBumpSkipCount",servMgr->autoBumpSkipCount);
+               iniFile.writeIntValue("kickPushStartRelays",servMgr->kickPushStartRelays);
+               iniFile.writeIntValue("kickPushInterval",servMgr->kickPushInterval);
+               iniFile.writeIntValue("allowConnectPCST",servMgr->allowConnectPCST);
+               iniFile.writeIntValue("enableGetName",servMgr->enableGetName);
+
+               iniFile.writeIntValue("maxRelaysIndexTxt", servMgr->maxRelaysIndexTxt); // for PCRaw (relay)
+
+               //JP-EX
+               iniFile.writeSection("Windows");
+               iniFile.writeBoolValue("getModulePath",servMgr->getModulePath);
+               iniFile.writeBoolValue("clearPLS",servMgr->clearPLS);
+               iniFile.writeBoolValue("writeLogFile",servMgr->writeLogFile);
+
+               //VP-EX
+               iniFile.writeStrValue("rootHost2",servMgr->rootHost2.cstr());
+               iniFile.writeBoolValue("autoPort0Kick",servMgr->autoPort0Kick);
+               iniFile.writeBoolValue("allowOnlyVP",servMgr->allowOnlyVP);
+               iniFile.writeIntValue("kickKeepTime",servMgr->kickKeepTime);
+               iniFile.writeBoolValue("vpDebug", servMgr->vpDebug);
+               iniFile.writeBoolValue("saveIniChannel", servMgr->saveIniChannel);
+#ifdef WIN32
+               iniFile.writeBoolValue("saveGuiPos", servMgr->saveGuiPos);
+               if (guiFlg){
+                       GetWindowPlacement(guiWnd, &winPlace);
+                       iniFile.writeIntValue("guiTop", winPlace.rcNormalPosition.top);
+                       iniFile.writeIntValue("guiBottom", winPlace.rcNormalPosition.bottom);
+                       iniFile.writeIntValue("guiLeft", winPlace.rcNormalPosition.left);
+                       iniFile.writeIntValue("guiRight", winPlace.rcNormalPosition.right);
+               }
+#endif
+               int i;
+
+               for(i=0; i<servMgr->numFilters; i++)
+               {
+                       iniFile.writeSection("Filter");
+                               writeFilterSettings(iniFile,servMgr->filters[i]);
+                       iniFile.writeLine("[End]");
+               }
+
+               iniFile.writeSection("Notify");
+                       iniFile.writeBoolValue("PeerCast",notifyMask&NT_PEERCAST);
+                       iniFile.writeBoolValue("Broadcasters",notifyMask&NT_BROADCASTERS);
+                       iniFile.writeBoolValue("TrackInfo",notifyMask&NT_TRACKINFO);
+               iniFile.writeLine("[End]");
+
+
+               iniFile.writeSection("Server1");
+                       writeServerSettings(iniFile,allowServer1);
+               iniFile.writeLine("[End]");
+
+               iniFile.writeSection("Server2");
+                       writeServerSettings(iniFile,allowServer2);
+               iniFile.writeLine("[End]");
+
+
+
+               iniFile.writeSection("Debug");
+               iniFile.writeBoolValue("logDebug",(showLog&(1<<LogBuffer::T_DEBUG))!=0);
+               iniFile.writeBoolValue("logErrors",(showLog&(1<<LogBuffer::T_ERROR))!=0);
+               iniFile.writeBoolValue("logNetwork",(showLog&(1<<LogBuffer::T_NETWORK))!=0);
+               iniFile.writeBoolValue("logChannel",(showLog&(1<<LogBuffer::T_CHANNEL))!=0);
+               iniFile.writeBoolValue("pauseLog",pauseLog);
+               iniFile.writeIntValue("idleSleepTime",sys->idleSleepTime);
+
+
+               if (servMgr->validBCID)
+               {
+                       BCID *bcid = servMgr->validBCID;
+                       while (bcid)
+                       {
+                               iniFile.writeSection("ValidBCID");
+                               char idstr[128];
+                               bcid->id.toStr(idstr);
+                               iniFile.writeStrValue("id",idstr);
+                               iniFile.writeStrValue("name",bcid->name.cstr());
+                               iniFile.writeStrValue("email",bcid->email.cstr());
+                               iniFile.writeStrValue("url",bcid->url.cstr());
+                               iniFile.writeBoolValue("valid",bcid->valid);
+                               iniFile.writeLine("[End]");
+                               
+                               bcid=bcid->next;
+                       }
+               }
+
+               if (servMgr->saveIniChannel){
+                       Channel *c = chanMgr->channel;
+                       while (c)
+                       {
+                               char idstr[64];
+                               if (c->isActive() && c->stayConnected)
+                               {
+                                       c->getIDStr(idstr);
+
+                                       iniFile.writeSection("RelayChannel");
+                                       iniFile.writeStrValue("name",c->getName());
+                                       iniFile.writeStrValue("genre",c->info.genre.cstr());
+                                       if (!c->sourceURL.isEmpty())
+                                               iniFile.writeStrValue("sourceURL",c->sourceURL.cstr());
+                                       iniFile.writeStrValue("sourceProtocol",ChanInfo::getProtocolStr(c->info.srcProtocol));
+                                       iniFile.writeStrValue("contentType",ChanInfo::getTypeStr(c->info.contentType));
+                                       iniFile.writeIntValue("bitrate",c->info.bitrate);
+                                       iniFile.writeStrValue("contactURL",c->info.url.cstr());
+                                       iniFile.writeStrValue("id",idstr);
+                                       iniFile.writeBoolValue("stayConnected",c->stayConnected);
+
+                                       ChanHitList *chl = chanMgr->findHitListByID(c->info.id);
+                                       if (chl)
+                                       {
+
+                                               ChanHitSearch chs;
+                                               chs.trackersOnly = true;
+                                               if (chl->pickHits(chs))
+                                               {
+                                                       char ipStr[64];
+                                                       chs.best[0].host.toStr(ipStr);
+                                                       iniFile.writeStrValue("tracker",ipStr);
+                                               }
+                                       }
+                                       iniFile.writeLine("[End]");
+                               }
+                               c=c->next;
+                       }
+               }
+               
+
+               
+#if 0
+               Servent *s = servents;
+               while (s)
+               {
+                       if (s->type == Servent::T_OUTGOING)
+                               if (s->isConnected())
+                               {
+                                       ServHost sh;
+                                       Host h = s->getHost();
+                                       sh.init(h,ServHost::T_SERVENT,0,s->networkID);
+                                       writeServHost(iniFile,sh);
+                               }
+                       s=s->next;
+               }
+#endif
+
+               for(i=0; i<ServMgr::MAX_HOSTCACHE; i++)
+               {
+                       ServHost *sh = &servMgr->hostCache[i];
+                       if (sh->type != ServHost::T_NONE)
+                               writeServHost(iniFile,*sh);
+               }
+
+               iniFile.close();
+       }
+}
+// --------------------------------------------------
+unsigned int readServerSettings(IniFile &iniFile, unsigned int a)
+{
+       while (iniFile.readNext())
+       {
+               if (iniFile.isName("[End]"))
+                       break;
+               else if (iniFile.isName("allowHTML"))
+                       a = iniFile.getBoolValue()?a|Servent::ALLOW_HTML:a&~Servent::ALLOW_HTML;
+               else if (iniFile.isName("allowDirect"))
+                       a = iniFile.getBoolValue()?a|Servent::ALLOW_DIRECT:a&~Servent::ALLOW_DIRECT;
+               else if (iniFile.isName("allowNetwork"))
+                       a = iniFile.getBoolValue()?a|Servent::ALLOW_NETWORK:a&~Servent::ALLOW_NETWORK;
+               else if (iniFile.isName("allowBroadcast"))
+                       a = iniFile.getBoolValue()?a|Servent::ALLOW_BROADCAST:a&~Servent::ALLOW_BROADCAST;
+       }
+       return a;
+}
+// --------------------------------------------------
+void readFilterSettings(IniFile &iniFile, ServFilter &sv)
+{
+       sv.host.init();
+
+       while (iniFile.readNext())
+       {
+               if (iniFile.isName("[End]"))
+                       break;
+               else if (iniFile.isName("ip"))
+                       sv.host.fromStrIP(iniFile.getStrValue(),0);
+               else if (iniFile.isName("private"))
+                       sv.flags = (sv.flags & ~ServFilter::F_PRIVATE) | (iniFile.getBoolValue()?ServFilter::F_PRIVATE:0);
+               else if (iniFile.isName("ban"))
+                       sv.flags = (sv.flags & ~ServFilter::F_BAN) | (iniFile.getBoolValue()?ServFilter::F_BAN:0);
+               else if (iniFile.isName("allow") || iniFile.isName("network"))
+                       sv.flags = (sv.flags & ~ServFilter::F_NETWORK) | (iniFile.getBoolValue()?ServFilter::F_NETWORK:0);
+               else if (iniFile.isName("direct"))
+                       sv.flags = (sv.flags & ~ServFilter::F_DIRECT) | (iniFile.getBoolValue()?ServFilter::F_DIRECT:0);
+       }
+
+}
+// --------------------------------------------------
+void ServMgr::loadSettings(const char *fn)
+{
+       IniFile iniFile;
+
+       if (!iniFile.openReadOnly(fn))
+               saveSettings(fn);
+
+
+       servMgr->numFilters = 0;
+       showLog = 0;
+
+       if (iniFile.openReadOnly(fn))
+       {
+               while (iniFile.readNext())
+               {
+                       // server settings
+                       if (iniFile.isName("serverPort"))
+                               servMgr->serverHost.port = iniFile.getIntValue();
+                       else if (iniFile.isName("autoServe"))
+                               servMgr->autoServe = iniFile.getBoolValue();
+                       else if (iniFile.isName("autoConnect"))
+                               servMgr->autoConnect = iniFile.getBoolValue();
+                       else if (iniFile.isName("icyPassword"))         // depreciated
+                               strcpy(servMgr->password,iniFile.getStrValue());
+                       else if (iniFile.isName("forceIP"))
+                               servMgr->forceIP = iniFile.getStrValue();
+                       else if (iniFile.isName("isRoot"))
+                               servMgr->isRoot = iniFile.getBoolValue();
+                       else if (iniFile.isName("broadcastID"))
+                       {
+                               chanMgr->broadcastID.fromStr(iniFile.getStrValue());
+                               chanMgr->broadcastID.id[0] = PCP_BROADCAST_FLAGS;                       // hacky, but we need to fix old clients
+
+                       }else if (iniFile.isName("htmlPath"))
+                               strcpy(servMgr->htmlPath,iniFile.getStrValue());
+                       else if (iniFile.isName("maxPGNUIncoming"))
+                               servMgr->maxGnuIncoming = iniFile.getIntValue();
+                       else if (iniFile.isName("minPGNUIncoming"))
+                               servMgr->minGnuIncoming = iniFile.getIntValue();
+
+                       else if (iniFile.isName("maxControlConnections"))
+                       {
+                               servMgr->maxControl = iniFile.getIntValue();
+
+                       }
+                       else if (iniFile.isName("maxBitrateOut"))
+                               servMgr->maxBitrateOut = iniFile.getIntValue();
+
+                       else if (iniFile.isName("maxStreamsOut"))               // depreciated
+                               servMgr->setMaxRelays(iniFile.getIntValue());
+                       else if (iniFile.isName("maxRelays"))           
+                               servMgr->setMaxRelays(iniFile.getIntValue());
+                       else if (iniFile.isName("maxDirect"))           
+                               servMgr->maxDirect = iniFile.getIntValue();
+
+                       else if (iniFile.isName("maxStreamsPerChannel"))                // depreciated
+                               chanMgr->maxRelaysPerChannel = iniFile.getIntValue();
+                       else if (iniFile.isName("maxRelaysPerChannel"))
+                               chanMgr->maxRelaysPerChannel = iniFile.getIntValue();
+
+                       else if (iniFile.isName("firewallTimeout"))
+                               firewallTimeout = iniFile.getIntValue();
+                       else if (iniFile.isName("forceNormal"))
+                               forceNormal = iniFile.getBoolValue();
+                       else if (iniFile.isName("broadcastMsgInterval"))
+                               chanMgr->broadcastMsgInterval = iniFile.getIntValue();
+                       else if (iniFile.isName("broadcastMsg"))
+                               chanMgr->broadcastMsg.set(iniFile.getStrValue(),String::T_ASCII);
+                       else if (iniFile.isName("hostUpdateInterval"))
+                               chanMgr->hostUpdateInterval = iniFile.getIntValue();
+                       else if (iniFile.isName("icyMetaInterval"))
+                               chanMgr->icyMetaInterval = iniFile.getIntValue();
+                       else if (iniFile.isName("maxServIn"))
+                               servMgr->maxServIn = iniFile.getIntValue();
+                       else if (iniFile.isName("chanLog"))
+                               servMgr->chanLog.set(iniFile.getStrValue(),String::T_ASCII);
+
+                       else if (iniFile.isName("rootMsg"))
+                               rootMsg.set(iniFile.getStrValue());
+                       else if (iniFile.isName("networkID"))
+                               networkID.fromStr(iniFile.getStrValue());
+                       else if (iniFile.isName("authType"))
+                       {
+                               char *t = iniFile.getStrValue();
+                               if (stricmp(t,"cookie")==0)
+                                       servMgr->authType = ServMgr::AUTH_COOKIE;
+                               else if (stricmp(t,"http-basic")==0)
+                                       servMgr->authType = ServMgr::AUTH_HTTPBASIC;
+                       }else if (iniFile.isName("cookiesExpire"))
+                       {
+                               char *t = iniFile.getStrValue();
+                               if (stricmp(t,"never")==0)
+                                       servMgr->cookieList.neverExpire = true;
+                               else if (stricmp(t,"session")==0)
+                                       servMgr->cookieList.neverExpire = false;
+
+
+                       }
+
+                       // privacy settings
+                       else if (iniFile.isName("password"))
+                               strcpy(servMgr->password,iniFile.getStrValue());
+                       else if (iniFile.isName("maxUptime"))
+                               chanMgr->maxUptime = iniFile.getIntValue();
+
+                       // client settings
+
+                       else if (iniFile.isName("rootHost"))
+                       {
+                               if (!PCP_FORCE_YP)
+                                       servMgr->rootHost = iniFile.getStrValue();
+
+                       }else if (iniFile.isName("deadHitAge"))
+                               chanMgr->deadHitAge = iniFile.getIntValue();
+                       else if (iniFile.isName("tryoutDelay"))
+                               servMgr->tryoutDelay = iniFile.getIntValue();
+                       else if (iniFile.isName("refreshHTML"))
+                               refreshHTML = iniFile.getIntValue();
+                       else if (iniFile.isName("relayBroadcast"))
+                       {
+                               servMgr->relayBroadcast = iniFile.getIntValue();
+                               if (servMgr->relayBroadcast < 30)
+                                       servMgr->relayBroadcast = 30;
+                       }
+                       else if (iniFile.isName("minBroadcastTTL"))
+                               chanMgr->minBroadcastTTL = iniFile.getIntValue();
+                       else if (iniFile.isName("maxBroadcastTTL"))
+                               chanMgr->maxBroadcastTTL = iniFile.getIntValue();
+                       else if (iniFile.isName("pushTimeout"))
+                               chanMgr->pushTimeout = iniFile.getIntValue();
+                       else if (iniFile.isName("pushTries"))
+                               chanMgr->pushTries = iniFile.getIntValue();
+                       else if (iniFile.isName("maxPushHops"))
+                               chanMgr->maxPushHops = iniFile.getIntValue();
+                       else if (iniFile.isName("autoQuery"))
+                       {
+                               chanMgr->autoQuery = iniFile.getIntValue();
+                               if ((chanMgr->autoQuery < 300) && (chanMgr->autoQuery > 0))
+                                       chanMgr->autoQuery = 300;
+                       }
+                       else if (iniFile.isName("queryTTL"))
+                       {
+                               servMgr->queryTTL = iniFile.getIntValue();
+                       }
+
+                       //JP-Extend
+                       else if (iniFile.isName("autoRelayKeep"))
+                               servMgr->autoRelayKeep = iniFile.getIntValue();
+                       else if (iniFile.isName("autoMaxRelaySetting"))
+                               servMgr->autoMaxRelaySetting = iniFile.getIntValue();
+                       else if (iniFile.isName("autoBumpSkipCount"))
+                               servMgr->autoBumpSkipCount = iniFile.getIntValue();
+                       else if (iniFile.isName("kickPushStartRelays"))
+                               servMgr->kickPushStartRelays = iniFile.getIntValue();
+                       else if (iniFile.isName("kickPushInterval"))
+                       {
+                               servMgr->kickPushInterval = iniFile.getIntValue();
+                               if (servMgr->kickPushInterval < 60)
+                                       servMgr->kickPushInterval = 0;
+                       }
+                       else if (iniFile.isName("allowConnectPCST"))
+                               servMgr->allowConnectPCST = iniFile.getIntValue();
+                       else if (iniFile.isName("enableGetName"))
+                               servMgr->enableGetName = iniFile.getIntValue();
+
+                       else if (iniFile.isName("maxRelaysIndexTxt"))                   // for PCRaw (relay)
+                               servMgr->maxRelaysIndexTxt = iniFile.getIntValue();
+
+                       //JP-Windows
+                       else if (iniFile.isName("getModulePath"))
+                               servMgr->getModulePath = iniFile.getBoolValue();
+                       else if (iniFile.isName("clearPLS"))
+                               servMgr->clearPLS = iniFile.getBoolValue();
+                       else if (iniFile.isName("writeLogFile"))
+                               servMgr->writeLogFile = iniFile.getBoolValue();
+
+                       //VP-EX
+                       else if (iniFile.isName("rootHost2"))
+                       {
+                               if (!PCP_FORCE_YP)
+                                       servMgr->rootHost2 = iniFile.getStrValue();
+                       }
+                       else if (iniFile.isName("autoPort0Kick"))
+                               servMgr->autoPort0Kick = iniFile.getBoolValue();
+                       else if (iniFile.isName("allowOnlyVP"))
+                               servMgr->allowOnlyVP = iniFile.getBoolValue();
+                       else if (iniFile.isName("kickKeepTime"))
+                               servMgr->kickKeepTime = iniFile.getIntValue();
+                       else if (iniFile.isName("vpDebug"))
+                               servMgr->vpDebug = iniFile.getBoolValue();
+                       else if (iniFile.isName("saveIniChannel"))
+                               servMgr->saveIniChannel = iniFile.getBoolValue();
+#ifdef WIN32
+                       else if (iniFile.isName("saveGuiPos"))
+                               servMgr->saveGuiPos = iniFile.getBoolValue();
+                       else if (iniFile.isName("guiTop"))
+                               winPlace.rcNormalPosition.top = iniFile.getIntValue();
+                       else if (iniFile.isName("guiBottom"))
+                               winPlace.rcNormalPosition.bottom = iniFile.getIntValue();
+                       else if (iniFile.isName("guiLeft"))
+                               winPlace.rcNormalPosition.left = iniFile.getIntValue();
+                       else if (iniFile.isName("guiRight")){
+                               winPlace.rcNormalPosition.right = iniFile.getIntValue();
+                               winPlace.length = sizeof(winPlace);
+                               winPlace.flags = 0;
+                               winPlace.showCmd = 1;
+                               winPlace.ptMinPosition.x = -1;
+                               winPlace.ptMinPosition.y = -1;
+                               winPlace.ptMaxPosition.x = -1;
+                               winPlace.ptMaxPosition.y = -1;
+                               if (servMgr->saveGuiPos){
+                                       guiFlg = true;
+                               }
+                       }
+#endif
+
+                       // debug
+                       else if (iniFile.isName("logDebug"))
+                               showLog |= iniFile.getBoolValue() ? 1<<LogBuffer::T_DEBUG:0;
+                       else if (iniFile.isName("logErrors"))
+                               showLog |= iniFile.getBoolValue() ? 1<<LogBuffer::T_ERROR:0;
+                       else if (iniFile.isName("logNetwork"))
+                               showLog |= iniFile.getBoolValue() ? 1<<LogBuffer::T_NETWORK:0;
+                       else if (iniFile.isName("logChannel"))
+                               showLog |= iniFile.getBoolValue() ? 1<<LogBuffer::T_CHANNEL:0;
+                       else if (iniFile.isName("pauseLog"))
+                               pauseLog = iniFile.getBoolValue();
+                       else if (iniFile.isName("idleSleepTime"))
+                               sys->idleSleepTime = iniFile.getIntValue();
+                       else if (iniFile.isName("[Server1]"))
+                               allowServer1 = readServerSettings(iniFile,allowServer1);
+                       else if (iniFile.isName("[Server2]"))
+                               allowServer2 = readServerSettings(iniFile,allowServer2);
+                       else if (iniFile.isName("[Filter]"))
+                       {
+                               readFilterSettings(iniFile,filters[numFilters]);
+
+                               if (numFilters < (MAX_FILTERS-1))
+                                       numFilters++;
+                       }
+                       else if (iniFile.isName("[Notify]"))
+                       {
+                               notifyMask = NT_UPGRADE;
+                               while (iniFile.readNext())
+                               {
+                                       if (iniFile.isName("[End]"))
+                                               break;
+                                       else if (iniFile.isName("PeerCast"))
+                                               notifyMask |= iniFile.getBoolValue()?NT_PEERCAST:0;
+                                       else if (iniFile.isName("Broadcasters"))
+                                               notifyMask |= iniFile.getBoolValue()?NT_BROADCASTERS:0;
+                                       else if (iniFile.isName("TrackInfo"))
+                                               notifyMask |= iniFile.getBoolValue()?NT_TRACKINFO:0;
+                               }
+
+                       }
+                       else if (iniFile.isName("[RelayChannel]"))
+                       {
+                               ChanInfo info;
+                               bool stayConnected=false;
+                               String sourceURL;
+                               while (iniFile.readNext())
+                               {
+                                       if (iniFile.isName("[End]"))
+                                               break;
+                                       else if (iniFile.isName("name"))
+                                               info.name.set(iniFile.getStrValue());
+                                       else if (iniFile.isName("id"))
+                                               info.id.fromStr(iniFile.getStrValue());
+                                       else if (iniFile.isName("sourceType"))
+                                               info.srcProtocol = ChanInfo::getProtocolFromStr(iniFile.getStrValue());
+                                       else if (iniFile.isName("contentType"))
+                                               info.contentType = ChanInfo::getTypeFromStr(iniFile.getStrValue());
+                                       else if (iniFile.isName("stayConnected"))
+                                               stayConnected = iniFile.getBoolValue();
+                                       else if (iniFile.isName("sourceURL"))
+                                               sourceURL.set(iniFile.getStrValue());
+                                       else if (iniFile.isName("genre"))
+                                               info.genre.set(iniFile.getStrValue());
+                                       else if (iniFile.isName("contactURL"))
+                                               info.url.set(iniFile.getStrValue());
+                                       else if (iniFile.isName("bitrate"))
+                                               info.bitrate = atoi(iniFile.getStrValue());
+                                       else if (iniFile.isName("tracker"))
+                                       {
+                                               ChanHit hit;
+                                               hit.init();
+                                               hit.tracker = true;
+                                               hit.host.fromStrName(iniFile.getStrValue(),DEFAULT_PORT);
+                                               hit.rhost[0] = hit.host;
+                                               hit.rhost[1] = hit.host;
+                                               hit.chanID = info.id;
+                                               hit.recv = true;
+                                               chanMgr->addHit(hit);
+                                       }
+
+                               }
+                               if (sourceURL.isEmpty())
+                               {
+                                       chanMgr->createRelay(info,stayConnected);
+                               }else
+                               {
+                                       info.bcID = chanMgr->broadcastID;
+                                       Channel *c = chanMgr->createChannel(info,NULL);
+                                       if (c)
+                                               c->startURL(sourceURL.cstr());
+                               }
+                       } else if (iniFile.isName("[Host]"))
+                       {
+                               Host h;
+                               ServHost::TYPE type=ServHost::T_NONE;
+                               bool firewalled=false;
+                               unsigned int time=0;
+                               while (iniFile.readNext())
+                               {
+                                       if (iniFile.isName("[End]"))
+                                               break;
+                                       else if (iniFile.isName("address"))
+                                               h.fromStrIP(iniFile.getStrValue(),DEFAULT_PORT);
+                                       else if (iniFile.isName("type"))
+                                               type = ServHost::getTypeFromStr(iniFile.getStrValue());
+                                       else if (iniFile.isName("time"))
+                                               time = iniFile.getIntValue();
+                               }
+                               servMgr->addHost(h,type,time);
+
+                       } else if (iniFile.isName("[ValidBCID]"))
+                       {
+                               BCID *bcid = new BCID();
+                               while (iniFile.readNext())
+                               {
+                                       if (iniFile.isName("[End]"))
+                                               break;
+                                       else if (iniFile.isName("id"))
+                                               bcid->id.fromStr(iniFile.getStrValue());
+                                       else if (iniFile.isName("name"))
+                                               bcid->name.set(iniFile.getStrValue());
+                                       else if (iniFile.isName("email"))
+                                               bcid->email.set(iniFile.getStrValue());
+                                       else if (iniFile.isName("url"))
+                                               bcid->url.set(iniFile.getStrValue());
+                                       else if (iniFile.isName("valid"))
+                                               bcid->valid = iniFile.getBoolValue();
+                               }
+                               servMgr->addValidBCID(bcid);
+                       }
+               }       
+       }
+
+       if (!numFilters)
+               setFilterDefaults();
+
+}
+
+// --------------------------------------------------
+unsigned int ServMgr::numStreams(GnuID &cid, Servent::TYPE tp, bool all)
+{
+       int cnt = 0;
+       Servent *sv = servents;
+       while (sv)
+       {
+               if (sv->isConnected())
+                       if (sv->type == tp)
+                               if (sv->chanID.isSame(cid))
+                                       if (all || !sv->isPrivate())
+                                               cnt++;
+               sv=sv->next;
+       }
+       return cnt;
+}
+// --------------------------------------------------
+unsigned int ServMgr::numStreams(Servent::TYPE tp, bool all)
+{
+       int cnt = 0;
+       Servent *sv = servents;
+       while (sv)
+       {
+               if (sv->isConnected())
+                       if (sv->type == tp)
+                               if (all || !sv->isPrivate())
+                               {
+                                       // for PCRaw (relay) start.
+                                       if(tp == Servent::T_RELAY)
+                                       {
+                                               Channel *ch = chanMgr->findChannelByID(sv->chanID);
+
+                                               // index.txt\82Í\83J\83E\83\93\83g\82µ\82È\82¢
+                                               if(!isIndexTxt(ch))
+                                                       cnt++;
+                                       }
+                                       else
+                                       // for PCRaw (relay) end.
+                                       {
+                                               cnt++;
+                                       }
+                               }
+               sv=sv->next;
+       }
+       return cnt;
+}
+
+// --------------------------------------------------
+bool ServMgr::getChannel(char *str,ChanInfo &info, bool relay)
+{
+       // remove file extension (only added for winamp)
+       //char *ext = strstr(str,".");
+       //if (ext) *ext = 0;
+
+       procConnectArgs(str,info);
+
+       WLockBlock wb(&(chanMgr->channellock));
+
+       wb.on();
+       Channel *ch;
+
+       ch = chanMgr->findChannelByNameID(info);
+       if (ch && ch->thread.active)
+       {
+
+               if (!ch->isPlaying())
+               {
+                       if (relay)
+                       {
+                               ch->info.lastPlayStart = 0; // force reconnect 
+                               ch->info.lastPlayEnd = 0; 
+                       }else
+                               return false;
+               }
+               
+               info = ch->info;        // get updated channel info 
+
+               return true;
+       }else
+       {
+               if (relay)
+               {
+                       wb.off();
+                       ch = chanMgr->findAndRelay(info);
+                       if (ch)
+                       {
+                               // \81«Exception point
+                               info = ch->info; //get updated channel info 
+                               return true;
+                       }
+               }
+       }
+
+       return false;
+}
+// --------------------------------------------------
+int ServMgr::findChannel(ChanInfo &info)
+{
+#if 0
+       char idStr[64];
+       info.id.toStr(idStr);
+
+
+       if (info.id.isSet())
+       {
+               // if we have an ID then try and connect to known hosts carrying channel.
+               ServHost sh = getOutgoingServent(info.id);
+               addOutgoing(sh.host,info.id,true);
+       }
+
+       GnuPacket pack;
+
+       XML xml;
+       XML::Node *n = info.createQueryXML();
+       xml.setRoot(n);
+       pack.initFind(NULL,&xml,servMgr->queryTTL);
+
+       addReplyID(pack.id);
+       int cnt = broadcast(pack,NULL);
+
+       LOG_NETWORK("Querying network: %s %s - %d servents",info.name.cstr(),idStr,cnt);
+
+       return cnt;
+#endif
+       return 0;
+}
+// --------------------------------------------------
+// add outgoing network connection from string (ip:port format)
+bool ServMgr::addOutgoing(Host h, GnuID &netid, bool pri)
+{
+#if 0
+       if (h.ip)
+       {
+               if (!findServent(h.ip,h.port,netid))
+               {
+                       Servent *sv = allocServent();
+                       if (sv)
+                       {
+                               if (pri)
+                                       sv->priorityConnect = true;
+                               sv->networkID = netid;
+                               sv->initOutgoing(h,Servent::T_OUTGOING);
+                               return true;
+                       }
+               }
+       }
+#endif
+       return false;
+}
+// --------------------------------------------------
+Servent *ServMgr::findConnection(Servent::TYPE t,GnuID &sid)
+{
+       Servent *sv = servents;
+       while (sv)
+       {
+               if (sv->isConnected())
+                       if (sv->type == t)
+                               if (sv->remoteID.isSame(sid))                           
+                                       return sv;
+               sv=sv->next;
+       }
+       return NULL;
+}
+
+// --------------------------------------------------
+void ServMgr::procConnectArgs(char *str,ChanInfo &info)
+{
+       char arg[MAX_CGI_LEN];
+       char curr[MAX_CGI_LEN];
+
+       char *args = strstr(str,"?");
+       if (args)
+               *args++=0;
+
+       info.initNameID(str);
+
+       if (args)
+       {
+
+               while (args=nextCGIarg(args,curr,arg))
+               {
+                       LOG_DEBUG("cmd: %s, arg: %s",curr,arg);
+
+                       if (strcmp(curr,"sip")==0)
+                       // sip - add network connection to client with channel
+                       {
+                               Host h;
+                               h.fromStrName(arg,DEFAULT_PORT);
+                               if (addOutgoing(h,servMgr->networkID,true))
+                                       LOG_NETWORK("Added connection: %s",arg);
+
+                       }else if (strcmp(curr,"pip")==0)
+                       // pip - add private network connection to client with channel
+                       {
+                               Host h;
+                               h.fromStrName(arg,DEFAULT_PORT);
+                               if (addOutgoing(h,info.id,true))
+                                       LOG_NETWORK("Added private connection: %s",arg);
+                       }else if (strcmp(curr,"ip")==0)
+                       // ip - add hit
+                       {
+                               Host h;
+                               h.fromStrName(arg,DEFAULT_PORT);
+                               ChanHit hit;
+                               hit.init();
+                               hit.host = h; 
+                               hit.rhost[0] = h;
+                               hit.rhost[1].init();
+                               hit.chanID = info.id;
+                               hit.recv = true;
+
+                               chanMgr->addHit(hit);
+                       }else if (strcmp(curr,"tip")==0)
+                       // tip - add tracker hit
+                       {
+                               Host h;
+                               h.fromStrName(arg,DEFAULT_PORT);
+                               chanMgr->hitlistlock.on();
+                               chanMgr->addHit(h,info.id,true);
+                               chanMgr->hitlistlock.off();
+
+                       }
+
+
+               }
+       }
+}
+
+// --------------------------------------------------
+bool ServMgr::start()
+{
+       char idStr[64];
+
+
+       const char *priv;
+#if PRIVATE_BROADCASTER
+       priv = "(private)";
+#else
+       priv = "";
+#endif
+#ifdef VERSION_EX
+       LOG_DEBUG("Peercast %s, %s %s",PCX_VERSTRING_EX,peercastApp->getClientTypeOS(),priv);
+#else
+       LOG_DEBUG("Peercast %s, %s %s",PCX_VERSTRING,peercastApp->getClientTypeOS(),priv);
+#endif
+
+       sessionID.toStr(idStr);
+       LOG_DEBUG("SessionID: %s",idStr);
+
+       chanMgr->broadcastID.toStr(idStr);
+       LOG_DEBUG("BroadcastID: %s",idStr);
+       checkForceIP();
+
+
+       serverThread.func = ServMgr::serverProc;
+       if (!sys->startThread(&serverThread))
+               return false;
+
+       idleThread.func = ServMgr::idleProc;
+       if (!sys->startThread(&idleThread))
+               return false;
+
+       return true;
+}
+// --------------------------------------------------
+int ServMgr::clientProc(ThreadInfo *thread)
+{
+#if 0
+       thread->lock();
+
+       GnuID netID;
+       netID = servMgr->networkID;
+
+       while(thread->active)
+       {
+               if (servMgr->autoConnect)
+               {
+                       if (servMgr->needConnections() || servMgr->forceLookup)
+                       {
+                               if (servMgr->needHosts() || servMgr->forceLookup)
+                               {
+                                       // do lookup to find some hosts
+
+                                       Host lh;
+                                       lh.fromStrName(servMgr->connectHost,DEFAULT_PORT);
+
+
+                                       if (!servMgr->findServent(lh.ip,lh.port,netID))
+                                       {
+                                               Servent *sv = servMgr->allocServent();
+                                               if (sv)
+                                               {
+                                                       LOG_DEBUG("Lookup: %s",servMgr->connectHost);
+                                                       sv->networkID = netID;
+                                                       sv->initOutgoing(lh,Servent::T_LOOKUP);
+                                                       servMgr->forceLookup = false;
+                                               }
+                                       }
+                               }
+
+                               for(int i=0; i<MAX_TRYOUT; i++)
+                               {
+                                       if (servMgr->outUsedFull())
+                                               break;
+                                       if (servMgr->tryFull())
+                                               break;
+
+
+                                       ServHost sh = servMgr->getOutgoingServent(netID);
+
+                                       if (!servMgr->addOutgoing(sh.host,netID,false))
+                                               servMgr->deadHost(sh.host,ServHost::T_SERVENT);
+                                       sys->sleep(servMgr->tryoutDelay);
+                                       break;
+                               }
+                       }
+               }else{
+#if 0
+                       Servent *s = servMgr->servents;
+                       while (s)
+                       {
+
+                               if (s->type == Servent::T_OUTGOING) 
+                                       s->thread.active = false;
+                               s=s->next;
+                       }
+#endif
+               }
+               sys->sleepIdle();
+       }
+       thread->unlock();
+#endif
+       return 0;
+}
+// -----------------------------------
+bool   ServMgr::acceptGIV(ClientSocket *sock)
+{
+       Servent *sv = servents;
+       while (sv)
+       {
+               if (sv->type == Servent::T_COUT)
+               {
+                       if (sv->acceptGIV(sock))
+                               return true;
+               }
+               sv=sv->next;
+       }
+       return false;
+}
+
+// -----------------------------------
+int ServMgr::broadcastPushRequest(ChanHit &hit, Host &to, GnuID &chanID, Servent::TYPE type)
+{
+       ChanPacket pack;
+       MemoryStream pmem(pack.data,sizeof(pack.data));
+       AtomStream atom(pmem);
+
+#ifndef VERSION_EX
+               atom.writeParent(PCP_BCST,8);
+#else
+               atom.writeParent(PCP_BCST,10);
+#endif
+               atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_ALL);
+               atom.writeChar(PCP_BCST_HOPS,0);
+               atom.writeChar(PCP_BCST_TTL,7);
+               atom.writeBytes(PCP_BCST_DEST,hit.sessionID.id,16);
+               atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
+               atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
+               atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
+#ifdef VERSION_EX
+               atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
+               atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
+#endif
+               atom.writeParent(PCP_PUSH,3);
+                       atom.writeInt(PCP_PUSH_IP,to.ip);
+                       atom.writeShort(PCP_PUSH_PORT,to.port);
+                       atom.writeBytes(PCP_PUSH_CHANID,chanID.id,16);
+
+
+       pack.len = pmem.pos;
+       pack.type = ChanPacket::T_PCP;
+
+
+       GnuID noID;
+       noID.clear();
+
+       return servMgr->broadcastPacket(pack,noID,servMgr->sessionID,hit.sessionID,type);
+}
+
+// --------------------------------------------------
+void ServMgr::writeRootAtoms(AtomStream &atom, bool getUpdate)
+{
+       atom.writeParent(PCP_ROOT,5 + (getUpdate?1:0));
+               atom.writeInt(PCP_ROOT_UPDINT,chanMgr->hostUpdateInterval);
+               atom.writeString(PCP_ROOT_URL,"download.php");
+               atom.writeInt(PCP_ROOT_CHECKVER,PCP_ROOT_VERSION);
+               atom.writeInt(PCP_ROOT_NEXT,chanMgr->hostUpdateInterval);
+               atom.writeString(PCP_MESG_ASCII,rootMsg.cstr());
+               if (getUpdate)
+                       atom.writeParent(PCP_ROOT_UPDATE,0);
+
+}
+// --------------------------------------------------
+void ServMgr::broadcastRootSettings(bool getUpdate)
+{
+       if (isRoot)
+       {
+
+               ChanPacket pack;
+               MemoryStream mem(pack.data,sizeof(pack.data));
+               AtomStream atom(mem);
+#ifndef VERSION_EX
+                       atom.writeParent(PCP_BCST,7);
+#else
+                       atom.writeParent(PCP_BCST,9);
+#endif
+                       atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_TRACKERS);
+                       atom.writeChar(PCP_BCST_HOPS,0);
+                       atom.writeChar(PCP_BCST_TTL,7);
+                       atom.writeBytes(PCP_BCST_FROM,sessionID.id,16);
+                       atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
+                       atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
+#ifdef VERSION_EX
+                       atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
+                       atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
+#endif
+                       writeRootAtoms(atom,getUpdate);
+
+               mem.len = mem.pos;
+               mem.rewind();
+               pack.len = mem.len;
+
+               GnuID noID;
+               noID.clear();
+
+               broadcastPacket(pack,noID,servMgr->sessionID,noID,Servent::T_CIN);
+       }
+}
+// --------------------------------------------------
+int ServMgr::broadcastPacket(ChanPacket &pack,GnuID &chanID,GnuID &srcID, GnuID &destID, Servent::TYPE type)
+{
+       int cnt=0;
+       
+       Servent *sv = servents;
+       while (sv)
+       {
+               if (sv->sendPacket(pack,chanID,srcID,destID,type))
+                       cnt++;
+               sv=sv->next;
+       }
+       return cnt;
+}
+
+// --------------------------------------------------
+int ServMgr::idleProc(ThreadInfo *thread)
+{
+
+//     thread->lock();
+
+       unsigned int lastPasvFind=0;
+       unsigned int lastBroadcast=0;
+
+
+       // nothing much to do for the first couple of seconds, so just hang around.
+       sys->sleep(2000);       
+
+       unsigned int lastBWcheck=0;
+       unsigned int bytesIn=0,bytesOut=0;
+
+       unsigned int lastBroadcastConnect = 0;
+       unsigned int lastRootBroadcast = 0;
+
+       unsigned int lastForceIPCheck = 0;
+
+       while(thread->active)
+       {
+               stats.update();
+
+
+
+               unsigned int ctime = sys->getTime();
+
+
+               if (!servMgr->forceIP.isEmpty())
+               {
+                       if ((ctime-lastForceIPCheck) > 60)
+                       {
+                               if (servMgr->checkForceIP())
+                               {
+                                       GnuID noID;
+                                       noID.clear();
+                                       chanMgr->broadcastTrackerUpdate(noID,true);
+                               }
+                               lastForceIPCheck = ctime;
+                       }
+               }
+
+
+               if (chanMgr->isBroadcasting())
+               {
+                       if ((ctime-lastBroadcastConnect) > 30)
+                       {
+                               servMgr->connectBroadcaster();
+                               lastBroadcastConnect = ctime;
+                       }
+               }
+
+               if (servMgr->isRoot)
+               {
+                       if ((servMgr->lastIncoming) && ((ctime-servMgr->lastIncoming) > 60*60))
+                       {
+                               peercastInst->saveSettings();
+                               sys->exit();
+                       }
+
+                       if ((ctime-lastRootBroadcast) > chanMgr->hostUpdateInterval)
+                       {
+                               servMgr->broadcastRootSettings(true);
+                               lastRootBroadcast = ctime;
+                       }
+               }
+
+
+               // clear dead hits
+               chanMgr->clearDeadHits(true);
+
+               if (servMgr->kickPushStartRelays && servMgr->kickPushInterval) //JP-EX
+               {
+                       servMgr->banFirewalledHost();
+               }
+
+               if (servMgr->shutdownTimer)
+               {
+                       if (--servMgr->shutdownTimer <= 0)
+                       {
+                               peercastInst->saveSettings();
+                               sys->exit();
+                       }
+               }
+
+               // shutdown idle channels
+               if (chanMgr->numIdleChannels() > ChanMgr::MAX_IDLE_CHANNELS)
+                       chanMgr->closeOldestIdle();
+
+
+               sys->sleep(500);
+       }
+
+       sys->endThread(thread);
+//     thread->unlock();
+       return 0;
+}
+
+// --------------------------------------------------
+int ServMgr::serverProc(ThreadInfo *thread)
+{
+
+//     thread->lock();
+
+       Servent *serv = servMgr->allocServent();
+       Servent *serv2 = servMgr->allocServent();
+
+       unsigned int lastLookupTime=0;
+
+
+       while (thread->active)
+       {
+
+               if (servMgr->restartServer)
+               {
+                       serv->abort();          // force close
+                       serv2->abort();         // force close
+                       servMgr->quit();
+
+                       servMgr->restartServer = false;
+               }
+
+               if (servMgr->autoServe)
+               {
+                       serv->allow = servMgr->allowServer1;
+                       serv2->allow = servMgr->allowServer2;
+
+
+                       if ((!serv->sock) || (!serv2->sock))
+                       {
+                               LOG_DEBUG("Starting servers");
+//                             servMgr->forceLookup = true;
+
+                               //if (servMgr->serverHost.ip != 0)
+                               {
+
+                                       if (servMgr->forceNormal)
+                                               servMgr->setFirewall(ServMgr::FW_OFF);
+                                       else
+                                               servMgr->setFirewall(ServMgr::FW_UNKNOWN);
+
+                                       Host h = servMgr->serverHost;
+
+                                       if (!serv->sock)
+                                               serv->initServer(h);
+
+                                       h.port++;
+                                       if (!serv2->sock)
+                                               serv2->initServer(h);
+
+
+                               }
+                       }
+               }else{
+                       // stop server
+                       serv->abort();          // force close
+                       serv2->abort();         // force close
+
+                       // cancel incoming connectuions
+                       Servent *s = servMgr->servents;
+                       while (s)
+                       {
+                               if (s->type == Servent::T_INCOMING)
+                                       s->thread.active = false;
+                               s=s->next;
+                       }
+
+                       servMgr->setFirewall(ServMgr::FW_ON);
+               }
+                       
+               sys->sleepIdle();
+
+       }
+
+       sys->endThread(thread);
+//     thread->unlock();
+       return 0;
+}
+
+// -----------------------------------
+void   ServMgr::setMaxRelays(int max)
+{
+       if (max < MIN_RELAYS)
+               max = MIN_RELAYS;
+       maxRelays = max;
+}
+
+// -----------------------------------
+XML::Node *ServMgr::createServentXML()
+{
+
+       return new XML::Node("servent agent=\"%s\" ",PCX_AGENT);
+}
+
+// --------------------------------------------------
+const char *ServHost::getTypeStr(TYPE t)
+{
+       switch(t)
+       {
+               case T_NONE: return "NONE";
+               case T_STREAM: return "STREAM";
+               case T_CHANNEL: return "CHANNEL";
+               case T_SERVENT: return "SERVENT";
+               case T_TRACKER: return "TRACKER";
+       }
+       return "UNKNOWN";
+}
+// --------------------------------------------------
+ServHost::TYPE ServHost::getTypeFromStr(const char *s)
+{
+       if (stricmp(s,"NONE")==0)
+               return T_NONE;
+       else if (stricmp(s,"SERVENT")==0)
+               return T_SERVENT;
+       else if (stricmp(s,"STREAM")==0)
+               return T_STREAM;
+       else if (stricmp(s,"CHANNEL")==0)
+               return T_CHANNEL;
+       else if (stricmp(s,"TRACKER")==0)
+               return T_TRACKER;
+
+       return T_NONE;
+}
+
+
+// --------------------------------------------------
+bool   ServFilter::writeVariable(Stream &out, const String &var)
+{
+       char buf[1024];
+
+       if (var == "network")
+               strcpy(buf,(flags & F_NETWORK)?"1":"0");
+       else if (var == "private")
+               strcpy(buf,(flags & F_PRIVATE)?"1":"0");
+       else if (var == "direct")
+               strcpy(buf,(flags & F_DIRECT)?"1":"0");
+       else if (var == "banned")
+               strcpy(buf,(flags & F_BAN)?"1":"0");
+       else if (var == "ip")
+               host.IPtoStr(buf);
+       else
+               return false;
+
+
+       out.writeString(buf);
+       return true;
+}
+// --------------------------------------------------
+bool   BCID::writeVariable(Stream &out, const String &var)
+{
+       char buf[1024];
+
+       if (var == "id")
+               id.toStr(buf);
+       else if (var == "name")
+               strcpy(buf,name.cstr());
+       else if (var == "email")
+               strcpy(buf,email.cstr());
+       else if (var == "url")
+               strcpy(buf,url.cstr());
+       else if (var == "valid")
+               strcpy(buf,valid?"Yes":"No");
+       else
+               return false;
+
+
+       out.writeString(buf);
+       return true;
+}
+
+
+// --------------------------------------------------
+bool ServMgr::writeVariable(Stream &out, const String &var)
+{
+       char buf[1024];
+       String str;
+
+       if (var == "version")
+#ifdef VERSION_EX
+               strcpy(buf,PCX_VERSTRING_EX);
+#else
+               strcpy(buf,PCX_VERSTRING);
+#endif
+       else if (var == "uptime")
+       {
+               str.setFromStopwatch(getUptime());
+               str.convertTo(String::T_HTML);
+               strcpy(buf,str.cstr());
+       }else if (var == "numRelays")
+               sprintf(buf,"%d",numStreams(Servent::T_RELAY,true));
+       else if (var == "numDirect")
+               sprintf(buf,"%d",numStreams(Servent::T_DIRECT,true));
+       else if (var == "totalConnected")
+               sprintf(buf,"%d",totalConnected());
+       else if (var == "numServHosts")
+               sprintf(buf,"%d",numHosts(ServHost::T_SERVENT));                
+       else if (var == "numServents")
+               sprintf(buf,"%d",numServents());                
+       else if (var == "serverPort")
+               sprintf(buf,"%d",serverHost.port);              
+       else if (var == "serverIP")
+               serverHost.IPtoStr(buf);
+       else if (var == "ypAddress")
+               strcpy(buf,rootHost.cstr());
+       else if (var == "password")
+               strcpy(buf,password);
+       else if (var == "isFirewalled")
+               sprintf(buf,"%d",getFirewall()==FW_ON?1:0);
+       else if (var == "firewallKnown")
+               sprintf(buf,"%d",getFirewall()==FW_UNKNOWN?0:1);
+       else if (var == "rootMsg")
+               strcpy(buf,rootMsg);
+       else if (var == "isRoot")
+               sprintf(buf,"%d",isRoot?1:0);
+       else if (var == "isPrivate")
+               sprintf(buf,"%d",(PCP_BROADCAST_FLAGS&1)?1:0);
+       else if (var == "forceYP")
+               sprintf(buf,"%d",PCP_FORCE_YP?1:0);
+       else if (var == "refreshHTML")
+               sprintf(buf,"%d",refreshHTML?refreshHTML:0x0fffffff);
+       else if (var == "maxRelays")
+               sprintf(buf,"%d",maxRelays);
+       else if (var == "maxDirect")
+               sprintf(buf,"%d",maxDirect);
+       else if (var == "maxBitrateOut")
+               sprintf(buf,"%d",maxBitrateOut);
+       else if (var == "maxControlsIn")
+               sprintf(buf,"%d",maxControl);
+       else if (var == "numFilters")
+               sprintf(buf,"%d",numFilters+1);
+       else if (var == "maxPGNUIn")
+               sprintf(buf,"%d",maxGnuIncoming);
+       else if (var == "minPGNUIn")
+               sprintf(buf,"%d",minGnuIncoming);
+       else if (var == "numActive1")
+               sprintf(buf,"%d",numActiveOnPort(serverHost.port));
+       else if (var == "numActive2")
+               sprintf(buf,"%d",numActiveOnPort(serverHost.port+1));
+       else if (var == "numPGNU")
+               sprintf(buf,"%d",numConnected(Servent::T_PGNU));
+       else if (var == "numCIN")
+               sprintf(buf,"%d",numConnected(Servent::T_CIN));
+       else if (var == "numCOUT")
+               sprintf(buf,"%d",numConnected(Servent::T_COUT));
+       else if (var == "numIncoming")
+               sprintf(buf,"%d",numActive(Servent::T_INCOMING));
+       else if (var == "numValidBCID")
+       {
+               int cnt = 0;
+               BCID *bcid = validBCID;
+               while (bcid)
+               {
+                       cnt++;
+                       bcid=bcid->next;
+               }
+               sprintf(buf,"%d",cnt);
+       }
+
+       else if (var == "disabled")
+               sprintf(buf,"%d",isDisabled);
+
+       // JP-EX
+       else if (var.startsWith("autoRelayKeep")) {
+               if (var == "autoRelayKeep.0")
+                       strcpy(buf, (autoRelayKeep == 0) ? "1":"0");
+               else if (var == "autoRelayKeep.1")
+                       strcpy(buf, (autoRelayKeep == 1) ? "1":"0");
+               else if (var == "autoRelayKeep.2")
+                       strcpy(buf, (autoRelayKeep == 2) ? "1":"0");
+       } else if (var == "autoMaxRelaySetting")
+               sprintf(buf,"%d",autoMaxRelaySetting);
+       else if (var == "autoBumpSkipCount")
+               sprintf(buf,"%d",autoBumpSkipCount);
+       else if (var == "kickPushStartRelays")
+               sprintf(buf,"%d",kickPushStartRelays);
+       else if (var == "kickPushInterval")
+               sprintf(buf,"%d",kickPushInterval);
+       else if (var == "allowConnectPCST")
+               strcpy(buf, (allowConnectPCST == 1) ? "1":"0");
+       else if (var == "enableGetName")
+               strcpy(buf, (enableGetName == 1)? "1":"0");
+
+       // VP-EX
+       else if (var == "ypAddress2")
+               strcpy(buf,rootHost2.cstr());
+       else if (var.startsWith("autoPort0Kick")) {
+               if (var == "autoPort0Kick.0")
+                       strcpy(buf, (autoPort0Kick == 0) ? "1":"0");
+               else if (var == "autoPort0Kick.1")
+                       strcpy(buf, (autoPort0Kick == 1) ? "1":"0");
+       }
+       else if (var.startsWith("allowOnlyVP")) {
+               if (var == "allowOnlyVP.0")
+                       strcpy(buf, (allowOnlyVP == 0) ? "1":"0");
+               else if (var == "allowOnlyVP.1")
+                       strcpy(buf, (allowOnlyVP == 1) ? "1":"0");
+       }
+       else if (var == "kickKeepTime")
+               sprintf(buf, "%d",kickKeepTime);
+
+       else if (var == "serverPort1")
+               sprintf(buf,"%d",serverHost.port);
+       else if (var == "serverLocalIP")
+       {
+               Host lh(ClientSocket::getIP(NULL),0);
+               char ipStr[64];
+               lh.IPtoStr(ipStr);
+               strcpy(buf,ipStr);
+       }else if (var == "upgradeURL")
+               strcpy(buf,servMgr->downloadURL);
+       else if (var == "serverPort2")
+               sprintf(buf,"%d",serverHost.port+1);
+       else if (var.startsWith("allow."))
+       {
+               if (var == "allow.HTML1")
+                       strcpy(buf,(allowServer1&Servent::ALLOW_HTML)?"1":"0");
+               else if (var == "allow.HTML2")
+                       strcpy(buf,(allowServer2&Servent::ALLOW_HTML)?"1":"0");
+               else if (var == "allow.broadcasting1")
+                       strcpy(buf,(allowServer1&Servent::ALLOW_BROADCAST)?"1":"0");
+               else if (var == "allow.broadcasting2")
+                       strcpy(buf,(allowServer2&Servent::ALLOW_BROADCAST)?"1":"0");
+               else if (var == "allow.network1")
+                       strcpy(buf,(allowServer1&Servent::ALLOW_NETWORK)?"1":"0");
+               else if (var == "allow.direct1")
+                       strcpy(buf,(allowServer1&Servent::ALLOW_DIRECT)?"1":"0");
+       }else if (var.startsWith("auth."))
+       {
+               if (var == "auth.useCookies")
+                       strcpy(buf,(authType==AUTH_COOKIE)?"1":"0");
+               else if (var == "auth.useHTTP")
+                       strcpy(buf,(authType==AUTH_HTTPBASIC)?"1":"0");
+               else if (var == "auth.useSessionCookies")
+                       strcpy(buf,(cookieList.neverExpire==false)?"1":"0");
+
+       }else if (var.startsWith("log."))
+       {
+               if (var == "log.debug")
+                       strcpy(buf,(showLog&(1<<LogBuffer::T_DEBUG))?"1":"0");
+               else if (var == "log.errors")
+                       strcpy(buf,(showLog&(1<<LogBuffer::T_ERROR))?"1":"0");
+               else if (var == "log.gnet")
+                       strcpy(buf,(showLog&(1<<LogBuffer::T_NETWORK))?"1":"0");
+               else if (var == "log.channel")
+                       strcpy(buf,(showLog&(1<<LogBuffer::T_CHANNEL))?"1":"0");
+               else
+                       return false;
+       }else if (var == "test")
+       {
+               out.writeUTF8(0x304b);          
+               out.writeUTF8(0x304d);          
+               out.writeUTF8(0x304f);          
+               out.writeUTF8(0x3051);          
+               out.writeUTF8(0x3053);  
+
+               out.writeUTF8(0x0041);  
+               out.writeUTF8(0x0042);  
+               out.writeUTF8(0x0043);  
+               out.writeUTF8(0x0044);  
+
+               out.writeChar('a');
+               out.writeChar('b');
+               out.writeChar('c');
+               out.writeChar('d');
+               return true;
+
+       }else if (var == "maxRelaysIndexTxt")           // for PCRaw (relay)
+               sprintf(buf, "%d", maxRelaysIndexTxt);
+       else
+               return false;
+
+       out.writeString(buf);
+       return true;
+}
+// --------------------------------------------------
+//JP-EX
+bool ServMgr::isCheckPushStream()
+{
+       if (servMgr->kickPushStartRelays)
+               if (servMgr->numStreams(Servent::T_RELAY,false)>=(servMgr->kickPushStartRelays-1))
+                               return true;
+
+       return false;
+}
+// --------------------------------------------------
+//JP-EX
+void ServMgr::banFirewalledHost()
+{
+       unsigned int kickpushtime = sys->getTime();
+       if ((kickpushtime-servMgr->kickPushTime) > servMgr->kickPushInterval)
+       {
+               servMgr->kickPushTime = kickpushtime;
+               Servent *s = servMgr->servents;
+               LOG_DEBUG("Servent scan start.");
+               while (s)
+               {
+                       if (s->type != Servent::T_NONE)
+                       {
+                               Host h = s->getHost();
+                               int ip = h.ip;
+                               int port = h.port;
+                               Host h2(ip,port);
+                               unsigned int tnum = 0;
+
+                               if (s->lastConnect)
+                                       tnum = sys->getTime() - s->lastConnect;
+                               if ((s->type==Servent::T_RELAY) && (s->status==Servent::S_CONNECTED) && (tnum>servMgr->kickPushInterval))
+                               {                                               
+/*                                     ChanHitList *hits[ChanMgr::MAX_HITLISTS];
+                                       int numHits=0;
+                                       for(int i=0; i<ChanMgr::MAX_HITLISTS; i++)
+                                       {
+                                               ChanHitList *chl = &chanMgr->hitlists[i];
+                                               if (chl->isUsed())
+                                                       hits[numHits++] = chl;
+                                       }
+
+                                       bool isfw = false;
+                                       int numRelay = 0;
+                                       if (numHits) 
+                                       {
+                                               for(int k=0; k<numHits; k++)
+                                               {
+                                                       ChanHitList *chl = hits[k];
+                                                       if (chl->isUsed())
+                                                       {
+                                                               for (int j=0; j<ChanHitList::MAX_HITS; j++ )
+                                                               {
+                                                                       ChanHit *hit = &chl->hits[j];
+                                                                       if (hit->host.isValid() && (h2.ip == hit->host.ip))
+                                                                       {
+                                                                               if (hit->firewalled)
+                                                                                       isfw = true;
+                                                                               numRelay = hit->numRelays;
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       if ((isfw==true) && (numRelay==0))
+                                       {
+                                               char hostName[256];
+                                               h2.toStr(hostName);
+                                               if (servMgr->isCheckPushStream())
+                                               {
+                                                       s->thread.active = false;
+                                                       LOG_ERROR("Stop firewalled Servent : %s",hostName);
+                                               }
+                                       }*/
+
+                                       chanMgr->hitlistlock.on();
+                                       ChanHitList *chl = chanMgr->findHitListByID(s->chanID);
+                                       if (chl){
+                                               ChanHit *hit = chl->hit;
+                                               while(hit){
+                                                       if ((hit->numHops == 1) && hit->host.isValid() && (h2.ip == hit->host.ip) && hit->firewalled /*&& !hit->numRelays*/)
+                                                       {
+                                                               char hostName[256];
+                                                               h2.toStr(hostName);
+                                                               if (servMgr->isCheckPushStream())
+                                                               {
+                                                                       s->thread.active = false;
+                                                                       LOG_ERROR("Stop firewalled Servent : %s",hostName);
+                                                               }
+                                                       }
+                                                       hit = hit->next;
+                                               }
+
+                                       }
+                                       chanMgr->hitlistlock.off();
+
+
+                               }
+                       }
+                       s=s->next;
+               }
+               LOG_DEBUG("Servent scan finished.");
+       }
+}
+
diff --git a/PeerCast.root/PeerCast/core/common/servmgr.h b/PeerCast.root/PeerCast/core/common/servmgr.h
new file mode 100644 (file)
index 0000000..492520e
--- /dev/null
@@ -0,0 +1,428 @@
+// ------------------------------------------------
+// File : servmgr.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _SERVMGR_H
+#define _SERVMGR_H
+
+#include "servent.h"
+
+// ----------------------------------
+
+const int MIN_YP_RETRY = 20;
+const int MIN_TRACKER_RETRY = 10;
+const int MIN_RELAY_RETRY = 5;
+
+// ----------------------------------
+class BCID
+{
+public:
+       BCID()
+       :next(0),valid(true)
+       {}
+
+       bool    writeVariable(Stream &, const String &);
+
+       GnuID   id;
+       String  name,email,url;
+       bool    valid;
+       BCID    *next;
+};
+
+
+// ----------------------------------
+class ServHost
+{
+public:
+       enum TYPE
+       {
+               T_NONE,
+               T_STREAM,
+               T_CHANNEL,
+               T_SERVENT,
+               T_TRACKER
+       };
+
+       ServHost() {init();}
+       void init()
+       {
+               host.init();
+               time = 0;
+               type = T_NONE;
+       }
+       void init(Host &h, TYPE tp, unsigned int tim)
+       {
+               init();
+               host = h;
+               type = tp;
+               if (tim)
+                       time = tim;
+               else
+                       time = sys->getTime();
+       }
+
+       static const char *getTypeStr(TYPE);
+       static TYPE getTypeFromStr(const char *);
+
+       TYPE type;
+       Host host;
+       unsigned int time;
+};
+// ----------------------------------
+class ServFilter 
+{
+public:
+       enum 
+       {
+               F_PRIVATE  = 0x01,
+               F_BAN      = 0x02,
+               F_NETWORK  = 0x04,
+               F_DIRECT   = 0x08
+       };
+
+       ServFilter() {init();}
+       void    init()
+       {
+               flags = 0;
+               host.init();
+       }
+
+       bool    writeVariable(Stream &, const String &);
+
+       Host host;
+       unsigned int flags;
+};
+
+// ----------------------------------
+// ServMgr keeps track of Servents
+class ServMgr
+{
+
+
+
+public:
+
+       enum NOTIFY_TYPE
+       {
+               NT_UPGRADE                      = 0x0001,
+               NT_PEERCAST                     = 0x0002,
+               NT_BROADCASTERS         = 0x0004,
+               NT_TRACKINFO            = 0x0008
+       };
+
+       enum FW_STATE
+       {
+               FW_OFF,
+               FW_ON,
+               FW_UNKNOWN
+       };
+       enum {
+
+               MAX_HOSTCACHE = 100,            // max. amount of hosts in cache
+               MIN_HOSTS       = 3,                    // min. amount of hosts that should be kept in cache
+
+               MAX_OUTGOING = 3,                       // max. number of outgoing servents to use
+               MAX_INCOMING = 6,                   // max. number of public incoming servents to use
+               MAX_TRYOUT   = 10,                      // max. number of outgoing servents to try connect
+               MIN_CONNECTED = 3,                      // min. amount of connected hosts that should be kept
+
+               MIN_RELAYS = 1,
+
+               MAX_FILTERS = 50,
+
+               MAX_VERSIONS = 16,
+
+               MAX_PREVIEWTIME = 300,          // max. seconds preview per channel available (direct connections)
+               MAX_PREVIEWWAIT = 300,          // max. seconds wait between previews 
+
+       };
+
+       enum AUTH_TYPE
+       {
+               AUTH_COOKIE,
+               AUTH_HTTPBASIC
+       };
+
+       
+
+       ServMgr();
+
+       bool    start();
+
+       Servent *findServent(unsigned int,unsigned short,GnuID &);
+       Servent *findServent(Servent::TYPE);
+       Servent *findServent(Servent::TYPE,Host &,GnuID &);
+       Servent *findOldestServent(Servent::TYPE,bool);
+       Servent *findServentByIndex(int);
+       Servent *findServentByServentID(int);
+
+       bool    writeVariable(Stream &, const String &);
+       Servent *allocServent();
+       unsigned int            numUsed(int);
+       unsigned int            numStreams(GnuID &, Servent::TYPE,bool);
+       unsigned int            numStreams(Servent::TYPE,bool);
+       unsigned int            numConnected(int,bool,unsigned int);
+       unsigned int            numConnected(int t,int tim = 0)
+       {
+               return numConnected(t,false,tim)+numConnected(t,true,tim);
+       }
+       unsigned int            numConnected();
+       unsigned int            numServents();
+
+       unsigned int            totalConnected()
+       {
+               //return numConnected(Servent::T_OUTGOING) + numConnected(Servent::T_INCOMING);
+               return numConnected();
+       }
+       unsigned int            numOutgoing();
+       bool    isFiltered(int,Host &h);
+       bool    addOutgoing(Host,GnuID &,bool);
+       Servent *findConnection(Servent::TYPE,GnuID &);
+
+
+       static  THREAD_PROC             serverProc(ThreadInfo *);
+       static  THREAD_PROC             clientProc(ThreadInfo *);
+       static  THREAD_PROC             trackerProc(ThreadInfo *);
+       static  THREAD_PROC             idleProc(ThreadInfo *);
+
+       int             broadcast(GnuPacket &,Servent * = NULL);
+       int             route(GnuPacket &, GnuID &, Servent * = NULL);
+
+       XML::Node *createServentXML();
+
+       void            connectBroadcaster();
+       void            procConnectArgs(char *,ChanInfo &);
+
+       void            quit();
+       void            closeConnections(Servent::TYPE);
+
+       void            checkFirewall();
+
+       // host cache
+       void                    addHost(Host &,ServHost::TYPE,unsigned int);
+       int                             getNewestServents(Host *,int, Host &);
+       ServHost                getOutgoingServent(GnuID &);
+       void                    deadHost(Host &,ServHost::TYPE);
+       unsigned int    numHosts(ServHost::TYPE);
+       void                    clearHostCache(ServHost::TYPE);
+       bool                    seenHost(Host &,ServHost::TYPE,unsigned int);
+
+       void    setMaxRelays(int);
+       void    setFirewall(FW_STATE);
+       bool    checkForceIP();
+       FW_STATE        getFirewall() {return firewalled;}
+       void    saveSettings(const char *);
+       void    loadSettings(const char *);
+       void    setPassiveSearch(unsigned int);
+       int             findChannel(ChanInfo &);
+       bool    getChannel(char *,ChanInfo &,bool);
+       void    setFilterDefaults();
+
+       bool    acceptGIV(ClientSocket *);
+       void    addVersion(unsigned int);
+
+       void broadcastRootSettings(bool);
+       int broadcastPushRequest(ChanHit &, Host &, GnuID &, Servent::TYPE);
+       void writeRootAtoms(AtomStream &,bool);
+
+       int     broadcastPacket(ChanPacket &,GnuID &,GnuID &,GnuID &,Servent::TYPE type);
+
+       void    addValidBCID(BCID *);
+       void    removeValidBCID(GnuID &);
+       BCID    *findValidBCID(GnuID &);
+       BCID    *findValidBCID(int);
+
+       unsigned int getUptime()
+       {
+               return sys->getTime()-startTime;
+       }
+
+       bool    seenPacket(GnuPacket &);
+
+
+       bool    needHosts()
+       {
+               return false;
+               //return numHosts(ServHost::T_SERVENT) < maxTryout;
+       }
+
+       unsigned int            numActiveOnPort(int);
+       unsigned int            numActive(Servent::TYPE);
+
+       bool    needConnections() 
+       {
+               return numConnected(Servent::T_PGNU,60) < minGnuIncoming;
+       }
+       bool    tryFull() 
+       {
+               return false;
+               //return maxTryout ? numUsed(Servent::T_OUTGOING) > maxTryout: false;
+       }
+
+       bool    pubInOver() 
+       {
+               return numConnected(Servent::T_PGNU) > maxGnuIncoming;
+//             return maxIncoming ? numConnected(Servent::T_INCOMING,false) > maxIncoming : false;
+       }
+       bool    pubInFull() 
+       {
+               return numConnected(Servent::T_PGNU) >= maxGnuIncoming;
+//             return maxIncoming ? numConnected(Servent::T_INCOMING,false) >= maxIncoming : false;
+       }
+
+       bool    outUsedFull() 
+       {
+               return false;
+//             return maxOutgoing ? numUsed(Servent::T_OUTGOING) >= maxOutgoing: false;
+       }
+       bool    outOver() 
+       {
+               return false;
+//             return maxOutgoing ? numConnected(Servent::T_OUTGOING) > maxOutgoing : false;
+       }
+
+       bool    controlInFull()
+       {
+               return numConnected(Servent::T_CIN)>=maxControl;
+       }
+
+       bool    outFull() 
+       {
+               return false;
+//             return maxOutgoing ? numConnected(Servent::T_OUTGOING) >= maxOutgoing : false;
+       }
+
+       bool    relaysFull() 
+       {
+               return numStreams(Servent::T_RELAY,false) >= maxRelays;
+       }
+       bool    directFull() 
+       {
+               return numStreams(Servent::T_DIRECT,false) >= maxDirect;
+       }
+
+       bool    bitrateFull(unsigned int br) 
+       {
+               return maxBitrateOut ? (BYTES_TO_KBPS(totalOutput(false))+br) > maxBitrateOut  : false;
+       }
+
+       unsigned int            totalOutput(bool);
+       unsigned int            totalInput(bool);
+
+       static ThreadInfo serverThread,idleThread;
+
+
+       Servent *servents;
+       WLock   lock;
+
+       ServHost        hostCache[MAX_HOSTCACHE];
+
+       char    password[64];
+
+       bool    allowGnutella;
+
+       unsigned int            maxBitrateOut,maxControl,maxRelays,maxDirect;
+       unsigned int            minGnuIncoming,maxGnuIncoming;
+       unsigned int            maxServIn;
+
+       bool    isDisabled;
+       bool    isRoot;
+       int             totalStreams;
+
+       Host    serverHost;
+       String  rootHost;
+       String  rootHost2;
+
+       char    downloadURL[128];
+       String  rootMsg;
+       String  forceIP;
+       char    connectHost[128];
+       GnuID   networkID;
+       unsigned int            firewallTimeout;
+       int             showLog;
+       int             shutdownTimer;
+       bool    pauseLog;
+       bool    forceNormal;
+       bool    useFlowControl;
+       unsigned int lastIncoming;
+
+       bool    restartServer;
+       bool    allowDirect;
+       bool    autoConnect,autoServe,forceLookup;
+       int             queryTTL;
+
+       unsigned int            allowServer1,allowServer2;
+       unsigned int            startTime;
+       unsigned int            tryoutDelay;
+       unsigned int            refreshHTML;
+       unsigned int            relayBroadcast;
+
+       unsigned int notifyMask;
+
+       BCID            *validBCID;
+       GnuID           sessionID;
+
+       ServFilter      filters[MAX_FILTERS];
+       int     numFilters;
+
+
+       CookieList      cookieList;
+       AUTH_TYPE       authType;
+
+       char    htmlPath[128];
+       unsigned int    clientVersions[MAX_VERSIONS],clientCounts[MAX_VERSIONS];
+       int     numVersions;
+
+       int serventNum;
+       String chanLog;
+
+       char modulePath[256]; //JP-EX
+       int enableGetName; //JP-EX
+       int allowConnectPCST; //JP-EX
+       int autoRelayKeep; //JP-EX
+       unsigned int autoMaxRelaySetting; //JP-EX
+       unsigned int autoBumpSkipCount;//JP-EX
+       unsigned int kickPushStartRelays; //JP-EX
+       unsigned int kickPushInterval; //JP-EX
+       unsigned int kickPushTime;
+       bool    isCheckPushStream(); //JP-EX
+       void    banFirewalledHost(); //JP-EX
+
+       bool    getModulePath; //JP-EX
+       bool    clearPLS; //JP-EX
+       bool    writeLogFile; //JP-EX
+
+       bool    autoPort0Kick;
+       bool    allowOnlyVP;
+       unsigned int kickKeepTime;
+       bool    vpDebug;
+       bool    saveIniChannel;
+       bool    saveGuiPos;
+       bool    keepDownstreams;
+
+       int maxRelaysIndexTxt;  // for PCRaw (relay)
+
+private:
+       FW_STATE        firewalled;
+};
+
+// ----------------------------------
+extern ServMgr *servMgr;
+
+
+#endif
diff --git a/PeerCast.root/PeerCast/core/common/socket.cpp b/PeerCast.root/PeerCast/core/common/socket.cpp
new file mode 100644 (file)
index 0000000..80ac2dd
--- /dev/null
@@ -0,0 +1,32 @@
+// ------------------------------------------------
+// File : socket.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             ClientSocket is a generic socket interface, Non OS/HW dependant.
+//             
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+#include <stdio.h>
+#include <string.h>
+#include "socket.h"
+#include "sys.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
diff --git a/PeerCast.root/PeerCast/core/common/socket.h b/PeerCast.root/PeerCast/core/common/socket.h
new file mode 100644 (file)
index 0000000..0e47e07
--- /dev/null
@@ -0,0 +1,185 @@
+// ------------------------------------------------
+// File : socket.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _SOCKET_H
+#define _SOCKET_H
+
+
+#include "common.h"
+#include "stream.h"
+
+//#define DISABLE_NAGLE 1
+
+class SocketBuffer {
+
+public:
+       SocketBuffer(const void *p, int l){
+               buf = ::new char[l];
+               len = l;
+               pos = 0;
+               next = NULL;
+               ctime = sys->getTime();
+               memcpy((void*)buf, p, l);
+       }
+
+       ~SocketBuffer(){
+               if (buf){
+                       ::delete [] buf;
+               }
+       }
+       char *buf;
+       int len;
+       int pos;
+       unsigned int ctime;
+       SocketBuffer *next;
+};
+
+class SocketBufferList {
+
+public:
+       SocketBufferList(){
+               top = NULL;
+               last = NULL;
+               skipCount = 0;
+               lastSkipTime = 0;
+       }
+
+       bool isNull(){ return (top == NULL); }
+       void add(const void *p, int l){
+               SocketBuffer *tmp = new SocketBuffer(p,l);
+
+               if (!last){
+                       top = tmp;
+                       last = tmp;
+               } else {
+                       last->next = tmp;
+                       last = tmp;
+               }
+
+//             LOG_DEBUG("tmp = %d, top = %d, last = %d", tmp, top, last);
+       }
+
+       SocketBuffer *getTop(){
+               unsigned int ctime = sys->getTime();
+
+               while(top){
+                       if (top && (top->ctime + 10 >= ctime)){
+                               break;
+                       } else {
+//                             LOG_DEBUG("over 10sec(data skip)");
+                               skipCount++;
+                               lastSkipTime = sys->getTime();
+                               deleteTop();
+                       }
+               }
+               return top;
+       }
+
+       void deleteTop(){
+//             LOG_DEBUG("oldtop = %d", top);
+               SocketBuffer *tmp = top;
+               top = tmp->next;
+               delete tmp;
+               if (!top){
+                       last = NULL;
+               }
+
+//             LOG_DEBUG("newtop = %d",top);
+       }
+
+       void clear(){
+               while(top){
+                       SocketBuffer *tmp = top;
+                       top = tmp->next;
+                       delete tmp;
+               }
+               top = NULL;
+               last = NULL;
+       }
+
+       SocketBuffer *top;
+       SocketBuffer *last;
+       unsigned int skipCount;
+       unsigned int lastSkipTime;
+
+};
+
+// --------------------------------------------------
+class ClientSocket : public Stream
+{
+public:
+
+       ClientSocket()
+       {
+               readTimeout = 30000;
+               writeTimeout = 30000;
+#ifdef WIN32
+               skipCount = 0;
+               lastSkipTime = 0;
+#endif
+       }
+
+       ~ClientSocket(){
+#ifdef WIN32
+               bufList.clear();
+#endif
+       }
+
+    // required interface
+       virtual void    open(Host &) = 0;
+       virtual void    bind(Host &) = 0;
+       virtual void    connect() = 0;
+       virtual bool    active() = 0;
+       virtual ClientSocket    *accept() = 0;
+       virtual Host    getLocalHost() = 0;
+
+       virtual void    setReadTimeout(unsigned int t)
+       {
+               readTimeout = t;
+       }
+       virtual void    setWriteTimeout(unsigned int t)
+       {
+               writeTimeout = t;
+       }
+       virtual void    setBlocking(bool) {}
+
+
+    static unsigned int    getIP(char *);
+       static bool                     getHostname(char *,unsigned int);
+
+    virtual bool eof()
+    {
+        return active()==false;
+    }
+
+    Host    host;
+
+#ifdef WIN32
+       SocketBufferList        bufList;
+       virtual void bufferingWrite(const void *, int) = 0;
+       unsigned int skipCount;
+       unsigned int lastSkipTime;
+#endif
+
+       unsigned int readTimeout,writeTimeout;
+
+};
+
+
+#endif
diff --git a/PeerCast.root/PeerCast/core/common/stats.cpp b/PeerCast.root/PeerCast/core/common/stats.cpp
new file mode 100644 (file)
index 0000000..46e0a44
--- /dev/null
@@ -0,0 +1,102 @@
+// ------------------------------------------------
+// File : stats.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             Statistic logging
+//             
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+#include "stats.h"
+#include "common.h"
+#include "sys.h"
+#include "stream.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+Stats stats;
+// ------------------------------------
+void Stats::clear()
+{
+       for(int i=0; i<Stats::MAX; i++)
+       {
+               current[i] = 0;
+               last[i] = 0;
+               perSec[i] = 0;
+       }
+       lastUpdate = 0;
+}
+// ------------------------------------
+void   Stats::update()
+{
+       unsigned int ctime = sys->getTime();
+
+       unsigned int diff = ctime - lastUpdate;
+       if (diff >= /* 5 */ 1)
+       {
+               
+               for(int i=0; i<Stats::MAX; i++)
+               {
+                       perSec[i] = (current[i]-last[i])/diff;
+                       last[i] = current[i];
+               }
+
+               lastUpdate = ctime;
+       }
+       
+}
+// ------------------------------------
+bool Stats::writeVariable(Stream &out,const String &var)
+{
+       char buf[1024];
+
+       if (var == "totalInPerSec")             
+               sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::BYTESIN)));
+       else if (var == "totalOutPerSec")               
+               sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::BYTESOUT)));
+       else if (var == "totalPerSec")          
+               sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::BYTESIN)+getPerSecond(Stats::BYTESOUT)));
+       else if (var == "wanInPerSec")          
+               sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::BYTESIN)-getPerSecond(Stats::LOCALBYTESIN)));
+       else if (var == "wanOutPerSec")         
+               sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::BYTESOUT)-getPerSecond(Stats::LOCALBYTESOUT)));
+       else if (var == "wanTotalPerSec")               
+               sprintf(buf,"%.1f",BYTES_TO_KBPS((getPerSecond(Stats::BYTESIN)-getPerSecond(Stats::LOCALBYTESIN))+(getPerSecond(Stats::BYTESOUT)-getPerSecond(Stats::LOCALBYTESOUT))));
+       else if (var == "netInPerSec")          
+               sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::PACKETDATAIN)));
+       else if (var == "netOutPerSec")         
+               sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::PACKETDATAOUT)));
+       else if (var == "netTotalPerSec")               
+               sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::PACKETDATAOUT)+getPerSecond(Stats::PACKETDATAIN)));
+       else if (var == "packInPerSec")         
+               sprintf(buf,"%.1f",getPerSecond(Stats::NUMPACKETSIN));
+       else if (var == "packOutPerSec")                
+               sprintf(buf,"%.1f",getPerSecond(Stats::NUMPACKETSOUT));
+       else if (var == "packTotalPerSec")              
+               sprintf(buf,"%.1f",getPerSecond(Stats::NUMPACKETSOUT)+getPerSecond(Stats::NUMPACKETSIN));
+
+       else
+               return false;
+
+       out.writeString(buf);
+
+       return true;
+}
+
+
+
diff --git a/PeerCast.root/PeerCast/core/common/stats.h b/PeerCast.root/PeerCast/core/common/stats.h
new file mode 100644 (file)
index 0000000..9c52717
--- /dev/null
@@ -0,0 +1,87 @@
+// ------------------------------------------------
+// File : stats.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _STATS_H
+#define _STATS_H
+
+// ------------------------------------------------------
+class Stats
+{
+public:
+
+       void    clear();
+       void    update();
+
+       enum STAT
+       {
+               NONE,
+
+               PACKETSSTART,
+               NUMQUERYIN,NUMQUERYOUT,
+               NUMPINGIN,NUMPINGOUT,
+               NUMPONGIN,NUMPONGOUT,
+               NUMPUSHIN,NUMPUSHOUT,
+               NUMHITIN,NUMHITOUT,
+               NUMOTHERIN,NUMOTHEROUT,
+               NUMDROPPED,
+               NUMDUP,
+               NUMACCEPTED,
+               NUMOLD,
+               NUMBAD,
+               NUMHOPS1,NUMHOPS2,NUMHOPS3,NUMHOPS4,NUMHOPS5,NUMHOPS6,NUMHOPS7,NUMHOPS8,NUMHOPS9,NUMHOPS10,
+               NUMPACKETSIN,
+               NUMPACKETSOUT,
+               NUMROUTED,
+               NUMBROADCASTED,
+               NUMDISCARDED,
+               NUMDEAD,
+               PACKETDATAIN,
+               PACKETDATAOUT,
+               PACKETSEND,             
+               
+
+               BYTESIN,
+               BYTESOUT,
+               LOCALBYTESIN,
+               LOCALBYTESOUT,
+
+               MAX
+       };
+
+       bool    writeVariable(class Stream &,const class String &);
+
+       void    clearRange(STAT s, STAT e)
+       {
+               for(int i=s; i<=e; i++)
+                       current[i] = 0;
+       }
+       void    clear(STAT s) {current[s]=0;}
+       void    add(STAT s,int n=1) {current[s]+=n;}
+       unsigned int getPerSecond(STAT s) {return perSec[s];}
+       unsigned int getCurrent(STAT s) {return current[s];}
+
+       unsigned int    current[Stats::MAX],last[Stats::MAX],perSec[Stats::MAX];
+       unsigned int    lastUpdate;
+};
+
+extern Stats stats;
+
+
+#endif
+
diff --git a/PeerCast.root/PeerCast/core/common/stream.cpp b/PeerCast.root/PeerCast/core/common/stream.cpp
new file mode 100644 (file)
index 0000000..b1f64b5
--- /dev/null
@@ -0,0 +1,367 @@
+// ------------------------------------------------
+// File : stream.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+//             Basic stream handling functions. 
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+#include "stream.h"
+#include "common.h"
+#include "sys.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+// --------------------------------------------------
+void MemoryStream::convertFromBase64()
+{       
+       char *out = buf;
+       char *in = buf;
+       
+       int rl=len;
+    while(rl >= 4) 
+       {
+               out += String::base64WordToChars(out,in);
+               in += 4;
+        rl -= 4;
+    }
+    *out = 0;
+       len = out-buf;
+}
+// -------------------------------------
+void FileStream::openReadOnly(const char *fn)
+{
+       file = fopen(fn,"rb");
+
+    if (!file)
+       throw StreamException("Unable to open file");
+}
+// -------------------------------------
+void FileStream::openWriteReplace(const char *fn)
+{
+       file = fopen(fn,"wb");
+
+       if (!file)
+       throw StreamException("Unable to open file");
+}
+// -------------------------------------
+void FileStream::openWriteAppend(const char *fn)
+{
+        file = fopen(fn,"ab");
+
+        if (!file)
+               throw StreamException("Unable to open file");
+}
+
+// -------------------------------------
+void FileStream::close()
+{
+       if (file)
+       {
+               fclose(file);
+               file = NULL;
+       }
+}
+// -------------------------------------
+void FileStream::rewind()
+{
+       if (file)
+               fseek(file,0,SEEK_SET);
+}
+// -------------------------------------
+int FileStream::length()
+{
+       int len = 0;
+       if (file)
+       {
+               int old = ftell(file);
+               fseek(file,0,SEEK_END);
+               len = ftell(file);
+               fseek(file,old,SEEK_SET);
+
+       }
+       return len;
+}
+
+// -------------------------------------
+bool FileStream::eof()
+{
+       if (file)
+               return (feof(file)!=0);
+       else
+               return true;
+}
+// -------------------------------------
+int FileStream::read(void *ptr, int len)
+{
+       if (!file)
+               return 0;
+       if (feof(file))
+       throw StreamException("End of file");
+
+       int r = (int)fread(ptr,1,len,file);
+
+       updateTotals(r, 0);
+    return r;
+}
+
+// -------------------------------------
+void FileStream::write(const void *ptr, int len)
+{
+       if (!file)
+               return;
+    fwrite(ptr,1,len,file);
+       updateTotals(0, len);
+
+}
+// -------------------------------------
+void FileStream::flush()
+{
+       if (!file)
+               return;
+    fflush(file);
+}
+// -------------------------------------
+int FileStream::pos()
+{
+       if (!file)
+               return 0;
+    return ftell(file);
+}
+
+// -------------------------------------
+void FileStream::seekTo(int pos)
+{
+       if (!file)
+               return;
+       fseek(file,pos,SEEK_SET);
+}
+
+// -------------------------------------
+void Stream::writeTo(Stream &out, int len)
+{
+       char tmp[4096];
+       while (len)
+       {
+               int rlen = sizeof(tmp);
+               if (rlen > len)
+                       rlen = len;
+
+               read(tmp,rlen);
+               out.write(tmp,rlen);
+
+               len-=rlen;
+       }
+}
+// -------------------------------------
+int    Stream::writeUTF8(unsigned int code)
+{
+       if (code < 0x80)
+       {
+               writeChar(code);
+               return 1;
+       }else 
+       if (code < 0x0800)
+       {
+               writeChar(code>>6 | 0xC0);
+               writeChar(code & 0x3F | 0x80);
+               return 2;
+       }else if (code < 0x10000)
+       {
+               writeChar(code>>12 | 0xE0);
+               writeChar(code>>6 & 0x3F | 0x80);
+               writeChar(code & 0x3F | 0x80);
+               return 3;
+       }else 
+       {
+               writeChar(code>>18 | 0xF0);
+               writeChar(code>>12 & 0x3F | 0x80);
+               writeChar(code>>6 & 0x3F | 0x80);
+               writeChar(code & 0x3F | 0x80);
+               return 4;
+       }
+               
+}
+
+// -------------------------------------
+void Stream::skip(int len)
+{
+       char tmp[4096];
+       while (len)
+       {
+               int rlen = sizeof(tmp);
+               if (rlen > len)
+                       rlen = len;
+               read(tmp,rlen);
+               len-=rlen;
+       }
+
+}
+
+
+// -------------------------------------
+void Stream::updateTotals(unsigned int in, unsigned int out)
+{
+       totalBytesIn += in;
+       totalBytesOut += out;
+
+       unsigned int tdiff = sys->getTime()-lastUpdate;
+       if (tdiff >= 5)
+       {
+               bytesInPerSec = (totalBytesIn-lastBytesIn)/tdiff;
+               bytesOutPerSec = (totalBytesOut-lastBytesOut)/tdiff;
+               lastBytesIn = totalBytesIn;
+               lastBytesOut = totalBytesOut;
+               lastUpdate = sys->getTime();
+       }
+}
+// -------------------------------------
+int    Stream::readLine(char *in, int max)
+{
+    int i=0;
+       max -= 2;
+
+       while(max--)
+    {                
+       char c;         
+       read(&c,1);
+               if (c == '\n')
+                       break;
+               if (c == '\r')
+                       continue;
+        in[i++] = c;
+    }
+    in[i] = 0;
+       return i;
+}
+// -------------------------------------
+void Stream::write(const char *fmt,va_list ap)
+{
+       char tmp[4096];
+       vsprintf(tmp,fmt,ap);
+    write(tmp,strlen(tmp));
+}
+// -------------------------------------
+void Stream::writeStringF(const char *fmt,...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       write(fmt,ap);
+       va_end(ap);     
+}
+// -------------------------------------
+void Stream::writeString(const char *str)
+{
+       write(str,strlen(str));
+}
+// -------------------------------------
+void Stream::writeLineF(const char *fmt,...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+
+       write(fmt,ap);
+
+       if (writeCRLF)
+           write("\r\n",2);
+       else
+               write("\n",1);
+
+       va_end(ap);     
+}
+
+// -------------------------------------
+void Stream::writeLine(const char *str)
+{
+       writeString(str);
+
+       if (writeCRLF)
+           write("\r\n",2);
+       else
+               write("\n",1);
+}
+
+// -------------------------------------
+int    Stream::readWord(char *in, int max)
+{
+       int i=0;
+    while (!eof())
+    {
+        char c = readChar();
+
+        if ((c == ' ') || (c == '\t') || (c == '\r') || (c == '\n'))
+        {
+               if (i)
+               break;          // stop reading
+            else
+                       continue;       // skip whitespace
+        }
+
+       if (i >= (max-1))
+               break;
+
+        in[i++] = c;
+    }
+
+       in[i]=0;
+    return i;
+}
+
+
+// --------------------------------------------------
+int Stream::readBase64(char *p, int max)
+{       
+       char vals[4];
+
+       int cnt=0;
+       while (cnt < (max-4))
+       {
+               read(vals,4);
+               int rl = String::base64WordToChars(p,vals);
+               if (!rl)
+                       break;
+
+               p+=rl;
+               cnt+=rl;
+       }
+       *p = 0;
+       return cnt;
+}
+
+
+// -------------------------------------
+int Stream::readBits(int cnt)
+{
+       int v = 0;
+
+       while (cnt)
+       {
+               if (!bitsPos)
+                       bitsBuffer = readChar();
+
+               cnt--;
+
+               v |= (bitsBuffer&(1<<(7-bitsPos)))?(1<<cnt):0;
+
+               bitsPos = (bitsPos+1)&7;
+       }
+
+       return v;
+}
diff --git a/PeerCast.root/PeerCast/core/common/stream.h b/PeerCast.root/PeerCast/core/common/stream.h
new file mode 100644 (file)
index 0000000..4561861
--- /dev/null
@@ -0,0 +1,541 @@
+// ------------------------------------------------
+// File : stream.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _STREAM_H
+#define _STREAM_H
+
+// -------------------------------------
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include "common.h"
+#include "sys.h"
+#include "id.h"
+
+// -------------------------------------
+class Stream
+{
+public:
+       Stream()
+       :writeCRLF(true)
+       ,totalBytesIn(0)
+       ,totalBytesOut(0)
+       ,lastBytesIn(0)
+       ,lastBytesOut(0)
+       ,bytesInPerSec(0)
+       ,bytesOutPerSec(0)
+       ,lastUpdate(0)
+       ,bitsBuffer(0)
+       ,bitsPos(0)
+       {
+       }
+       virtual ~Stream() {}
+
+       virtual int readUpto(void *,int) {return 0;}
+       virtual int read(void *,int)=0;
+       virtual void write(const void *,int) = 0;
+    virtual bool eof()
+    {
+       throw StreamException("Stream can`t eof");
+               return false;
+    }
+
+       virtual void rewind()
+       {
+       throw StreamException("Stream can`t rewind");
+       }
+
+       virtual void seekTo(int)
+       {
+       throw StreamException("Stream can`t seek");
+       }
+
+       void writeTo(Stream &out, int len);
+       virtual void skip(int i);
+
+       virtual void close()
+       {
+       }
+
+       virtual void    setReadTimeout(unsigned int ) 
+       {
+       }
+       virtual void    setWriteTimeout(unsigned int )
+       {
+       }
+       virtual void    setPollRead(bool)
+       {
+       }
+
+       virtual int             getPosition() {return 0;}
+
+
+       // binary
+    char       readChar()
+    {
+       char v;
+        read(&v,1);
+        return v;
+    }
+    short      readShort()
+    {
+       short v;
+        read(&v,2);
+               CHECK_ENDIAN2(v);
+        return v;
+    }
+    long       readLong()
+    {
+       long v;
+        read(&v,4);
+               CHECK_ENDIAN4(v);
+        return v;
+    }
+       int readInt()
+       {
+               return readLong();
+       }
+       ID4 readID4()
+       {
+               ID4 id;
+               read(id.getData(),4);
+               return id;
+       }
+       int     readInt24()
+       {
+               int v=0;
+        read(&v,3);
+               CHECK_ENDIAN3(v);
+       }
+
+
+
+       long readTag()
+       {
+               long v = readLong();
+               return SWAP4(v);
+       }
+
+       int     readString(char *s, int max)
+       {
+               int cnt=0;
+               while (max)
+               {
+                       char c = readChar();
+                       *s++ = c;
+                       cnt++;
+                       max--;
+                       if (!c)
+                               break;
+               }
+               return cnt;
+       }
+
+       virtual bool    readReady() {return true;}
+       virtual int numPending() {return 0;}
+
+
+       void writeID4(ID4 id)
+       {
+               write(id.getData(),4);
+       }
+
+       void    writeChar(char v)
+       {
+               write(&v,1);
+       }
+       void    writeShort(short v)
+       {
+               CHECK_ENDIAN2(v);
+               write(&v,2);
+       }
+       void    writeLong(long v)
+       {
+               CHECK_ENDIAN4(v);
+               write(&v,4);
+       }
+       void writeInt(int v) {writeLong(v);}
+
+       void    writeTag(long v)
+       {
+               //CHECK_ENDIAN4(v);
+               writeLong(SWAP4(v));
+       }
+
+       void    writeTag(char id[4])
+       {
+               write(id,4);
+       }
+
+       int     writeUTF8(unsigned int);
+
+       // text
+    int        readLine(char *in, int max);
+
+    int                readWord(char *, int);
+       int             readBase64(char *, int);
+
+       void    write(const char *,va_list);
+       void    writeLine(const char *);
+       void    writeLineF(const char *,...);
+       void    writeString(const char *);
+       void    writeStringF(const char *,...);
+
+       bool    writeCRLF;
+
+       int             readBits(int);
+
+       void    updateTotals(unsigned int,unsigned int);
+
+
+       unsigned char bitsBuffer;
+       unsigned int bitsPos;
+
+       unsigned int totalBytesIn,totalBytesOut;
+       unsigned int lastBytesIn,lastBytesOut;
+       unsigned int bytesInPerSec,bytesOutPerSec;
+       unsigned int lastUpdate;
+
+};
+
+
+// -------------------------------------
+class FileStream : public Stream
+{
+public:
+       FileStream() {file=NULL;}
+
+    void       openReadOnly(const char *);
+    void       openWriteReplace(const char *);
+    void       openWriteAppend(const char *);
+       bool    isOpen(){return file!=NULL;}
+       int             length();
+       int             pos();
+
+       virtual void    seekTo(int);
+       virtual int             getPosition() {return pos();}
+       virtual void    flush();
+    virtual int                read(void *,int);
+    virtual void       write(const void *,int);
+    virtual bool       eof();
+    virtual void       rewind();
+    virtual void       close();
+
+       FILE *file;
+};
+// -------------------------------------
+class MemoryStream : public Stream
+{
+public:
+       MemoryStream()
+       :buf(NULL)
+       ,len(0)
+       ,pos(0)
+       ,own(false)
+       {
+       }
+
+       MemoryStream(void *p, int l)
+       :buf((char *)p)
+       ,len(l)
+       ,pos(0)
+       ,own(false)
+       {
+       }
+
+       MemoryStream(int l)
+       :buf(new char[l])
+       ,len(l)
+       ,pos(0)
+       ,own(true)
+       {
+       }
+
+       ~MemoryStream() {free2();}
+
+       void readFromFile(FileStream &file)
+       {
+               len = file.length();
+               buf = new char[len];
+               own = true;
+               pos = 0;
+               file.read(buf,len);
+       }
+
+       void free2()
+       {
+               if (own && buf)
+               {
+                       delete buf;
+                       buf = NULL;
+                       own = false;
+               }
+
+       }
+
+       virtual int read(void *p,int l)
+    {
+               if (pos+l <= len)
+               {
+                       memcpy(p,&buf[pos],l);
+                       pos += l;
+                       return l;
+               }else
+               {
+                       memset(p,0,l);
+                       return 0;
+               }
+    }
+
+       virtual void write(const void *p,int l)
+    {
+               if ((pos+l) > len)
+                       throw StreamException("Stream - premature end of write()");
+               memcpy(&buf[pos],p,l);
+               pos += l;
+    }
+
+    virtual bool eof()
+    {
+        return pos >= len;
+    }
+
+       virtual void rewind()
+       {
+               pos = 0;
+       }
+
+       virtual void seekTo(int p)
+       {
+               pos = p;
+       }
+
+       virtual int getPosition()
+       {
+               return pos;
+       }
+
+       void    convertFromBase64();
+
+
+       char *buf;
+       bool own;
+       int len,pos;
+};
+// --------------------------------------------------
+class IndirectStream : public Stream
+{
+public:
+
+       void init(Stream *s)
+       {
+               stream = s;
+       }
+
+       virtual int read(void *p,int l)
+    {
+               return stream->read(p,l);
+    }
+
+       virtual void write(const void *p,int l)
+    {
+               stream->write(p,l);
+    }
+
+    virtual bool eof()
+    {
+        return stream->eof();
+    }
+
+    virtual void close()
+    {
+        stream->close();
+    }
+
+       Stream *stream;
+};
+
+// -------------------------------------
+
+class SockBufStream : public Stream
+{
+public:
+       SockBufStream(Stream &sockStream, int bufsize=128*1024)
+               : sock(sockStream), mem(bufsize)
+               {
+               }
+
+       ~SockBufStream()
+               {
+                       flush();
+                       mem.free2();
+               }
+
+       virtual int read(void *p,int l)
+               {
+                       return sock.read(p, l);
+               }
+
+       virtual void write(const void *p, int len)
+               {
+                       if ( mem.pos+len > mem.len )
+                               flush();
+
+                       mem.write(p, len);
+               }
+
+       void flush()
+               {
+                       if ( mem.pos > 0 ) {
+                               sock.write(mem.buf, mem.pos);
+                               clearWriteBuffer();
+                       }
+               }
+
+       void clearWriteBuffer()
+               {
+                       mem.rewind();
+               }
+
+private:
+       Stream &sock;
+       MemoryStream mem;
+};
+
+// -------------------------------------
+class WriteBufferStream : public Stream
+{
+public:
+       WriteBufferStream(Stream *out_)
+       :buf(NULL)
+       ,own(false)
+       ,len(0)
+       ,pos(0)
+       ,out(out_)
+       {
+       }
+
+       WriteBufferStream(void *p, int l, Stream *out_)
+       :buf((char *)p)
+       ,own(false)
+       ,len(l)
+       ,pos(0)
+       ,out(out_)
+       {
+       }
+
+       WriteBufferStream(int l, Stream *out_)
+       :buf(new char[l])
+       ,own(true)
+       ,len(l)
+       ,pos(0)
+       ,out(out_)
+       {
+       }
+
+       virtual ~WriteBufferStream()
+       {
+               try {
+                       flush();
+               } catch (StreamException &) {}
+               free();
+       }
+
+       void readFromFile(FileStream &file)
+       {
+               len = file.length();
+               buf = new char[len];
+               own = true;
+               pos = 0;
+               file.read(buf,len);
+       }
+
+       void flush()
+       {
+               if (!out || !buf) return;
+               out->write(buf, pos);
+               pos = 0;
+       }
+
+       void free()
+       {
+               if (own && buf)
+               {
+                       delete buf;
+                       buf = NULL;
+                       own = false;
+               }
+
+       }
+
+       virtual int read(void *p,int l)
+    {
+               return 0;
+    }
+
+       virtual void write(const void *p,int l)
+    {
+               char *cp = (char *) p;
+               while ((pos + l) >= len) {
+                       int n = len - pos;
+                       memcpy(&buf[pos], cp, n);
+                       l -= n;
+                       cp += n;
+                       pos = len;
+                       flush();
+                       if (pos != 0) return;
+               }
+               if (l > 0) {
+                       memcpy(&buf[pos], cp, l);
+                       pos += l;
+               }
+    }
+
+    virtual bool eof()
+    {
+        return true;
+    }
+
+       virtual void rewind()
+       {
+               pos = 0;
+       }
+
+       virtual void seekTo(int p)
+       {
+               pos = p;
+       }
+
+       virtual int getPosition()
+       {
+               return pos;
+       }
+
+       void    convertFromBase64();
+
+
+       char *buf;
+       bool own;
+       int len,pos;
+       Stream *out;
+};
+
+#endif
+
diff --git a/PeerCast.root/PeerCast/core/common/sys.cpp b/PeerCast.root/PeerCast/core/common/sys.cpp
new file mode 100644 (file)
index 0000000..1e0704b
--- /dev/null
@@ -0,0 +1,1041 @@
+// ------------------------------------------------
+// File : sys.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             Sys is a base class for all things systemy, like starting threads, creating sockets etc..
+//             Lock is a very basic cross platform CriticalSection class               
+//             SJIS-UTF8 conversion by ????
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "common.h"
+#include "sys.h"
+#include "socket.h"
+#include "gnutella.h"
+#include "servmgr.h" //JP-EX
+#ifdef WIN32
+#include "utf8.h" //JP-Patch
+#endif
+#include <stdlib.h>
+#include <time.h>
+#include "jis.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// -----------------------------------
+#define isSJIS(a,b) ((a >= 0x81 && a <= 0x9f || a >= 0xe0 && a<=0xfc) && (b >= 0x40 && b <= 0x7e || b >= 0x80 && b<=0xfc))
+#define isEUC(a) (a >= 0xa1 && a <= 0xfe)
+#define isASCII(a) (a <= 0x7f) 
+#define isPLAINASCII(a) (((a >= '0') && (a <= '9')) || ((a >= 'a') && (a <= 'z')) || ((a >= 'A') && (a <= 'Z')))
+#define isUTF8(a,b) ((a & 0xc0) == 0xc0 && (b & 0x80) == 0x80 )
+#define isESCAPE(a,b) ((a == '&') && (b == '#'))
+#define isHTMLSPECIAL(a) ((a == '&') || (a == '\"') || (a == '\'') || (a == '<') || (a == '>'))
+
+
+
+// -----------------------------------
+const char *LogBuffer::logTypes[]=
+{
+       "",
+       "DBUG",
+       "EROR",
+       "GNET",
+       "CHAN",
+};
+
+// -----------------------------------
+// base64 encode/decode taken from ices2 source.. 
+static char base64table[64] = {
+    'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
+    'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
+    'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
+    'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
+};
+#if 0
+// -----------------------------------
+static char *util_base64_encode(char *data)
+{
+    int len = strlen(data);
+    char *out = malloc(len*4/3 + 4);
+    char *result = out;
+    int chunk;
+
+    while(len > 0) {
+        chunk = (len >3)?3:len;
+        *out++ = base64table[(*data & 0xFC)>>2];
+        *out++ = base64table[((*data & 0x03)<<4) | ((*(data+1) & 0xF0) >> 4)];
+        switch(chunk) {
+            case 3:
+                *out++ = base64table[((*(data+1) & 0x0F)<<2) | ((*(data+2) & 0xC0)>>6)];
+                *out++ = base64table[(*(data+2)) & 0x3F];
+                break;
+            case 2:
+                *out++ = base64table[((*(data+1) & 0x0F)<<2)];
+                *out++ = '=';
+                break;
+            case 1:
+                *out++ = '=';
+                *out++ = '=';
+                break;
+        }
+        data += chunk;
+        len -= chunk;
+    }
+
+    return result;
+}
+#endif
+
+// -----------------------------------
+static int base64chartoval(char input)
+{
+    if(input >= 'A' && input <= 'Z')
+        return input - 'A';
+    else if(input >= 'a' && input <= 'z')
+        return input - 'a' + 26;
+    else if(input >= '0' && input <= '9')
+        return input - '0' + 52;
+    else if(input == '+')
+        return 62;
+    else if(input == '/')
+        return 63;
+    else if(input == '=')
+        return -1;
+    else
+        return -2;
+}
+
+// -----------------------------------
+static char *util_base64_decode(char *input)
+{
+       return NULL;
+}
+
+
+
+
+
+// ------------------------------------------
+Sys::Sys()
+{
+       idleSleepTime = 10;
+       logBuf = new LogBuffer(1000,100);
+       numThreads=0;
+}
+
+// ------------------------------------------
+void Sys::sleepIdle()
+{
+       sleep(idleSleepTime);
+}
+
+// ------------------------------------------
+bool Host::isLocalhost()
+{
+       return loopbackIP() || (ip == ClientSocket::getIP(NULL)); 
+}
+// ------------------------------------------
+void Host::fromStrName(const char *str, int p)
+{
+       if (!strlen(str))
+       {
+               port = 0;
+               ip = 0;
+               return;
+       }
+
+       char name[128];
+       strncpy(name,str,sizeof(name)-1);
+       name[127] = '\0';
+       port = p;
+       char *pp = strstr(name,":");
+       if (pp)
+       {
+               port = atoi(pp+1);
+               pp[0] = 0;
+       }
+
+       ip = ClientSocket::getIP(name);
+}
+// ------------------------------------------
+void Host::fromStrIP(const char *str, int p)
+{
+       unsigned int ipb[4];
+       unsigned int ipp;
+
+
+       if (strstr(str,":"))
+       {
+               if (sscanf(str,"%03d.%03d.%03d.%03d:%d",&ipb[0],&ipb[1],&ipb[2],&ipb[3],&ipp) == 5)
+               {
+                       ip = ((ipb[0]&0xff) << 24) | ((ipb[1]&0xff) << 16) | ((ipb[2]&0xff) << 8) | ((ipb[3]&0xff));
+                       port = ipp;
+               }else
+               {
+                       ip = 0;
+                       port = 0;
+               }
+       }else{
+               port = p;
+               if (sscanf(str,"%03d.%03d.%03d.%03d",&ipb[0],&ipb[1],&ipb[2],&ipb[3]) == 4)
+                       ip = ((ipb[0]&0xff) << 24) | ((ipb[1]&0xff) << 16) | ((ipb[2]&0xff) << 8) | ((ipb[3]&0xff));
+               else
+                       ip = 0;
+       }
+}
+// -----------------------------------
+bool Host::isMemberOf(Host &h)
+{
+       if (h.ip==0)
+               return false;
+
+    if( h.ip0() != 255 && ip0() != h.ip0() )
+        return false;
+    if( h.ip1() != 255 && ip1() != h.ip1() )
+        return false;
+    if( h.ip2() != 255 && ip2() != h.ip2() )
+        return false;
+    if( h.ip3() != 255 && ip3() != h.ip3() )
+        return false;
+
+/* removed for endieness compatibility
+       for(int i=0; i<4; i++)
+               if (h.ipByte[i] != 255)
+                       if (ipByte[i] != h.ipByte[i])
+                               return false;
+*/
+       return true;
+}
+
+// -----------------------------------
+char *trimstr(char *s1)
+{
+       while (*s1)
+       {
+               if ((*s1 == ' ') || (*s1 == '\t'))
+                       s1++;
+               else
+                       break;
+
+       }
+
+       char *s = s1;
+
+       if(strlen(s1) > 0) {
+/*     s1 = s1+strlen(s1);
+
+       while (*--s1)
+               if ((*s1 != ' ') && (*s1 != '\t'))
+                       break;*/
+
+               s1 = s1+strlen(s1);
+
+//     s1[1] = 0;
+
+               while (*--s1)
+                       if ((*s1 != ' ') && (*s1 != '\t'))
+                               break;
+               s1[1] = 0;
+       }
+       return s;
+}
+
+// -----------------------------------
+char *stristr(const char *s1, const char *s2)
+{
+       while (*s1)
+       {
+               if (TOUPPER(*s1) == TOUPPER(*s2))
+               {
+                       const char *c1 = s1;
+                       const char *c2 = s2;
+
+                       while (*c1 && *c2)
+                       {
+                               if (TOUPPER(*c1) != TOUPPER(*c2))
+                                       break;
+                               c1++;
+                               c2++;
+                       }
+                       if (*c2==0)
+                               return (char *)s1;
+               }
+
+               s1++;
+       }
+       return NULL;
+}
+// -----------------------------------
+bool String::isValidURL()
+{
+       return (strnicmp(data,"http://",7)==0) || (strnicmp(data,"mailto:",7)==0);
+}
+
+// -----------------------------------
+void String::setFromTime(unsigned int t)
+{
+//     char *p = ctime((time_t*)&t);
+       time_t tmp = t;
+       char *p = ctime(&tmp);
+       if (p)
+               strcpy(data,p);
+       else
+               strcpy(data,"-");
+       type = T_ASCII;
+}
+// -----------------------------------
+void String::setFromStopwatch(unsigned int t)
+{
+       unsigned int sec,min,hour,day;
+
+       sec = t%60;
+       min = (t/60)%60;
+       hour = (t/3600)%24;
+       day = (t/86400);
+
+       if (day)
+               sprintf(data,"%d day, %d hour",day,hour);
+       else if (hour)
+               sprintf(data,"%d hour, %d min",hour,min);
+       else if (min)
+               sprintf(data,"%d min, %d sec",min,sec);
+       else if (sec)
+               sprintf(data,"%d sec",sec);
+       else
+               sprintf(data,"-");
+
+       type = T_ASCII;
+}
+// -----------------------------------
+void String::setFromString(const char *str, TYPE t)
+{
+       int cnt=0;
+       bool quote=false;
+       while (*str)
+       {
+               bool add=true;
+               if (*str == '\"')
+               {
+                       if (quote) 
+                               break;
+                       else 
+                               quote = true;
+                       add = false;
+               }else if (*str == ' ')
+               {
+                       if (!quote)
+                       {
+                               if (cnt)
+                                       break;
+                               else
+                                       add = false;
+                       }
+               }
+
+               if (add)
+               {
+                       data[cnt++] = *str++;
+                       if (cnt >= (MAX_LEN-1))
+                               break;
+               }else
+                       str++;
+       }
+       data[cnt] = 0;
+       type = t;
+}
+
+// -----------------------------------
+int String::base64WordToChars(char *out,const char *input)
+{
+       char *start = out;
+       signed char vals[4];
+
+    vals[0] = base64chartoval(*input++);
+    vals[1] = base64chartoval(*input++);
+    vals[2] = base64chartoval(*input++);
+    vals[3] = base64chartoval(*input++);
+
+    if(vals[0] < 0 || vals[1] < 0 || vals[2] < -1 || vals[3] < -1) 
+               return 0;
+
+    *out++ = vals[0]<<2 | vals[1]>>4;
+    if(vals[2] >= 0)
+        *out++ = ((vals[1]&0x0F)<<4) | (vals[2]>>2);
+    else
+        *out++ = 0;
+
+    if(vals[3] >= 0)
+        *out++ = ((vals[2]&0x03)<<6) | (vals[3]);
+    else
+        *out++ = 0;
+
+       return out-start;
+}
+
+// -----------------------------------
+void String::BASE642ASCII(const char *input)
+{
+       char *out = data;
+    int len = strlen(input);
+
+    while(len >= 4) 
+       {
+               out += base64WordToChars(out,input);
+               input += 4;
+        len -= 4;
+    }
+    *out = 0;
+}
+
+
+
+// -----------------------------------
+void String::UNKNOWN2UNICODE(const char *in,bool safe)
+{
+       MemoryStream utf8(data,MAX_LEN-1);
+
+       unsigned char c;
+       unsigned char d;
+
+       while (c = *in++)
+       {
+               d = *in;
+
+               if (isUTF8(c,d))                // utf8 encoded 
+               {
+                       int numChars=0;
+                       int i;
+
+                       for(i=0; i<6; i++)
+                       {
+                               if (c & (0x80>>i))
+                                       numChars++;
+                               else
+                                       break;
+                       }
+
+                       utf8.writeChar(c);
+                       for(i=0; i<numChars-1; i++)
+                               utf8.writeChar(*in++);
+
+               }
+               else if(isSJIS(c,d))                    // shift_jis
+               {
+                       utf8.writeUTF8(JISConverter::sjisToUnicode((c<<8 | d)));
+                       in++;
+
+               }
+               else if(isEUC(c) && isEUC(d))           // euc-jp
+               {
+                       utf8.writeUTF8(JISConverter::eucToUnicode((c<<8 | d)));
+                       in++;
+
+               }
+               else if (isESCAPE(c,d))         // html escape tags &#xx;
+               {
+                       in++;
+                       char code[16];
+                       char *cp = code;
+                       while (c=*in++) 
+                       {
+                               if (c!=';')
+                                       *cp++ = c;
+                               else
+                                       break;
+                       }
+                       *cp = 0;
+
+                       utf8.writeUTF8(strtoul(code,NULL,10));
+
+               }
+               else if (isPLAINASCII(c))       // plain ascii : a-z 0-9 etc..
+               {
+                       utf8.writeUTF8(c);
+
+               }
+               else if (isHTMLSPECIAL(c) && safe)                      
+               {
+                       const char *str = NULL;
+                       if (c == '&') str = "&amp;";
+                       else if (c == '\"') str = "&quot;";
+                       else if (c == '\'') str = "&#039;";
+                       else if (c == '<') str = "&lt;";
+                       else if (c == '>') str = "&gt;";
+                       else str = "?";
+
+                       utf8.writeString(str);
+               }
+               else
+               {
+                       utf8.writeUTF8(c);
+               }
+
+               if (utf8.pos >= (MAX_LEN-10))
+                       break;
+
+
+       }
+
+       utf8.writeChar(0);      // null terminate
+
+}
+
+// -----------------------------------
+void String::ASCII2HTML(const char *in)
+{
+       char *op = data;
+       char *oe = data+MAX_LEN-10;
+       unsigned char c;
+       const char *p = in;
+       while (c = *p++)
+       {
+               
+               if (((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')))
+               {
+                       *op++ = c;
+               }else
+               {
+                       sprintf(op,"&#x%02X;",(int)c);
+                       op+=6;
+               }
+               if (op >= oe)
+                       break;
+       }
+       *op = 0;
+}
+// -----------------------------------
+void String::ASCII2ESC(const char *in, bool safe)
+{
+       char *op = data;
+       char *oe = data+MAX_LEN-10;
+       const char *p = in;
+       unsigned char c;
+       while (c = *p++)
+       {
+               if (((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')))
+                       *op++ = c;
+               else
+               {
+                       *op++ = '%';
+                       if (safe)
+                               *op++ = '%';
+                       *op=0;
+                       sprintf(op,"%02X",(int)c);
+                       op+=2;
+               }
+               if (op >= oe)
+                       break;
+       }
+       *op=0;
+}
+// -----------------------------------
+void String::HTML2ASCII(const char *in)
+{
+       unsigned char c;
+       char *o = data;
+       char *oe = data+MAX_LEN-10;
+       const char *p = in;
+       while (c = *p++)
+       {
+               if ((c == '&') && (p[0] == '#'))
+               {
+                       p++;
+                       char code[8];
+                       char *cp = code;
+                       char ec = *p++;         // hex/dec
+                       while (c=*p++) 
+                       {
+                               if (c!=';')
+                                       *cp++ = c;
+                               else
+                                       break;
+                       }
+                       *cp = 0;
+                       c = (unsigned char)strtoul(code,NULL,ec=='x'?16:10);
+               }
+               *o++ = c;
+               if (o >= oe)
+                       break;
+       }
+
+       *o=0;
+}
+// -----------------------------------
+void String::HTML2UNICODE(const char *in)
+{
+       MemoryStream utf8(data,MAX_LEN-1);
+
+       unsigned char c;
+       while (c = *in++)
+       {
+               if ((c == '&') && (*in == '#'))
+               {
+                       in++;
+                       char code[16];
+                       char *cp = code;
+                       char ec = *in++;                // hex/dec
+                       while (c=*in++) 
+                       {
+                               if (c!=';')
+                                       *cp++ = c;
+                               else
+                                       break;
+                       }
+                       *cp = 0;
+                       utf8.writeUTF8(strtoul(code,NULL,ec=='x'?16:10));
+               }else
+                       utf8.writeUTF8(c);
+
+               if (utf8.pos >= (MAX_LEN-10))
+                       break;
+       }
+
+       utf8.writeUTF8(0);
+}
+
+// -----------------------------------
+void String::ESC2ASCII(const char *in)
+{
+       unsigned char c;
+       char *o = data;
+       char *oe = data+MAX_LEN-10;
+       const char *p = in;
+       while (c = *p++)
+       {
+               if (c == '+')
+                       c = ' ';
+               else if (c == '%')
+               {
+                       if (p[0] == '%')
+                               p++;
+
+                       char hi = TOUPPER(p[0]);
+                       char lo = TOUPPER(p[1]);
+                       c = (TONIBBLE(hi)<<4) | TONIBBLE(lo);
+                       p+=2;
+               }
+               *o++ = c;
+               if (o >= oe)
+                       break;
+       }
+
+       *o=0;
+}
+// -----------------------------------
+void String::ASCII2META(const char *in, bool safe)
+{
+       char *op = data;
+       char *oe = data+MAX_LEN-10;
+       const char *p = in;
+       unsigned char c;
+       while (c = *p++)
+       {
+               switch (c)
+               {
+                       case '%':
+                               if (safe)
+                                       *op++='%';
+                               break;
+                       case ';':
+                               c = ':';
+                               break;
+               }
+
+               *op++=c;
+               if (op >= oe)
+                       break;
+       }
+       *op=0;
+}
+#ifdef WIN32
+// -----------------------------------
+void String::ASCII2SJIS(const char *in) //JP-EX
+{
+       char *op = data;
+       char *p;
+       if (utf8_decode(in,&p)<0)
+       {
+               strcpy(op,in);
+               return;
+       }
+       strcpy(op,p);
+       free(p);
+}
+#endif
+// -----------------------------------
+void String::convertTo(TYPE t)
+{
+       if (t != type)
+       {
+               String tmp = *this;
+
+               // convert to ASCII
+               switch (type)
+               {
+                       case T_UNKNOWN:
+                       case T_ASCII:
+                               break;
+                       case T_HTML:
+                               tmp.HTML2ASCII(data);
+                               break;
+                       case T_ESC:
+                       case T_ESCSAFE:
+                               tmp.ESC2ASCII(data);
+                               break;
+                       case T_META:
+                       case T_METASAFE:
+                               break;
+                       case T_BASE64:
+                               tmp.BASE642ASCII(data);
+                               break;
+               }
+
+               // convert to new format
+               switch (t)
+               {
+                       case T_UNKNOWN:
+                       case T_ASCII:
+                               strcpy(data,tmp.data);
+                               break;
+                       case T_UNICODE:
+                               UNKNOWN2UNICODE(tmp.data,false);
+                               break;
+                       case T_UNICODESAFE:
+                               UNKNOWN2UNICODE(tmp.data,true);
+                               break;
+                       case T_HTML:
+                               ASCII2HTML(tmp.data);
+                               break;
+                       case T_ESC:
+                               ASCII2ESC(tmp.data,false);
+                               break;
+                       case T_ESCSAFE:
+                               ASCII2ESC(tmp.data,true);
+                               break;
+                       case T_META:
+                               ASCII2META(tmp.data,false);
+                               break;
+                       case T_METASAFE:
+                               ASCII2META(tmp.data,true);
+                               break;
+#ifdef WIN32
+                       case T_SJIS: //JP-EX
+                               ASCII2SJIS(tmp.data);
+                               break;
+#endif
+               }
+
+               type = t;
+       }
+}
+// -----------------------------------
+void LogBuffer::write(const char *str, TYPE t)
+{
+       lock.on();
+
+       unsigned int len = strlen(str);
+       int cnt=0;
+       while (len)
+       {
+               unsigned int rlen = len;
+               if (rlen > (lineLen-1))
+                       rlen = lineLen-1;
+
+               int i = currLine % maxLines;
+               int bp = i*lineLen;
+               strncpy(&buf[bp],str,rlen);
+               buf[bp+rlen] = 0;
+               if (cnt==0)
+               {
+                       times[i] = sys->getTime();
+                       types[i] = t;
+               }else
+               {
+                       times[i] = 0;
+                       types[i] = T_NONE;
+               }
+               currLine++;
+
+               str += rlen;
+               len -= rlen;
+               cnt++;
+       }
+
+       lock.off();
+}
+
+// -----------------------------------
+char *getCGIarg(const char *str, const char *arg)
+{
+       if (!str)
+               return NULL;
+
+//     char *s = strstr(str,arg);
+       char *s = (char*)strstr(str,arg);
+
+       if (!s)
+               return NULL;
+
+       s += strlen(arg);
+
+       return s;
+}
+
+// -----------------------------------
+bool cmpCGIarg(char *str, char *arg, char *value)
+{
+       if ((!str) || (!strlen(value)))
+               return false;
+
+       if (strnicmp(str,arg,strlen(arg)) == 0)
+       {
+
+               str += strlen(arg);
+
+               return strncmp(str,value,strlen(value))==0;
+       }else
+               return false;
+}
+// -----------------------------------
+bool hasCGIarg(char *str, char *arg)
+{
+       if (!str)
+               return false;
+
+       char *s = strstr(str,arg);
+
+       if (!s)
+               return false;
+
+       return true;
+}
+
+
+// ---------------------------
+void GnuID::encode(Host *h, const char *salt1, const char *salt2, unsigned char salt3)
+{
+       int s1=0,s2=0;
+       for(int i=0; i<16; i++)
+       {
+               unsigned char ipb = id[i];
+
+               // encode with IP address 
+               if (h)
+                       ipb ^= ((unsigned char *)&h->ip)[i&3];
+
+               // add a bit of salt 
+               if (salt1)
+               {
+                       if (salt1[s1])
+                               ipb ^= salt1[s1++];
+                       else
+                               s1=0;
+               }
+
+               // and some more
+               if (salt2)
+               {
+                       if (salt2[s2])
+                               ipb ^= salt2[s2++];
+                       else
+                               s2=0;
+               }
+
+               // plus some pepper
+               ipb ^= salt3;
+
+               id[i] = ipb;
+       }
+
+}
+// ---------------------------
+void GnuID::toStr(char *str)
+{
+
+       str[0] = 0;
+       for(int i=0; i<16; i++)
+       {
+               char tmp[8];
+               unsigned char ipb = id[i];
+
+               sprintf(tmp,"%02X",ipb);
+               strcat(str,tmp);
+       }
+
+}
+// ---------------------------
+void GnuID::fromStr(const char *str)
+{
+       clear();
+
+       if (strlen(str) < 32)
+               return;
+
+       char buf[8];
+
+       buf[2] = 0;
+
+       for(int i=0; i<16; i++)
+       {
+               buf[0] = str[i*2];
+               buf[1] = str[i*2+1];
+               id[i] = (unsigned char)strtoul(buf,NULL,16);
+       }
+
+}
+
+// ---------------------------
+void GnuID::generate(unsigned char flags)
+{
+       clear();
+
+       for(int i=0; i<16; i++)
+               id[i] = sys->rnd();
+
+       id[0] = flags;
+}
+
+// ---------------------------
+unsigned char GnuID::getFlags()
+{
+       return id[0];
+}
+
+// ---------------------------
+GnuIDList::GnuIDList(int max)
+:ids(new GnuID[max])
+{
+       maxID = max;
+       for(int i=0; i<maxID; i++)
+               ids[i].clear();
+}
+// ---------------------------
+GnuIDList::~GnuIDList()
+{
+       delete [] ids;
+}
+// ---------------------------
+bool GnuIDList::contains(GnuID &id)
+{
+       for(int i=0; i<maxID; i++)
+               if (ids[i].isSame(id))
+                       return true;
+       return false;
+}
+// ---------------------------
+int GnuIDList::numUsed()
+{
+       int cnt=0;
+       for(int i=0; i<maxID; i++)
+               if (ids[i].storeTime)
+                       cnt++;
+       return cnt;
+}
+// ---------------------------
+unsigned int GnuIDList::getOldest()
+{
+       unsigned int t=(unsigned int)-1;
+       for(int i=0; i<maxID; i++)
+               if (ids[i].storeTime)
+                       if (ids[i].storeTime < t)
+                               t = ids[i].storeTime;
+       return t;
+}
+// ---------------------------
+void GnuIDList::add(GnuID &id)
+{
+       unsigned int minTime = (unsigned int) -1;
+       int minIndex = 0;
+
+       // find same or oldest
+       for(int i=0; i<maxID; i++)
+       {
+               if (ids[i].isSame(id))
+               {
+                       ids[i].storeTime = sys->getTime();
+                       return;
+               }
+               if (ids[i].storeTime <= minTime)
+               {
+                       minTime = ids[i].storeTime;
+                       minIndex = i;
+               }
+       }
+
+       ids[minIndex] = id;
+       ids[minIndex].storeTime = sys->getTime();
+}
+// ---------------------------
+void GnuIDList::clear()
+{
+       for(int i=0; i<maxID; i++)
+               ids[i].clear();
+}
+       
+// ---------------------------
+void LogBuffer::dumpHTML(Stream &out)
+{
+       WLockBlock lb(&lock);
+       lb.on();
+
+       unsigned int nl = currLine;
+       unsigned int sp = 0;
+       if (nl > maxLines)
+       {
+               nl = maxLines-1;
+               sp = (currLine+1)%maxLines;
+       }
+
+       String tim,str;
+       if (nl)
+       {
+               for(unsigned int i=0; i<nl; i++)
+               {
+                       unsigned int bp = sp*lineLen;
+
+                       if (types[sp])
+                       {
+                               tim.setFromTime(times[sp]);
+
+                               out.writeString(tim.cstr());
+                               out.writeString(" <b>[");
+                               out.writeString(getTypeStr(types[sp]));
+                               out.writeString("]</b> ");
+                       }
+                       str.set(&buf[bp]);
+                       str.convertTo(String::T_HTML);
+
+                       out.writeString(str.cstr());
+                       out.writeString("<br>");
+
+                       sp++;
+                       sp %= maxLines;
+               }
+       }
+
+       lb.off();
+
+}
+
+// ---------------------------
+void   ThreadInfo::shutdown()
+{
+       active = false;
+       //sys->waitThread(this);
+}
diff --git a/PeerCast.root/PeerCast/core/common/sys.h b/PeerCast.root/PeerCast/core/common/sys.h
new file mode 100644 (file)
index 0000000..5583a9d
--- /dev/null
@@ -0,0 +1,534 @@
+// ------------------------------------------------
+// File : sys.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _SYS_H
+#define _SYS_H
+
+#include <string.h>
+#include "common.h"
+
+#define RAND(a,b) (((a = 36969 * (a & 65535) + (a >> 16)) << 16) + \
+                    (b = 18000 * (b & 65535) + (b >> 16))  )
+extern char *stristr(const char *s1, const char *s2);
+extern char *trimstr(char *s);
+
+
+#define MAX_CGI_LEN 1024
+// ------------------------------------
+class String
+{
+public:
+       enum {
+               MAX_LEN = 256
+       };
+
+       enum TYPE
+       {
+               T_UNKNOWN,
+               T_ASCII,
+               T_HTML,
+               T_ESC,
+               T_ESCSAFE,
+               T_META,
+               T_METASAFE,
+               T_BASE64,
+               T_UNICODE,
+               T_UNICODESAFE,
+#ifdef WIN32
+               T_SJIS, //JP-EX
+#endif
+       };
+
+       String() {clear();}
+       String(const char *p, TYPE t=T_ASCII) 
+       {
+               set(p,t);
+       }
+
+       // set from straight null terminated string
+       void set(const char *p, TYPE t=T_ASCII) 
+       {
+               strncpy(data,p,MAX_LEN-1);
+               data[MAX_LEN-1] = 0;
+               type = t;
+       }
+
+       // set from quoted or unquoted null terminated string
+       void setFromString(const char *str, TYPE t=T_ASCII);
+       
+       // set from stopwatch
+       void setFromStopwatch(unsigned int t);
+
+       // set from time
+       void setFromTime(unsigned int t);
+
+
+       // from single word (end at whitespace)
+       void setFromWord(const char *str)
+       {
+               int i;
+               for(i=0; i<MAX_LEN-1; i++)
+               {
+                       data[i] = *str++;
+                       if ((data[i]==0) || (data[i]==' '))
+                               break;
+               }
+               data[i]=0;
+       }
+
+
+       // set from null terminated string, remove first/last chars
+       void setUnquote(const char *p, TYPE t=T_ASCII) 
+       {
+               int slen = strlen(p);
+               if (slen > 2)
+               {
+                       if (slen >= MAX_LEN) slen = MAX_LEN;
+                       strncpy(data,p+1,slen-2);
+                       data[slen-2]=0;
+               }else
+                       clear();
+               type = t;
+       }
+
+       void clear() 
+       {
+               data[0]=0;
+               type = T_UNKNOWN;
+       }
+       void ASCII2ESC(const char *,bool);
+       void ASCII2HTML(const char *);
+       void ASCII2META(const char *,bool);
+       void ESC2ASCII(const char *);
+       void HTML2ASCII(const char *);
+       void HTML2UNICODE(const char *);
+       void BASE642ASCII(const char *);
+       void UNKNOWN2UNICODE(const char *,bool);
+#ifdef WIN32
+       void ASCII2SJIS(const char *); //JP-EX
+#endif
+
+       static  int     base64WordToChars(char *,const char *);
+
+       static bool isSame(const char *s1, const char *s2) {return strcmp(s1,s2)==0;}
+
+       bool startsWith(const char *s) const {return strncmp(data,s,strlen(s))==0;}
+       bool isValidURL();
+       bool isEmpty() {return data[0]==0;}
+       bool isSame(::String &s) const {return strcmp(data,s.data)==0;}
+       bool isSame(const char *s) const {return strcmp(data,s)==0;}
+       bool contains(::String &s) {return stristr(data,s.data)!=NULL;}
+       bool contains(const char *s) {return stristr(data,s)!=NULL;}
+       void append(const char *s)
+       {
+               if ((strlen(s)+strlen(data) < (MAX_LEN-1)))
+                       strcat(data,s);
+       }
+       void append(char c)
+       {
+               char tmp[2];
+               tmp[0]=c;
+               tmp[1]=0;
+               append(tmp);
+       }
+
+       void prepend(const char *s)
+       {
+               ::String tmp;
+               tmp.set(s);
+               tmp.append(data);
+               tmp.type = type;
+               *this = tmp;
+       }
+
+       bool operator == (const char *s) const {return isSame(s);}
+
+       operator const char *() const {return data;}
+
+       void convertTo(TYPE t);
+
+       char    *cstr() {return data;}
+
+       static bool isWhitespace(char c) {return c==' ' || c=='\t';}
+
+       TYPE    type;
+       char    data[MAX_LEN];
+};
+
+// ------------------------------------
+namespace peercast {
+class Random {
+public:
+       Random(int s=0x14235465)
+       {
+               setSeed(s);
+       }
+       
+       unsigned int next()
+       {
+               return RAND(a[0],a[1]);
+       }
+
+       void setSeed(int s)
+       {
+               a[0] = a[1] = s;
+       }       
+       
+       unsigned long a[2];
+};
+}
+// ------------------------------------
+class Sys
+{
+public:
+       Sys();
+
+
+
+    virtual class ClientSocket *createSocket() = 0;
+       virtual bool                    startThread(class ThreadInfo *) = 0;
+       virtual void                    sleep(int) = 0;
+       virtual void                    appMsg(long,long = 0) = 0;
+       virtual unsigned int    getTime() = 0;          
+       virtual double                  getDTime() = 0;         
+       virtual unsigned int    rnd() = 0;
+       virtual void                    getURL(const char *) = 0;
+       virtual void                    exit() = 0;
+       virtual bool                    hasGUI() = 0;
+       virtual void                    callLocalURL(const char *,int)=0;
+       virtual void                    executeFile(const char *) = 0;
+       virtual void                    endThread(ThreadInfo *) {}
+       virtual void                    waitThread(ThreadInfo *, int timeout = 30000) {}
+
+
+
+#ifdef __BIG_ENDIAN__
+       unsigned short  convertEndian(unsigned short v) { return SWAP2(v); }
+       unsigned int    convertEndian(unsigned int v) { return SWAP4(v); }
+#else
+       unsigned short  convertEndian(unsigned short v) { return v; }
+       unsigned int    convertEndian(unsigned int v) { return v; }
+#endif
+
+
+       void    sleepIdle();
+
+       unsigned int idleSleepTime;
+       unsigned int rndSeed;
+       unsigned int numThreads;
+
+       class LogBuffer *logBuf;
+};
+
+
+#ifdef WIN32
+#include <windows.h>
+
+typedef __int64 int64_t;
+
+
+// ------------------------------------
+class WEvent
+{
+public:
+       WEvent()
+       {
+                event = ::CreateEvent(NULL, // no security attributes
+                                  TRUE, // manual-reset
+                                  FALSE,// initially non-signaled
+                                  NULL);// anonymous
+       }
+
+       ~WEvent()
+       {
+               ::CloseHandle(event);
+       }
+
+       void    signal()
+       {
+               ::SetEvent(event);
+       }
+
+       void    wait(int timeout = 30000)
+       {
+               switch(::WaitForSingleObject(event, timeout))
+               {
+          case WAIT_TIMEOUT:
+              throw TimeoutException();
+              break;
+          //case WAIT_OBJECT_0:
+              //break;
+               }
+       }
+
+       void    reset()
+       {
+               ::ResetEvent(event);
+       }
+
+
+
+       HANDLE event;
+};
+
+
+
+// ------------------------------------
+typedef int (WINAPI *THREAD_FUNC)(ThreadInfo *);
+typedef unsigned int THREAD_HANDLE;
+#define THREAD_PROC int WINAPI
+#define vsnprintf _vsnprintf
+
+// ------------------------------------
+class WLock
+{
+public:
+       WLock()
+       {
+               InitializeCriticalSection(&cs);
+       }
+
+
+       void    on()
+       {
+               EnterCriticalSection(&cs);
+       }
+
+       void    off()
+       {
+               LeaveCriticalSection(&cs);
+       }
+       
+       CRITICAL_SECTION cs;
+};
+#endif
+
+
+#ifdef _UNIX
+// ------------------------------------
+#include <pthread.h>
+#include <errno.h>
+
+#ifdef __APPLE__
+#include <sched.h>
+#define _BIG_ENDIAN 1
+#endif
+
+typedef long long int64_t;
+
+typedef int (*THREAD_FUNC)(ThreadInfo *);
+#define THREAD_PROC int 
+typedef pthread_t THREAD_HANDLE;
+
+// ------------------------------------
+#define stricmp strcasecmp
+#define strnicmp strncasecmp
+
+
+// ------------------------------------
+class WEvent
+{
+public:
+
+       WEvent()
+       {
+       }
+
+       void    signal()
+       {
+       }
+
+       void    wait(int timeout = 30000)
+       {
+       }
+
+       void    reset()
+       {
+       }
+
+};
+
+// ------------------------------------
+class WLock 
+{
+private:
+       pthread_mutex_t mutex;
+public:
+       WLock()
+       {
+           const pthread_mutexattr_t mattr = 
+               {
+#ifdef __APPLE__               
+                       PTHREAD_MUTEX_RECURSIVE
+#else
+                       PTHREAD_MUTEX_RECURSIVE_NP
+#endif
+                };
+                
+        pthread_mutex_init( &mutex, &mattr );
+       }
+
+       ~WLock()
+       {
+        pthread_mutex_destroy( &mutex );
+       }
+
+
+       void    on()
+       {
+               pthread_mutex_lock(&mutex);
+       }
+
+       void    off()
+       {
+               pthread_mutex_unlock(&mutex);
+       }
+       
+};
+#endif
+
+class WLockBlock
+{
+private:
+       WLock *lock;
+       bool flg;
+public:
+       WLockBlock(WLock *l){
+               lock = l;
+               flg = false;
+       }
+       ~WLockBlock(){
+               if (flg){
+                       lock->off();
+                       LOG_DEBUG("LOCK OFF by destructor");
+               }
+       }
+       void on(){
+               flg = true;
+               lock->on();
+       }
+       void off(){
+               flg = false;
+               lock->off();
+       }
+};
+
+// ------------------------------------
+class ThreadInfo
+{
+public:
+       //typedef int  (__stdcall *THREAD_FUNC)(ThreadInfo *);
+
+       ThreadInfo()
+       {
+               active = false;
+               finish = false;
+               id = 0;
+               func = NULL;
+               data = NULL;
+       }
+
+       void    shutdown();
+
+       volatile bool   active;
+       volatile bool   finish;
+       int             id;
+       THREAD_FUNC func;
+       THREAD_HANDLE handle;
+       
+
+       void    *data;
+};
+
+
+// ------------------------------------
+class LogBuffer 
+{
+public:
+       enum TYPE
+       {
+               T_NONE,
+               T_DEBUG,
+               T_ERROR,
+               T_NETWORK,
+               T_CHANNEL,
+       };
+
+       LogBuffer(int i, int l)
+       {
+               lineLen = l;
+               maxLines = i;
+               currLine = 0;
+               buf = new char[lineLen*maxLines];
+               times = new unsigned int [maxLines];
+               types = new TYPE [maxLines];
+       }
+
+       void    clear()
+       {
+               currLine = 0;
+       }
+       void    write(const char *, TYPE);
+       static const char *getTypeStr(TYPE t) {return logTypes[t];}
+       void    dumpHTML(class Stream &);
+
+       char *buf;
+       unsigned int *times;
+       unsigned int currLine,maxLines,lineLen;
+       TYPE    *types;
+       WLock   lock;
+       static  const char *logTypes[];
+
+};
+
+#define RWLOCK_READ_MAX 32
+
+class LockBlock
+{
+public:
+       LockBlock(WLock &l){ flg = false; lock = l; }
+       ~LockBlock(){ if (flg) lock.off(); }
+       void lockon(){ flg = true; lock.on(); }
+       void lockoff(){ flg = false; lock.off(); }
+
+private:
+       WLock lock;
+       bool flg;
+};
+
+// ------------------------------------
+extern Sys *sys;
+
+// ------------------------------------
+
+
+#if _BIG_ENDIAN
+#define CHECK_ENDIAN2(v) v=SWAP2(v)
+#define CHECK_ENDIAN3(v) v=SWAP3(v)
+#define CHECK_ENDIAN4(v) v=SWAP4(v)
+#else
+#define CHECK_ENDIAN2
+#define CHECK_ENDIAN3
+#define CHECK_ENDIAN4
+#endif
+
+
+// ------------------------------------
+#endif
+
diff --git a/PeerCast.root/PeerCast/core/common/url.cpp b/PeerCast.root/PeerCast/core/common/url.cpp
new file mode 100644 (file)
index 0000000..f98d195
--- /dev/null
@@ -0,0 +1,355 @@
+// ------------------------------------------------
+// File : url.h
+// Date: 20-feb-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "url.h"
+#include "socket.h"
+#include "http.h"
+#include "servent.h"
+#include "servmgr.h"
+#include "peercast.h"
+#include "version2.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ------------------------------------------------
+void URLSource::stream(Channel *ch)
+{
+       
+       String url,tmpUrl;
+       while (ch->thread.active && !peercastInst->isQuitting)
+       {
+               tmpUrl = url;
+               if (url.isEmpty())
+                       url = baseurl;
+
+               url = streamURL(ch,url.cstr());
+               if (url == tmpUrl){
+                       sys->sleep(2000);
+               }
+       }
+
+}
+// ------------------------------------------------
+int URLSource::getSourceRate()
+{
+       if (inputStream)
+               return inputStream->bytesInPerSec;
+       else
+               return 0;
+}
+
+// ------------------------------------------------
+::String URLSource::streamURL(Channel *ch, const char *url)
+{
+       String nextURL;
+
+       if (peercastInst->isQuitting || !ch->thread.active)
+               return nextURL;
+
+
+       String urlTmp;
+       urlTmp.set(url);
+
+       char *fileName = urlTmp.cstr();
+
+       PlayList *pls=NULL;
+       ChannelStream *source=NULL;
+
+       LOG_CHANNEL("Fetch URL=%s",fileName);
+
+       try
+       {
+
+               // get the source protocol
+               if (strnicmp(fileName,"http://",7)==0)  
+               {
+                       ch->info.srcProtocol = ChanInfo::SP_HTTP;
+                       fileName += 7;
+               }
+               else if (strnicmp(fileName,"mms://",6)==0)      
+               {
+                       ch->info.srcProtocol = ChanInfo::SP_MMS;
+                       fileName += 6;
+               }
+               else if (strnicmp(fileName,"pcp://",6)==0)      
+               {
+                       ch->info.srcProtocol = ChanInfo::SP_PCP;
+                       fileName += 6;
+               }
+               else if (strnicmp(fileName,"file://",7)==0)     
+               {
+                       ch->info.srcProtocol = ChanInfo::SP_FILE;
+                       fileName += 7;
+               }
+               else 
+               {
+                       ch->info.srcProtocol = ChanInfo::SP_FILE;
+               }
+
+               // default to mp3 for shoutcast servers
+               if (ch->info.contentType == ChanInfo::T_PLS)
+                       ch->info.contentType = ChanInfo::T_MP3;
+
+
+               ch->setStatus(Channel::S_CONNECTING);
+
+               if ((ch->info.srcProtocol == ChanInfo::SP_HTTP) || (ch->info.srcProtocol == ChanInfo::SP_PCP) || (ch->info.srcProtocol == ChanInfo::SP_MMS))
+               {
+
+                       if ((ch->info.contentType == ChanInfo::T_WMA) || (ch->info.contentType == ChanInfo::T_WMV))
+                               ch->info.srcProtocol = ChanInfo::SP_MMS;
+
+                       
+                       LOG_CHANNEL("Channel source is HTTP");
+
+                       ClientSocket *inputSocket = sys->createSocket();
+                       if (!inputSocket)
+                               throw StreamException("Channel cannot create socket");
+
+
+                       inputStream = inputSocket;
+
+
+                       char *dir = strstr(fileName,"/");
+                       if (dir)
+                               *dir++=0;
+
+
+                       LOG_CHANNEL("Fetch Host=%s",fileName);
+                       if (dir)
+                               LOG_CHANNEL("Fetch Dir=%s",dir);
+
+
+                       Host host;
+                       host.fromStrName(fileName,80);
+
+                       inputSocket->open(host);
+                       inputSocket->connect();
+
+                       HTTP http(*inputSocket);
+                       http.writeLineF("GET /%s HTTP/1.0",dir?dir:"");
+
+                       http.writeLineF("%s %s",HTTP_HS_HOST,fileName);
+                       http.writeLineF("%s %s",HTTP_HS_CONNECTION,"close");
+                       http.writeLineF("%s %s",HTTP_HS_ACCEPT,"*/*");
+
+                       if (ch->info.srcProtocol == ChanInfo::SP_MMS)
+                       {
+                               http.writeLineF("%s %s",HTTP_HS_AGENT,"NSPlayer/4.1.0.3856");
+                               http.writeLine("Pragma: no-cache,rate=1.000000,request-context=1");
+                               //http.writeLine("Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=4294967295:4294967295,request-context=22605256,max-duration=0");
+                               http.writeLine("Pragma: xPlayStrm=1");
+                               http.writeLine("Pragma: xClientGUID={c77e7400-738a-11d2-9add-0020af0a3278}");
+                               http.writeLine("Pragma: stream-switch-count=2");
+                               http.writeLine("Pragma: stream-switch-entry=ffff:1:0 ffff:2:0");
+                       }else
+                       {
+                               http.writeLineF("%s %s",HTTP_HS_AGENT,PCX_AGENT);  
+                               http.writeLineF("%s %d",PCX_HS_PCP,1);  
+                               http.writeLine("Icy-MetaData:1");                               // fix by ravon 
+                       }
+
+                       http.writeLine("");
+
+                       int res = http.readResponse();
+
+
+                       String name = ch->info.name;
+
+                       while (http.nextHeader())
+                       {                               
+
+                               LOG_CHANNEL("Fetch HTTP: %s",http.cmdLine);
+
+                               ChanInfo tmpInfo = ch->info;
+                               Servent::readICYHeader(http,ch->info,NULL);
+
+                               if (!tmpInfo.name.isEmpty())
+                                       ch->info.name = tmpInfo.name;
+                               if (!tmpInfo.genre.isEmpty())
+                                       ch->info.genre = tmpInfo.genre;
+                               if (!tmpInfo.url.isEmpty())
+                                       ch->info.url = tmpInfo.url;
+
+                               if (http.isHeader("icy-metaint"))
+                                       ch->icyMetaInterval = http.getArgInt();
+                               else if (http.isHeader("Location:"))
+                                       nextURL.set(http.getArgStr());
+
+                               char *arg = http.getArgStr();
+                               if (arg)
+                               {
+                                       if (http.isHeader("content-type"))
+                                       {
+                                               if (stristr(arg,MIME_XSCPLS))
+                                                       pls = new PlayList(PlayList::T_SCPLS, 1000);
+                                               else if (stristr(arg,MIME_PLS))
+                                                       pls = new PlayList(PlayList::T_PLS, 1000);
+                                               else if (stristr(arg,MIME_XPLS))
+                                                       pls = new PlayList(PlayList::T_PLS, 1000);
+                                               else if (stristr(arg,MIME_M3U))
+                                                       pls = new PlayList(PlayList::T_PLS, 1000);
+                                               else if (stristr(arg,MIME_TEXT))
+                                                       pls = new PlayList(PlayList::T_PLS, 1000);
+                                               else if (stristr(arg,MIME_ASX))
+                                                       pls = new PlayList(PlayList::T_ASX, 1000);
+                                               else if (stristr(arg,MIME_MMS))
+                                                       ch->info.srcProtocol = ChanInfo::SP_MMS;
+                                       }
+                               }
+
+                       }
+
+                       if ((!nextURL.isEmpty()) && (res==302))
+                       {
+                               LOG_CHANNEL("Channel redirect: %s",nextURL.cstr());
+                               inputSocket->close();
+                               delete inputSocket;
+                               inputSocket = NULL;
+                               return nextURL;
+                       }
+
+                       if (res!=200)
+                       {
+                               LOG_ERROR("HTTP response: %d",res);
+                               throw StreamException("Bad HTTP connect");
+                       }
+
+
+               }else if (ch->info.srcProtocol == ChanInfo::SP_FILE)
+               {
+
+                       LOG_CHANNEL("Channel source is FILE");
+
+                       FileStream *fs = new FileStream();
+                       fs->openReadOnly(fileName);
+                       inputStream = fs;
+
+                       ChanInfo::TYPE fileType = ChanInfo::T_UNKNOWN;
+                       // if filetype is unknown, try and figure it out from file extension.
+                       //if ((info.srcType == ChanInfo::T_UNKNOWN) || (info.srcType == ChanInfo::T_PLAYLIST))
+                       {
+                               const char *ext = fileName+strlen(fileName);
+                               while (*--ext)
+                                       if (*ext=='.')
+                                       {
+                                               ext++;
+                                               break;
+                                       }
+
+                               fileType = ChanInfo::getTypeFromStr(ext);
+                       }
+
+
+                       if (ch->info.bitrate)
+                               ch->readDelay = true;
+
+
+                       if (fileType == ChanInfo::T_PLS) 
+                               pls = new PlayList(PlayList::T_PLS, 1000);
+                       else if (fileType == ChanInfo::T_ASX) 
+                               pls = new PlayList(PlayList::T_ASX, 1000);
+                       else
+                               ch->info.contentType = fileType;
+
+               }else
+               {
+                       throw StreamException("Unsupported URL");
+               }
+
+               
+               if (pls)
+               {
+
+                       LOG_CHANNEL("Channel is Playlist");
+
+                       pls->read(*inputStream);
+
+                       inputStream->close();
+                       delete inputStream;
+                       inputStream = NULL;
+
+                       int urlNum=0;
+                       String url;
+
+                       LOG_CHANNEL("Playlist: %d URLs",pls->numURLs);
+                       while ((ch->thread.active) && (pls->numURLs) && (!peercastInst->isQuitting))
+                       {
+                               if (url.isEmpty())
+                               {
+                                       url = pls->urls[urlNum%pls->numURLs];
+                                       urlNum++;
+                               }
+                               try
+                               {
+                                       url = streamURL(ch,url.cstr());
+                               }catch(StreamException &)
+                               {}
+                       }
+
+                       delete pls;
+                       
+               }else
+               {
+
+                       // if we didn`t get a channel id from the source, then create our own (its an original broadcast)
+                       if (!ch->info.id.isSet())
+                       {
+                               ch->info.id = chanMgr->broadcastID;
+                               ch->info.id.encode(NULL,ch->info.name.cstr(),ch->info.genre,ch->info.bitrate);
+                       }
+
+                       if (ch->info.contentType == ChanInfo::T_ASX)
+                               ch->info.contentType = ChanInfo::T_WMV;
+
+                       ch->setStatus(Channel::S_BROADCASTING);
+
+                       inputStream->setReadTimeout(60);        // use longer read timeout
+
+                       source = ch->createSource();
+
+                       ch->readStream(*inputStream,source);
+
+                       inputStream->close();
+               }
+
+       }catch(StreamException &e)
+       {
+               ch->setStatus(Channel::S_ERROR);
+               LOG_ERROR("Channel error: %s",e.msg);
+               sys->sleep(1000);
+       }
+
+
+       ch->setStatus(Channel::S_CLOSING);
+       if (inputStream)
+       {
+               delete inputStream;
+               inputStream = NULL;
+       }
+
+       if (source)
+               delete source;
+
+
+       return nextURL;
+
+}
diff --git a/PeerCast.root/PeerCast/core/common/url.h b/PeerCast.root/PeerCast/core/common/url.h
new file mode 100644 (file)
index 0000000..8d113c0
--- /dev/null
@@ -0,0 +1,49 @@
+// ------------------------------------------------
+// File : url.h
+// Date: 20-feb-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _URL_H
+#define _URL_H
+
+#include "channel.h"
+
+// ------------------------------------------------
+class URLSource : public ChannelSource
+{
+public:
+       URLSource(const char *url) 
+       :inputStream(NULL)
+       {
+               baseurl.set(url);
+       }
+
+       ::String streamURL(Channel *, const char *);    
+
+       virtual void stream(Channel *);
+
+       virtual int getSourceRate();
+
+
+       Stream          *inputStream;
+       ::String        baseurl;
+};
+
+
+
+
+#endif
+
diff --git a/PeerCast.root/PeerCast/core/common/utf8.c b/PeerCast.root/PeerCast/core/common/utf8.c
new file mode 100644 (file)
index 0000000..4747c3f
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2001 Peter Harris <peter.harris@hummingbird.com>
+ * Copyright (C) 2001 Edmund Grimley Evans <edmundo@rano.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * Convert a string between UTF-8 and the locale's charset.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "utf8.h"
+#include "identify_encoding.h"
+#ifdef _WIN32
+
+/* Thanks to Peter Harris <peter.harris@hummingbird.com> for this win32
+ * code.
+ */
+
+#include <stdio.h>
+#include <windows.h>
+
+static unsigned char *make_utf8_string(const wchar_t *unicode)
+{
+       int size = 0, index = 0, out_index = 0;
+       unsigned char *out;
+       unsigned short c;
+
+       /* first calculate the size of the target string */
+       c = unicode[index++];
+       while (c) 
+       {
+               if (c < 0x0080) 
+               {
+                       size += 1;
+               }
+               else if (c < 0x0800)
+               {
+                       size += 2;
+        }else{
+                       size += 3;
+               }
+               c = unicode[index++];
+       }
+
+       out = (unsigned char *)malloc(size + 1);
+       if (out == NULL)
+               return NULL;
+       index = 0;
+
+       c = unicode[index++];
+       while (c)
+    {
+               if (c < 0x080)
+               {
+                       out[out_index++] = (unsigned char)c;
+               }else if (c < 0x800)
+               {
+                       out[out_index++] = 0xc0 | (c >> 6);
+                       out[out_index++] = 0x80 | (c & 0x3f);
+        }else{
+                       out[out_index++] = 0xe0 | (c >> 12);
+                       out[out_index++] = 0x80 | ((c >> 6) & 0x3f);
+                       out[out_index++] = 0x80 | (c & 0x3f);
+               }
+               c = unicode[index++];
+       }
+       out[out_index] = 0x00;
+
+       return out;
+}
+
+static wchar_t *make_unicode_string(const unsigned char *utf8)
+{
+       int size = 0, index = 0, out_index = 0;
+       wchar_t *out;
+       unsigned char c;
+
+       /* first calculate the size of the target string */
+       c = utf8[index++];
+       while (c)
+       {
+               if ((c & 0x80) == 0)
+               {
+                       index += 0;
+               }else if((c & 0xe0) == 0xe0)
+               {
+                       index += 2;
+        }else{
+                       index += 1;
+               }
+               size += 1;
+               c = utf8[index++];
+       }
+
+       out = (wchar_t *)malloc((size + 1) * sizeof(wchar_t));
+       if (out == NULL)
+               return NULL;
+       index = 0;
+
+       c = utf8[index++];
+       while (c)
+       {
+               if ((c & 0x80) == 0)
+               {
+            out[out_index++] = c;
+        }else if ((c & 0xe0) == 0xe0)
+               {
+                       out[out_index] = (c & 0x1F) << 12;
+                       c = utf8[index++];
+                       out[out_index] |= (c & 0x3F) << 6;
+                       c = utf8[index++];
+                       out[out_index++] |= (c & 0x3F);
+        }else{
+                       out[out_index] = (c & 0x3F) << 6;
+                       c = utf8[index++];
+                       out[out_index++] |= (c & 0x3F);
+               }
+               c = utf8[index++];
+       }
+       out[out_index] = 0;
+
+       return out;
+}
+
+int utf8_encode(const char *from, char **to)
+{
+       wchar_t *unicode;
+       int wchars, err;
+
+
+       wchars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from,
+                       strlen(from), NULL, 0);
+
+       if(wchars == 0)
+       {
+//             fprintf(stderr, "Unicode translation error %d\n", GetLastError());
+               return -1;
+       }
+
+       unicode = (wchar_t *)calloc(wchars + 1, sizeof(unsigned short));
+       if(unicode == NULL) 
+       {
+//             fprintf(stderr, "Out of memory processing string to UTF8\n");
+               return -1;
+       }
+
+       err = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, strlen(from), unicode, wchars);
+       if (err != wchars)
+       {
+               free(unicode);
+//             fprintf(stderr, "Unicode translation error %d\n", GetLastError());
+               return -1;
+       }
+
+       /* On NT-based windows systems, we could use WideCharToMultiByte(), but 
+        * MS doesn't actually have a consistent API across win32.
+        */
+       *to = (char *)make_utf8_string(unicode);
+
+       free(unicode);
+       return 0;
+}
+
+int utf8_decode(const char *from, char **to)
+{
+       wchar_t *unicode;
+       int chars, err;
+
+       const char *cds;
+       identify_encoding_t *cdt;
+       enum identify_encoding_order order;
+       order = ieo_SJIS;
+       cdt = identify_encoding_open(order);
+       cds = identify_encoding(cdt,(char *)from);
+       if (strcmp(cds,"UTF-8")!=0)
+       {
+               identify_encoding_close(cdt);
+               return -1;
+       }
+       identify_encoding_close(cdt);
+
+
+       /* On NT-based windows systems, we could use MultiByteToWideChar(CP_UTF8), but 
+        * MS doesn't actually have a consistent API across win32.
+        */
+       unicode = (wchar_t *)make_unicode_string((const unsigned char *)from);
+       if (unicode == NULL) 
+       {
+//             fprintf(stderr, "Out of memory processing string from UTF8 to UNICODE16\n");
+               return -1;
+       }
+
+       chars = WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, unicode, -1, NULL, 0, NULL, NULL);
+
+       if (chars == 0)
+       {
+//             fprintf(stderr, "Unicode translation error %d\n", GetLastError());
+               free(unicode);
+               return -1;
+       }
+
+       *to = (char *)calloc(chars + 1, sizeof(unsigned char));
+       if (*to == NULL) 
+       {
+//             fprintf(stderr, "Out of memory processing string to local charset\n");
+               free(unicode);
+               return -1;
+       }
+
+       err = WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, unicode, -1, *to, chars, NULL, NULL);
+       if (err != chars)
+       {
+//             fprintf(stderr, "Unicode translation error %d\n", GetLastError());
+               free(unicode);
+               free(*to);
+               *to = NULL;
+               return -1;
+       }
+
+       free(unicode);
+       return 0;
+}
+
+#else /* End win32. Rest is for real operating systems */
+
+
+#ifdef HAVE_LANGINFO_CODESET
+#include <langinfo.h>
+#endif
+
+int iconvert(const char *fromcode, const char *tocode,
+                        const char *from, size_t fromlen,
+                        char **to, size_t *tolen);
+
+static char *current_charset = 0; /* means "US-ASCII" */
+
+void convert_set_charset(const char *charset)
+{
+
+       if (!charset)
+               charset = getenv("CHARSET");
+
+#ifdef HAVE_LANGINFO_CODESET
+       if (!charset)
+               charset = nl_langinfo(CODESET);
+#endif
+
+       free(current_charset);
+       current_charset = 0;
+       if (charset && *charset)
+               current_charset = strdup(charset);
+}
+
+static int convert_buffer(const char *fromcode, const char *tocode,
+                                                 const char *from, size_t fromlen,
+                                                 char **to, size_t *tolen)
+{
+       int ret = -1;
+
+#ifdef HAVE_ICONV
+       ret = iconvert(fromcode, tocode, from, fromlen, to, tolen);
+       if (ret != -1)
+               return ret;
+#endif
+
+#ifndef HAVE_ICONV /* should be ifdef USE_CHARSET_CONVERT */
+       ret = charset_convert(fromcode, tocode, from, fromlen, to, tolen);
+       if (ret != -1)
+               return ret;
+#endif
+
+       return ret;
+}
+
+static int convert_string(const char *fromcode, const char *tocode,
+                                                 const char *from, char **to, char replace)
+{
+       int ret;
+       size_t fromlen;
+       char *s;
+
+       fromlen = strlen(from);
+       ret = convert_buffer(fromcode, tocode, from, fromlen, to, 0);
+       if (ret == -2)
+               return -1;
+       if (ret != -1)
+               return ret;
+
+       s = malloc(fromlen + 1);
+       if (!s)
+               return -1;
+       strcpy(s, from);
+       *to = s;
+       for (; *s; s++)
+               if (*s & ~0x7f)
+                       *s = replace;
+       return 3;
+}
+
+int utf8_encode(const char *from, char **to)
+{
+       char *charset;
+
+       if (!current_charset)
+               convert_set_charset(0);
+       charset = current_charset ? current_charset : "US-ASCII";
+       return convert_string(charset, "UTF-8", from, to, '#');
+}
+
+int utf8_decode(const char *from, char **to)
+{
+       char *charset;
+
+       if (*from == 0)
+       {
+               *to = malloc(1);
+               **to = 0;
+               return 1;
+       }
+
+       if (!current_charset)
+               convert_set_charset(0);
+       charset = current_charset ? current_charset : "US-ASCII";
+       return convert_string("UTF-8", charset, from, to, '?');
+}
+
+#endif
diff --git a/PeerCast.root/PeerCast/core/common/utf8.h b/PeerCast.root/PeerCast/core/common/utf8.h
new file mode 100644 (file)
index 0000000..f701319
--- /dev/null
@@ -0,0 +1,36 @@
+
+/*
+ * Convert a string between UTF-8 and the locale's charset.
+ * Invalid bytes are replaced by '#', and characters that are
+ * not available in the target encoding are replaced by '?'.
+ *
+ * If the locale's charset is not set explicitly then it is
+ * obtained using nl_langinfo(CODESET), where available, the
+ * environment variable CHARSET, or assumed to be US-ASCII.
+ *
+ * Return value of conversion functions:
+ *
+ *  -1 : memory allocation failed
+ *   0 : data was converted exactly
+ *   1 : valid data was converted approximately (using '?')
+ *   2 : input was invalid (but still converted, using '#')
+ *   3 : unknown encoding (but still converted, using '?')
+ */
+
+#ifndef __UTF8_H
+#define __UTF8_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void convert_set_charset(const char *charset);
+
+int utf8_encode(const char *from, char **to);
+int utf8_decode(const char *from, char **to);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __UTF8_H */
diff --git a/PeerCast.root/PeerCast/core/common/version2.h b/PeerCast.root/PeerCast/core/common/version2.h
new file mode 100644 (file)
index 0000000..24a45ce
--- /dev/null
@@ -0,0 +1,53 @@
+// ------------------------------------------------
+// File : version2.h
+// Date: 17-june-2005
+// Author: giles
+//
+// (c) 2005 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _VERSION2_H
+#define _VERSION2_H
+
+// ------------------------------------------------
+#ifdef PRIVATE_BROADCASTER
+static const char PCP_BROADCAST_FLAGS  = 0x01; 
+static bool    PCP_FORCE_YP                            = true;
+#else
+static const char PCP_BROADCAST_FLAGS  = 0x00;
+static bool    PCP_FORCE_YP                            = false;
+#endif
+// ------------------------------------------------
+static const int PCP_CLIENT_VERSION            = 1217;
+static const int PCP_CLIENT_VERSION_VP = 23;
+static const int PCP_ROOT_VERSION              = 1212;
+
+static const int PCP_CLIENT_MINVERSION = 1200;
+
+static const char *PCX_AGENT           = "PeerCast/0.1217";    
+static const char *PCX_AGENTJP                 = "PeerCast/0.1217-J";
+static const char *PCX_AGENTVP         = "PeerCast/0.1217(VP0023)";
+static const char *PCX_VERSTRING       = "v0.1217(VP0023)";
+
+#if 1 /* for VP extend version */
+#define VERSION_EX 1
+static const char *PCP_CLIENT_VERSION_EX_PREFIX = "IM"; // 2bytes only
+static const int  PCP_CLIENT_VERSION_EX_NUMBER = 7651;
+static const char *PCX_AGENTEX = "PeerCast/0.1217(IM7651)";
+static const char *PCX_VERSTRING_EX = "v0.1217(IM7651)";
+#endif
+
+// ------------------------------------------------
+
+
+#endif
diff --git a/PeerCast.root/PeerCast/core/common/xml.cpp b/PeerCast.root/PeerCast/core/common/xml.cpp
new file mode 100644 (file)
index 0000000..19c1035
--- /dev/null
@@ -0,0 +1,491 @@
+// ------------------------------------------------
+// File : xml.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             Basic XML parsing/creation 
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "xml.h"
+#include "stream.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ----------------------------------
+void XML::Node::add(Node *n)
+{
+       if (!n)
+               return;
+
+       n->parent = this;
+
+    if (child)
+    {
+       // has children, add to last sibling
+        Node *s = child;
+        while (s->sibling)
+               s = s->sibling;
+        s->sibling = n;
+
+    }else{
+       // no children yet
+        child = n;
+    }
+}
+// ---------------------------------
+inline char nibsToByte(char n1, char n2)
+{
+       if (n1 >= 'A') n1 = n1-'A'+10;
+       else n1 = n1-'0';
+       if (n2 >= 'A') n2 = n2-'A'+10;
+       else n2 = n2-'0';
+
+    return ((n2&0xf)<<4)|(n1&0xf);
+}
+
+// ----------------------------------
+int XML::Node::getBinaryContent(void *ptr, int size)
+{
+       char *in = contData;
+    char *out = (char *)ptr;
+
+    int i=0;
+    while (*in)
+    {
+       if (isWhiteSpace(*in))
+        {
+               in++;
+        }else
+        {
+               if (i >= size)
+               throw StreamException("Too much binary data");
+               out[i++] = nibsToByte(in[0],in[1]);
+               in+=2;
+        }
+    }
+    return i;
+}
+// ----------------------------------
+void XML::Node::setBinaryContent(void *ptr, int size)
+{
+       const char hexTable[] = "0123456789ABCDEF";
+    const int lineWidth = 1023;
+
+       contData = new char[size*2+1+(size/lineWidth)];
+
+    char *bp = (char *)ptr;
+    register char *ap = contData;
+
+    for(register int i=0; i<size; i++)
+    {
+       register char c = bp[i];
+       *ap++ = hexTable[c&0xf];
+       *ap++ = hexTable[(c>>4)&0xf];
+        if ((i&lineWidth)==lineWidth)
+               *ap++ = '\n';
+    }
+    ap[0] = 0;
+}
+
+
+// ----------------------------------
+void XML::Node::setContent(const char *n)
+{
+       contData = strdup(n);
+}
+// ----------------------------------
+void XML::Node::setAttributes(const char *n)
+{
+    char c;
+
+       attrData = strdup(n);
+
+    // count maximum amount of attributes
+    int maxAttr = 1;           // 1 for tag name
+    bool inQ = false;
+    int i=0;
+    while ((c=attrData[i++])!=0)
+    {
+       if (c=='\"')
+                       inQ ^= true;
+
+               if (!inQ)
+                       if (c=='=')
+                               maxAttr++;
+    }
+
+
+    attr = new Attribute[maxAttr];
+
+    attr[0].namePos = 0;
+    attr[0].valuePos = 0;
+
+    numAttr=1;
+
+    i=0;
+
+    // skip until whitespace
+    while (c=attrData[i++])
+       if (isWhiteSpace(c))
+               break;
+
+    if (!c) return;    // no values
+
+    attrData[i-1]=0;
+
+
+    while ((c=attrData[i])!=0)
+    {
+       if (!isWhiteSpace(c))
+        {
+                       if (numAttr>=maxAttr)
+                               throw StreamException("Too many attributes");
+
+                       // get start of tag name
+               attr[numAttr].namePos = i;
+
+
+                       // skip whitespaces until next '='
+                       // terminate name on next whitespace or '='
+            while (attrData[i])
+                       {
+                               c = attrData[i++];
+
+                               if ((c == '=') || isWhiteSpace(c))
+                               {
+                                       attrData[i-1] = 0;      // null term. name
+                                       if (c == '=')
+                               break;
+                               }
+                       }
+
+                       // skip whitespaces
+            while (attrData[i])
+                       {
+                   if (isWhiteSpace(attrData[i]))
+                                       i++;
+                               else
+                                       break;
+                       }
+
+                       // check for valid start of attribute value - '"'
+                       if (attrData[i++] != '\"')
+               throw StreamException("Bad tag value");
+
+            attr[numAttr++].valuePos = i;
+
+                       // terminate attribute value at next '"'
+
+            while (attrData[i])
+                               if (attrData[i++] == '\"')
+                       break;
+
+                       attrData[i-1] = 0;      // null term. value
+
+
+        }else{
+               i++;
+       }
+    }
+}
+// ----------------------------------
+XML::Node::Node(const char *fmt,...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+
+       char tmp[8192];
+       vsprintf(tmp,fmt,ap);
+       setAttributes(tmp);
+
+       va_end(ap);     
+       init();
+}
+
+// ----------------------------------
+void XML::Node::init()
+{
+    parent = sibling = child = NULL;
+    contData = NULL;
+    userPtr = NULL;
+}      
+// ----------------------------------
+int XML::Node::findAttrInt(const char *name)
+{
+       char *v = findAttr(name);
+    if (!v) return 0;
+    return atoi(v);
+}
+// ----------------------------------
+int XML::Node::findAttrID(const char *name)
+{
+       char *v = findAttr(name);
+    if (!v) return 0;
+    return strToID(v);
+}
+// ----------------------------------
+char *XML::Node::findAttr(const char *name)
+{
+       int nlen = strlen(name);
+       for(int i=1; i<numAttr; i++)
+    {
+       char *an = getAttrName(i);
+       if (strnicmp(an,name,nlen)==0)
+               return getAttrValue(i);
+    }
+    return NULL;
+}
+// ----------------------------------
+void XML::Node::write(Stream &out, int level)
+{
+    int i;
+#if 0
+    char tabs[64];
+
+    for(i=0; i<level; i++)
+       tabs[i] = ' ';
+    tabs[i] = '\0';
+
+
+    if (level)
+           out.write(tabs,i);
+#endif
+    char *name = getAttrValue(0);
+
+    out.write("<",1);
+    out.write(name,strlen(name));
+
+    for(i=1; i<numAttr; i++)
+    {
+           out.write(" ",1);
+       char *at = getAttrName(i);
+           out.write(at,strlen(at));
+
+           out.write("=\"",2);
+        char *av = getAttrValue(i);
+           out.write(av,strlen(av));
+           out.write("\"",1);
+    }
+
+       if ((!contData) && (!child))
+       {
+           out.write("/>\n",3);
+       }else
+       {
+           out.write(">\n",2);
+
+           if (contData)
+                   out.write(contData,strlen(contData));
+
+               if (child)
+               child->write(out,level+1);
+#if 0
+           if (level)
+                   out.write(tabs,strlen(tabs));
+#endif
+           out.write("</",2);
+           out.write(name,strlen(name));
+           out.write(">\n",2);
+       }
+
+    if (sibling)
+       sibling->write(out,level);
+}
+// ----------------------------------
+XML::Node::~Node()
+{
+//     LOG("delete %s",getName());
+
+       if (contData)
+       delete [] contData;
+    if (attrData)
+       delete [] attrData;
+    if (attr)
+       delete [] attr;
+
+    Node *n = child;
+    while (n)
+    {
+       Node *nn = n->sibling;
+       delete n;
+       n = nn;
+    }
+}
+
+
+// ----------------------------------
+XML::~XML()
+{
+       if (root)
+       delete root;
+}
+
+// ----------------------------------
+void XML::write(Stream &out)
+{
+       if (!root)
+       throw StreamException("No XML root");
+
+       out.writeLine("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
+    root->write(out,1);
+
+}
+// ----------------------------------
+void XML::writeCompact(Stream &out)
+{
+       if (!root)
+       throw StreamException("No XML root");
+
+       out.writeLine("<?xml ?>");
+    root->write(out,1);
+
+}
+// ----------------------------------
+void XML::writeHTML(Stream &out)
+{
+       if (!root)
+       throw StreamException("No XML root");
+
+    root->write(out,1);
+}
+
+// ----------------------------------
+void XML::setRoot(Node *n)
+{
+       root=n;
+}
+
+
+// ----------------------------------
+XML::Node *XML::findNode(const char *n)
+{
+       if (root)
+       return root->findNode(n);
+       else
+               return NULL;
+}
+
+
+// ----------------------------------
+XML::Node *XML::Node::findNode(const char *name)
+{
+       if (stricmp(getName(),name)==0)
+       return this;
+
+       XML::Node *c = child;
+
+       while (c)
+       {
+               XML::Node *fn = c->findNode(name);
+               if (fn)
+                       return fn;
+               c=c->sibling;
+       }
+
+       return NULL;
+}
+
+// ----------------------------------
+void XML::read(Stream &in)
+{
+       const int BUFFER_LEN = 100*1024;
+       static char buf[BUFFER_LEN];
+
+    Node *currNode=NULL;
+    int tp=0;
+
+    while (!in.eof())
+    {
+       char c = in.readChar();
+
+        if (c == '<')
+        {
+               if (tp && currNode)     // check for content
+            {
+               buf[tp] = 0;
+               currNode->setContent(buf);
+            }
+            tp = 0;
+
+               // read to next '>'
+            while (!in.eof())
+            {
+               c = in.readChar();
+                if (c == '>')
+                       break;
+
+                       if (tp >= BUFFER_LEN)
+                       throw StreamException("Tag too long");
+
+                buf[tp++] = c;
+            }
+            buf[tp]=0;
+
+            if (buf[0] == '!')                                 // comment
+            {
+               // do nothing
+            }else if (buf[0] == '?')                   // doc type
+            {
+               if (strnicmp(&buf[1],"xml ",4))
+                       throw StreamException("Not XML document");
+            }else if (buf[0] == '/')                   // end tag
+            {
+               if (!currNode)
+                       throw StreamException("Unexpected end tag");
+               currNode = currNode->parent;
+            }else      // new tag
+            {
+                   //LOG("tag: %s",buf);
+
+               bool singleTag = false;
+
+                if (buf[tp-1] == '/')                  // check for single tag
+                {
+                       singleTag = true;
+                    buf[tp-1] = 0;
+                }
+
+                               // only add valid tags
+                               if (strlen(buf))
+                               {
+                                       Node *n = new Node(buf);
+
+                                       if (currNode)
+                               currNode->add(n);
+                                       else
+                               setRoot(n);
+
+                                       if (!singleTag)
+                                               currNode = n;
+                               }
+            }
+
+            tp = 0;
+        } else {
+
+               if (tp >= BUFFER_LEN)
+               throw StreamException("Content too big");
+
+               buf[tp++] = c;
+
+        }
+    }
+}
+
diff --git a/PeerCast.root/PeerCast/core/common/xml.h b/PeerCast.root/PeerCast/core/common/xml.h
new file mode 100644 (file)
index 0000000..df157a4
--- /dev/null
@@ -0,0 +1,92 @@
+// ------------------------------------------------
+// File : xml.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _XML_H
+#define _XML_H
+
+//-----------------------
+#include "common.h"
+#include <stdarg.h>
+
+//-----------------------
+class Stream;
+
+//-----------------------
+class XML
+{
+public:
+       class Node
+    {
+    public:
+       class Attribute
+        {
+               public:
+                int namePos,valuePos;
+        };
+
+               Node(const char *,...);
+
+               void    init();
+
+        ~Node();
+        
+           void        add(Node *);
+        void   write(Stream &,int);    // output, level
+        char   *getName() {return getAttrName(0);}
+
+        char   *getAttrValue(int i) {return &attrData[attr[i].valuePos];}
+        char   *getAttrName(int i) {return &attrData[attr[i].namePos];}
+        char   *getContent()  {return contData; }
+        int            getBinaryContent(void *, int);
+
+        void   setAttributes(const char *);
+        void   setContent(const char *);
+        void   setBinaryContent(void *, int);
+
+           Node        *findNode(const char *);
+        char   *findAttr(const char *);
+        int            findAttrInt(const char *);
+        int            findAttrID(const char *);
+
+        char *contData,*attrData;
+
+        Attribute      *attr;
+        int    numAttr;
+
+       Node *child,*parent,*sibling;
+        void *userPtr;
+    };
+
+    XML()
+    {
+       root = NULL;
+    }
+
+    ~XML();
+
+    void       setRoot(Node *n);
+    void       write(Stream &);
+    void       writeCompact(Stream &);
+    void       writeHTML(Stream &);
+    void       read(Stream &);
+    Node       *findNode(const char *n);
+
+    Node *root;
+};
+#endif
diff --git a/PeerCast.root/PeerCast/core/win32/lib/corelib.vcproj b/PeerCast.root/PeerCast/core/win32/lib/corelib.vcproj
new file mode 100644 (file)
index 0000000..6f7743e
--- /dev/null
@@ -0,0 +1,1573 @@
+<?xml version="1.0" encoding="shift_jis"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="corelib"
+       ProjectGUID="{7BCFE65B-8757-45F3-8DFB-1E7D683950D1}"
+       RootNamespace="corelib"
+       SccProjectName="&quot;$/PeerCast.root/PeerCast&quot;, JCAAAAAA"
+       SccLocalPath="..\..\.."
+       SccProvider="MSSCCI:Microsoft Visual SourceSafe"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Private Release|Win32"
+                       OutputDirectory=".\corelib___Win32_Private_Release"
+                       IntermediateDirectory=".\corelib___Win32_Private_Release"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+                       UseOfMFC="0"
+                       ATLMinimizesCRunTimeLibraryUsage="false"
+                       CharacterSet="2"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="2"
+                               InlineFunctionExpansion="1"
+                               AdditionalIncludeDirectories="../../,../../common"
+                               PreprocessorDefinitions="WIN32;NDEBUG;_LIB;PRIVATE_BROADCASTER"
+                               StringPooling="true"
+                               RuntimeLibrary="0"
+                               EnableFunctionLevelLinking="true"
+                               PrecompiledHeaderFile=".\corelib___Win32_Private_Release/corelib.pch"
+                               AssemblerListingLocation=".\corelib___Win32_Private_Release/"
+                               ObjectFile=".\corelib___Win32_Private_Release/"
+                               ProgramDataBaseFileName=".\corelib___Win32_Private_Release/"
+                               WarningLevel="3"
+                               SuppressStartupBanner="true"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="NDEBUG"
+                               Culture="1033"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                               OutputFile=".\corelib___Win32_Private_Release\corelib.lib"
+                               SuppressStartupBanner="true"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                               SuppressStartupBanner="true"
+                               OutputFile=".\corelib___Win32_Private_Release/corelib.bsc"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Debug|Win32"
+                       OutputDirectory=".\Debug"
+                       IntermediateDirectory=".\Debug"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+                       UseOfMFC="0"
+                       ATLMinimizesCRunTimeLibraryUsage="false"
+                       CharacterSet="2"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="0"
+                               AdditionalIncludeDirectories="../../,../../common,../../../ui/win32/simple"
+                               PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
+                               MinimalRebuild="true"
+                               BasicRuntimeChecks="3"
+                               RuntimeLibrary="1"
+                               PrecompiledHeaderFile=".\Debug/corelib.pch"
+                               AssemblerListingLocation=".\Debug/"
+                               ObjectFile=".\Debug/"
+                               ProgramDataBaseFileName=".\Debug/"
+                               WarningLevel="3"
+                               SuppressStartupBanner="true"
+                               DebugInformationFormat="4"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="_DEBUG"
+                               Culture="1033"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                               OutputFile=".\Debug\corelib.lib"
+                               SuppressStartupBanner="true"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                               SuppressStartupBanner="true"
+                               OutputFile=".\Debug/corelib.bsc"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       OutputDirectory=".\Release"
+                       IntermediateDirectory=".\Release"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+                       UseOfMFC="0"
+                       ATLMinimizesCRunTimeLibraryUsage="false"
+                       CharacterSet="2"
+                       WholeProgramOptimization="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="2"
+                               InlineFunctionExpansion="1"
+                               EnableIntrinsicFunctions="true"
+                               AdditionalIncludeDirectories="../../,../../common"
+                               PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+                               StringPooling="true"
+                               RuntimeLibrary="0"
+                               EnableFunctionLevelLinking="true"
+                               PrecompiledHeaderFile=".\Release/corelib.pch"
+                               AssemblerListingLocation=".\Release/"
+                               ObjectFile=".\Release/"
+                               ProgramDataBaseFileName=".\Release/"
+                               WarningLevel="3"
+                               SuppressStartupBanner="true"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="NDEBUG"
+                               Culture="1033"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                               OutputFile=".\Release\corelib.lib"
+                               SuppressStartupBanner="true"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                               SuppressStartupBanner="true"
+                               OutputFile=".\Release/corelib.bsc"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Private Debug|Win32"
+                       OutputDirectory=".\corelib___Win32_Private_Debug"
+                       IntermediateDirectory=".\corelib___Win32_Private_Debug"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+                       UseOfMFC="0"
+                       ATLMinimizesCRunTimeLibraryUsage="false"
+                       CharacterSet="2"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="0"
+                               AdditionalIncludeDirectories="../../,../../common"
+                               PreprocessorDefinitions="WIN32;_DEBUG;_LIB;PRIVATE_BROADCASTER"
+                               MinimalRebuild="true"
+                               BasicRuntimeChecks="3"
+                               RuntimeLibrary="1"
+                               PrecompiledHeaderFile=".\corelib___Win32_Private_Debug/corelib.pch"
+                               AssemblerListingLocation=".\corelib___Win32_Private_Debug/"
+                               ObjectFile=".\corelib___Win32_Private_Debug/"
+                               ProgramDataBaseFileName=".\corelib___Win32_Private_Debug/"
+                               WarningLevel="3"
+                               SuppressStartupBanner="true"
+                               DebugInformationFormat="4"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="_DEBUG"
+                               Culture="1033"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                               OutputFile=".\corelib___Win32_Private_Debug\corelib.lib"
+                               SuppressStartupBanner="true"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                               SuppressStartupBanner="true"
+                               OutputFile=".\corelib___Win32_Private_Debug/corelib.bsc"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="Core Source"
+                       >
+                       <File
+                               RelativePath="..\..\common\channel.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\gnutella.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\html.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\http.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\icy.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\inifile.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\jis.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\mms.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\mp3.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\nsv.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\ogg.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\pcp.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\peercast.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\rtsp.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\servent.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\servhs.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\servmgr.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\socket.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\stats.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\stream.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\sys.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\url.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\xml.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+               </Filter>
+               <Filter
+                       Name="Core Includes"
+                       >
+                       <File
+                               RelativePath="..\..\common\asf.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\atom.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\channel.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\common.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\cstream.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\gnutella.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\html-xml.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\html.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\http.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\icy.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\id.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\inifile.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\jis.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\mms.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\mp3.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\nsv.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\ogg.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\pcp.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\peercast.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\rtsp.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\servent.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\servmgr.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\socket.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\stats.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\stream.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\sys.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\url.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\version2.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\xml.h"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="Win32 Source"
+                       >
+                       <File
+                               RelativePath="..\wsocket.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\wsys.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+               </Filter>
+               <Filter
+                       Name="Win32 Includes"
+                       >
+                       <File
+                               RelativePath="..\wsocket.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\wsys.h"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="Unix Source"
+                       >
+                       <File
+                               RelativePath="..\..\unix\usocket.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\unix\usys.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+               </Filter>
+               <Filter
+                       Name="Unix Includes"
+                       >
+                       <File
+                               RelativePath="..\..\unix\usocket.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\unix\usys.h"
+                               >
+                       </File>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/PeerCast.root/PeerCast/core/win32/lib/corelib.vcproj.vspscc b/PeerCast.root/PeerCast/core/win32/lib/corelib.vcproj.vspscc
new file mode 100644 (file)
index 0000000..16d4a14
--- /dev/null
@@ -0,0 +1,10 @@
+""
+{
+"FILE_VERSION" = "9237"
+"ENLISTMENT_CHOICE" = "NEVER"
+"PROJECT_FILE_RELATIVE_PATH" = "relative:core\\win32\\lib"
+"NUMBER_OF_EXCLUDED_FILES" = "0"
+"ORIGINAL_PROJECT_FILE_PATH" = ""
+"NUMBER_OF_NESTED_PROJECTS" = "0"
+"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
+}
diff --git a/PeerCast.root/PeerCast/core/win32/wsocket.cpp b/PeerCast.root/PeerCast/core/win32/wsocket.cpp
new file mode 100644 (file)
index 0000000..5b03e4c
--- /dev/null
@@ -0,0 +1,675 @@
+// ------------------------------------------------
+// File : wsocket.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             Windows version of ClientSocket. Handles the nitty gritty of actually
+//             reading and writing TCP
+//             
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+// TODO: fix socket closing
+
+
+//#include "stdafx.h"
+//#include "winsock2.h"
+#include <windows.h>
+#include <stdio.h>
+#include "wsocket.h"
+#include "stats.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+// --------------------------------------------------
+void WSAClientSocket::init()
+{
+       WORD wVersionRequested;
+       WSADATA wsaData;
+       int err;
+    
+       wVersionRequested = MAKEWORD( 2, 0 );
+       err = WSAStartup( wVersionRequested, &wsaData );
+       if ( err != 0 )
+               throw SockException("Unable to init sockets");
+
+    //LOG4("WSAStartup:  OK");
+
+}
+// --------------------------------------------------
+bool ClientSocket::getHostname(char *str,unsigned int ip)
+{
+       HOSTENT *he;
+
+       ip = htonl(ip);
+
+       he = gethostbyaddr((char *)&ip,sizeof(ip),AF_INET);
+
+       if (he)
+       {
+               strcpy(str,he->h_name);
+               return true;
+       }else
+               return false;
+}
+
+unsigned int cache_ip = 0;
+unsigned int cache_time = 0;
+
+// --------------------------------------------------
+unsigned int ClientSocket::getIP(char *name)
+{
+       unsigned int ctime = sys->getTime();
+       bool null_flg = (name == NULL);
+
+       if (null_flg){
+               if ((cache_time != 0) && (cache_time + 60 > ctime)){
+                       return cache_ip;
+               } else {
+                       cache_time = 0;
+                       cache_ip = 0;
+               }
+       }
+
+       char szHostName[256];
+
+       if (!name)
+       {
+               if (gethostname(szHostName, sizeof(szHostName))==0)
+                       name = szHostName;
+               else
+                       return 0;
+       }
+
+       HOSTENT *he = WSAClientSocket::resolveHost(name);
+
+       if (!he)
+               return 0;
+
+
+       LPSTR lpAddr = he->h_addr_list[0];
+       if (lpAddr)
+       {
+               unsigned int ret;
+               struct in_addr  inAddr;
+               memmove (&inAddr, lpAddr, 4);
+
+               ret =  inAddr.S_un.S_un_b.s_b1<<24 |
+                          inAddr.S_un.S_un_b.s_b2<<16 |
+                          inAddr.S_un.S_un_b.s_b3<<8 |
+                          inAddr.S_un.S_un_b.s_b4;
+
+               if (null_flg){
+                       cache_ip = ret;
+                       cache_time = ctime;
+               }
+               return ret;
+       }
+       return 0;
+}
+// --------------------------------------------------
+void WSAClientSocket::setLinger(int sec)
+{
+       linger linger;
+       linger.l_onoff = (sec>0)?1:0;
+    linger.l_linger = sec;
+
+       if (setsockopt(sockNum, SOL_SOCKET, SO_LINGER, (const char *)&linger, sizeof (linger)) == -1) 
+               throw SockException("Unable to set LINGER");
+}
+
+// --------------------------------------------------
+void WSAClientSocket::setBlocking(bool yes)
+{
+       unsigned long op = yes ? 0 : 1;
+       if (ioctlsocket(sockNum, FIONBIO, &op) == SOCKET_ERROR)
+               throw SockException("Can`t set blocking");
+}
+// --------------------------------------------------
+void WSAClientSocket::setNagle(bool on)
+{
+    int nodelay = (on==false);
+       if (setsockopt(sockNum, SOL_SOCKET, TCP_NODELAY, (char *)&nodelay, sizeof nodelay) == -1) 
+               throw SockException("Unable to set NODELAY");
+
+}
+
+// --------------------------------------------------
+void WSAClientSocket::setReuse(bool yes)
+{
+       unsigned long op = yes ? 1 : 0;
+       if (setsockopt(sockNum,SOL_SOCKET,SO_REUSEADDR,(char *)&op,sizeof(unsigned long)) == -1) 
+               throw SockException("Unable to set REUSE");
+}
+
+// --------------------------------------------------
+void WSAClientSocket::setBufSize(int size)
+{
+       int oldop;
+       int op = size;
+       int len = sizeof(op);
+       if (getsockopt(sockNum,SOL_SOCKET,SO_RCVBUF,(char *)&oldop,&len) == -1) {
+               LOG_DEBUG("Unable to get RCVBUF");
+       } else if (oldop < size) {
+               if (setsockopt(sockNum,SOL_SOCKET,SO_RCVBUF,(char *)&op,len) == -1) 
+                       LOG_DEBUG("Unable to set RCVBUF");
+               //else
+               //      LOG_DEBUG("*** recvbufsize:%d -> %d", oldop, op);
+       }
+
+       if (getsockopt(sockNum,SOL_SOCKET,SO_SNDBUF,(char *)&oldop,&len) == -1) {
+               LOG_DEBUG("Unable to get SNDBUF");
+       } else if (oldop < size) {
+               if (setsockopt(sockNum,SOL_SOCKET,SO_SNDBUF,(char *)&op,len) == -1) 
+                       LOG_DEBUG("Unable to set SNDBUF");
+               //else
+               //      LOG_DEBUG("*** sendbufsize: %d -> %d", oldop, op);
+       }
+}
+
+// --------------------------------------------------
+HOSTENT *WSAClientSocket::resolveHost(const char *hostName)
+{
+       HOSTENT *he;
+
+       if ((he = gethostbyname(hostName)) == NULL)
+       {
+               // if failed, try using gethostbyaddr instead
+
+               unsigned long ip = inet_addr(hostName);
+               
+               if (ip == INADDR_NONE)
+                       return NULL;
+
+               if ((he = gethostbyaddr((char *)&ip,sizeof(ip),AF_INET)) == NULL)
+                       return NULL;    
+       }
+       return he;
+}
+
+// --------------------------------------------------
+void WSAClientSocket::open(Host &rh)
+{
+       sockNum = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+       if (sockNum == INVALID_SOCKET)
+               throw SockException("Can`t open socket");
+
+       setBlocking(false);
+#ifdef DISABLE_NAGLE
+       setNagle(false);
+#endif
+       setBufSize(65535);
+
+       host = rh;
+
+       memset(&remoteAddr,0,sizeof(remoteAddr));
+
+       remoteAddr.sin_family = AF_INET;
+       remoteAddr.sin_port = htons(host.port);
+       remoteAddr.sin_addr.S_un.S_addr = htonl(host.ip);
+
+}
+// --------------------------------------------------
+void WSAClientSocket::checkTimeout(bool r, bool w)
+{
+    int err = WSAGetLastError();
+    if (err == WSAEWOULDBLOCK)
+    {
+
+               timeval timeout;
+               fd_set read_fds;
+               fd_set write_fds;
+
+               timeout.tv_sec = 0;
+               timeout.tv_usec = 0;
+
+        FD_ZERO (&write_fds);
+               if (w)
+               {
+                       timeout.tv_sec = (int)this->writeTimeout/1000;
+                       FD_SET (sockNum, &write_fds);
+               }
+
+        FD_ZERO (&read_fds);
+               if (r)
+               {
+                       timeout.tv_sec = (int)this->readTimeout/1000;
+               FD_SET (sockNum, &read_fds);
+               }
+
+               timeval *tp;
+               if (timeout.tv_sec)
+                       tp = &timeout;
+               else
+                       tp = NULL;
+
+
+               int r=select (NULL, &read_fds, &write_fds, NULL, tp);
+
+        if (r == 0)
+                       throw TimeoutException();
+               else if (r == SOCKET_ERROR)
+                       throw SockException("select failed.");
+
+       }else{
+               char str[32];
+               sprintf(str,"%d",err);
+               throw SockException(str);
+       }
+}
+
+// --------------------------------------------------
+void WSAClientSocket::checkTimeout2(bool r, bool w)
+{
+    {
+
+               timeval timeout;
+               fd_set read_fds;
+               fd_set write_fds;
+
+               timeout.tv_sec = 0;
+               timeout.tv_usec = 0;
+
+        FD_ZERO (&write_fds);
+               if (w)
+               {
+                       timeout.tv_sec = (int)this->writeTimeout/1000;
+                       FD_SET (sockNum, &write_fds);
+               }
+
+        FD_ZERO (&read_fds);
+               if (r)
+               {
+                       timeout.tv_sec = (int)this->readTimeout/1000;
+               FD_SET (sockNum, &read_fds);
+               }
+
+               timeval *tp;
+               if (timeout.tv_sec)
+                       tp = &timeout;
+               else
+                       tp = NULL;
+
+
+               int r=select (NULL, &read_fds, &write_fds, NULL, tp);
+
+        if (r == 0)
+                       throw TimeoutException();
+               else if (r == SOCKET_ERROR)
+                       throw SockException("select failed.");
+       }
+}
+
+// --------------------------------------------------
+Host WSAClientSocket::getLocalHost()
+{
+       struct sockaddr_in localAddr;
+
+       int len = sizeof(localAddr);
+    if (getsockname(sockNum, (sockaddr *)&localAddr, &len) == 0)
+               return Host(SWAP4(localAddr.sin_addr.s_addr),0);
+       else
+               return Host(0,0);
+}
+
+// --------------------------------------------------
+void WSAClientSocket::connect()
+{
+       if (::connect(sockNum,(struct sockaddr *)&remoteAddr,sizeof(remoteAddr)) == SOCKET_ERROR)
+               checkTimeout(false,true);
+
+}
+// --------------------------------------------------
+int WSAClientSocket::read(void *p, int l)
+{
+       int bytesRead=0;
+
+       while (l)
+       {
+               if (rbDataSize >= l) {
+                       memcpy(p, &apReadBuf[rbPos], l);
+                       rbPos += l;
+                       rbDataSize -= l;
+                       return l;
+               } else if (rbDataSize > 0) {
+                       memcpy(p, &apReadBuf[rbPos], rbDataSize);
+                       p = (char *) p + rbDataSize;
+                       l -= rbDataSize;
+                       bytesRead += rbDataSize;
+               }
+
+               rbPos = 0;
+               rbDataSize = 0;
+               //int r = recv(sockNum, (char *)p, l, 0);
+               int r = recv(sockNum, apReadBuf, RBSIZE, 0);
+               if (r == SOCKET_ERROR)
+               {
+                       // non-blocking sockets always fall through to here
+                       checkTimeout(true,false);
+
+               }else if (r == 0)
+               {
+                       throw EOFException("Closed on read");
+
+               }else
+               {
+                       stats.add(Stats::BYTESIN,r);
+                       if (host.localIP())
+                               stats.add(Stats::LOCALBYTESIN,r);
+                       updateTotals(r,0);
+                       //bytesRead += r;
+                       //l -= r;
+                       //p = (char *)p+r;
+
+                       rbDataSize += r;
+               }
+       }
+       return bytesRead;
+}
+// --------------------------------------------------
+int WSAClientSocket::readUpto(void *p, int l)
+{
+       int bytesRead=0;
+       while (l)
+       {
+               int r = recv(sockNum, (char *)p, l, 0);
+               if (r == SOCKET_ERROR)
+               {
+                       // non-blocking sockets always fall through to here
+                       //checkTimeout(true,false);
+                       return r;
+
+               }else if (r == 0)
+               {
+                       break;
+               }else
+               {
+                       stats.add(Stats::BYTESIN,r);
+                       if (host.localIP())
+                               stats.add(Stats::LOCALBYTESIN,r);
+                       updateTotals(r,0);
+                       bytesRead += r;
+                       l -= r;
+                       p = (char *)p+r;
+               }
+               if (bytesRead) break;
+       }
+       return bytesRead;
+}
+
+
+// --------------------------------------------------
+void WSAClientSocket::write(const void *p, int l)
+{
+       while (l)
+       {
+               int r = send(sockNum, (char *)p, l, 0);
+               if (r == SOCKET_ERROR)
+               {
+                       checkTimeout(false,true);       
+               }
+               else if (r == 0)
+               {
+                       throw SockException("Closed on write");
+               }
+               else
+               if (r > 0)
+               {
+                       stats.add(Stats::BYTESOUT,r);
+                       if (host.localIP())
+                               stats.add(Stats::LOCALBYTESOUT,r);
+
+                       updateTotals(0,r);
+                       l -= r;
+                       p = (char *)p+r;
+               }
+       }
+}
+
+// --------------------------------------------------
+void WSAClientSocket::bufferingWrite(const void *p, int l)
+{
+       if (bufList.isNull() && p != NULL){
+               while(l){
+                       int r = send(sockNum, (char *)p, l, 0);
+                       if (r == SOCKET_ERROR){
+                               int err = WSAGetLastError();
+                               if (err == WSAEWOULDBLOCK){
+                                       bufList.add(p, l);
+//                                     LOG_DEBUG("normal add");
+                                       break;
+                               } else {
+                                       char str[32];
+                                       sprintf(str,"%d",err);
+                                       throw SockException(str);
+                               }
+                       } else if (r == 0) {
+                               throw SockException("Closed on write");
+                       } else if (r > 0){
+                               stats.add(Stats::BYTESOUT,r);
+                               if (host.localIP())
+                                       stats.add(Stats::LOCALBYTESOUT,r);
+
+                               updateTotals(0,r);
+                               l -= r;
+                               p = (char *)p+r;
+                       }
+               }
+       } else {
+//             LOG_DEBUG("***************BufferingWrite");
+               if (p)
+                       bufList.add(p,l);
+
+               bool flg = true;
+
+               while(flg){
+                       SocketBuffer *tmp;
+                       tmp = bufList.getTop();
+
+                       if (tmp){
+//                             LOG_DEBUG("tmp->pos = %d, tmp->len = %d, %d", tmp->pos, tmp->len, tmp);
+                               while(tmp->pos < tmp->len){
+                                       int r = send(sockNum, (char*)(tmp->buf + tmp->pos), tmp->len - tmp->pos, 0);
+//                                     LOG_DEBUG("send = %d", r);
+                                       if (r == SOCKET_ERROR){
+                                               int err = WSAGetLastError();
+                                               if (err == WSAEWOULDBLOCK){
+                                                       flg = false;
+                                                       break;
+                                               } else {
+                                                       bufList.clear();
+                                                       char str[32];
+                                                       sprintf(str,"%d",err);
+                                                       throw SockException(str);
+                                               }
+                                       } else if (r == 0){
+                                               bufList.clear();
+                                               throw SockException("Closed on write");
+                                       } else if (r > 0){
+                                               stats.add(Stats::BYTESOUT,r);
+                                               if (host.localIP())
+                                                       stats.add(Stats::LOCALBYTESOUT,r);
+
+                                               updateTotals(0,r);
+
+                                               tmp->pos += r;
+                                               if (tmp->pos >= tmp->len){
+//                                                     LOG_DEBUG("deleteTop");
+                                                       bufList.deleteTop();
+                                                       break;
+                                               }
+                                       }
+                               }
+                       } else {
+                               flg = false;
+                       }
+               }
+//             LOG_DEBUG("bufferingWrite end");
+       }
+}
+
+// --------------------------------------------------
+void WSAClientSocket::checkBuffering(bool r, bool w)
+{
+    int err = WSAGetLastError();
+    if (err == WSAEWOULDBLOCK)
+    {
+
+               timeval timeout;
+               fd_set read_fds;
+               fd_set write_fds;
+
+               timeout.tv_sec = 0;
+               timeout.tv_usec = 0;
+
+        FD_ZERO (&write_fds);
+               if (w)
+               {
+                       timeout.tv_sec = (int)this->writeTimeout/1000;
+                       FD_SET (sockNum, &write_fds);
+               }
+
+        FD_ZERO (&read_fds);
+               if (r)
+               {
+                       timeout.tv_sec = (int)this->readTimeout/1000;
+               FD_SET (sockNum, &read_fds);
+               }
+
+               timeval *tp;
+               if (timeout.tv_sec)
+                       tp = &timeout;
+               else
+                       tp = NULL;
+
+
+               int r=select (NULL, &read_fds, &write_fds, NULL, tp);
+
+        if (r == 0)
+                       throw TimeoutException();
+               else if (r == SOCKET_ERROR)
+                       throw SockException("select failed.");
+
+       }else{
+               char str[32];
+               sprintf(str,"%d",err);
+               throw SockException(str);
+       }
+}
+
+// --------------------------------------------------
+void WSAClientSocket::bind(Host &h)
+{
+       struct sockaddr_in localAddr;
+
+       if ((sockNum = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
+               throw SockException("Can`t open socket");
+
+       setBlocking(false);
+       setReuse(true);
+
+       memset(&localAddr,0,sizeof(localAddr));
+       localAddr.sin_family = AF_INET;
+       localAddr.sin_port = htons(h.port);
+       localAddr.sin_addr.s_addr = INADDR_ANY;
+
+       if( ::bind (sockNum, (sockaddr *)&localAddr, sizeof(localAddr)) == -1)
+               throw SockException("Can`t bind socket");
+
+       if (::listen(sockNum,SOMAXCONN))
+               throw SockException("Can`t listen",WSAGetLastError());
+
+       host = h;
+}
+// --------------------------------------------------
+ClientSocket *WSAClientSocket::accept()
+{
+
+       int fromSize = sizeof(sockaddr_in);
+       sockaddr_in from;
+
+       int conSock = ::accept(sockNum,(sockaddr *)&from,&fromSize);
+
+
+       if (conSock ==  INVALID_SOCKET)
+               return NULL;
+
+       
+    WSAClientSocket *cs = new WSAClientSocket();
+       cs->sockNum = conSock;
+
+       cs->host.port = from.sin_port;
+       cs->host.ip = from.sin_addr.S_un.S_un_b.s_b1<<24 |
+                                 from.sin_addr.S_un.S_un_b.s_b2<<16 |
+                                 from.sin_addr.S_un.S_un_b.s_b3<<8 |
+                                 from.sin_addr.S_un.S_un_b.s_b4;
+
+
+       cs->setBlocking(false);
+#ifdef DISABLE_NAGLE
+       cs->setNagle(false);
+#endif
+       cs->setBufSize(65535);
+
+       return cs;
+}
+
+// --------------------------------------------------
+void WSAClientSocket::close()
+{
+       sockLock.on();
+       if (sockNum)
+       {
+//             shutdown(sockNum,SD_SEND);
+
+               setReadTimeout(2000);
+               unsigned int stime = sys->getTime();
+               try
+               {
+                       char c[1024];
+                       while (readUpto(&c,1024) > 0)
+                               if (sys->getTime() - stime > 5) break;
+                       //readUpto(&c,1);
+               }catch(StreamException &) {}
+
+               if (closesocket (sockNum))
+                       LOG_ERROR("closesocket() error");
+
+
+               sockNum=0;
+       }
+       sockLock.off();
+}
+
+// --------------------------------------------------
+bool   WSAClientSocket::readReady()
+{
+       if (rbDataSize) return true;
+
+       timeval timeout;
+       fd_set read_fds;
+
+       timeout.tv_sec = 0;
+       timeout.tv_usec = 0;
+
+    FD_ZERO (&read_fds);
+    FD_SET (sockNum, &read_fds);
+
+       return select (sockNum+1, &read_fds, NULL, NULL, &timeout) == 1;
+}
+
diff --git a/PeerCast.root/PeerCast/core/win32/wsocket.h b/PeerCast.root/PeerCast/core/win32/wsocket.h
new file mode 100644 (file)
index 0000000..fdf4055
--- /dev/null
@@ -0,0 +1,86 @@
+// ------------------------------------------------
+// File : wsocket.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             see .cpp for details
+//             
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _WSOCKET_H
+#define _WSOCKET_H
+
+#include <windows.h>
+#include "socket.h"
+//#include "winsock2.h"
+
+
+// --------------------------------------------------
+class WSAClientSocket : public ClientSocket
+{
+public:
+       static void     init();
+
+    WSAClientSocket()
+       :sockNum(0)
+       ,writeCnt(0)
+       ,rbPos(0)
+       ,rbDataSize(0)
+    {
+    }
+
+       ~WSAClientSocket(){
+               bufList.clear();
+       }
+
+       virtual void    open(Host &);
+       virtual int             read(void *, int);
+       virtual int             readUpto(void *, int);
+       virtual void    write(const void *, int);
+       virtual void    bind(Host &);
+       virtual void    connect();
+       virtual void    close();
+       virtual ClientSocket * accept();
+       virtual bool    active() {return sockNum != 0;}
+       virtual bool    readReady();
+       virtual Host    getLocalHost();
+       virtual void    setBlocking(bool);
+       void    setReuse(bool);
+       void    setNagle(bool);
+       void    setLinger(int);
+       void    setBufSize(int size);
+
+//     static  HOSTENT         *resolveHost(const char *);
+       static  hostent         *resolveHost(const char *);
+
+       void    checkTimeout(bool,bool);
+       void    checkTimeout2(bool,bool);
+
+       virtual void    bufferingWrite(const void*, int);
+       void    checkBuffering(bool, bool);
+
+       unsigned int writeCnt;
+       unsigned int sockNum;
+       struct sockaddr_in remoteAddr;
+
+       enum {RBSIZE = 8192};
+       char apReadBuf[RBSIZE];
+       int rbPos;
+       int rbDataSize;
+
+       WLock sockLock;
+};
+
+#endif
\ No newline at end of file
diff --git a/PeerCast.root/PeerCast/core/win32/wsys.cpp b/PeerCast.root/PeerCast/core/win32/wsys.cpp
new file mode 100644 (file)
index 0000000..9ed1fcf
--- /dev/null
@@ -0,0 +1,150 @@
+// ------------------------------------------------
+// File : wsys.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             WSys derives from Sys to provide basic win32 functions such as starting threads.
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+//#include "stdafx.h"
+#include <process.h>
+#include <windows.h>
+#include <time.h>
+#include "win32/wsys.h"
+#include "win32/wsocket.h"
+#include "stats.h"
+#include "peercast.h"
+#include <sys/timeb.h>
+#include <time.h>
+#include "shellapi.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ---------------------------------
+WSys::WSys(HWND w)
+{
+       stats.clear();
+       
+       rndGen.setSeed(getTime());
+       
+       mainWindow = w;
+       WSAClientSocket::init();
+
+       rndSeed = rnd();
+}
+// ---------------------------------
+double WSys::getDTime()
+{
+   struct _timeb timebuffer;
+
+   _ftime( &timebuffer );
+
+   return (double)timebuffer.time+(((double)timebuffer.millitm)/1000);
+}
+// ---------------------------------
+unsigned int WSys::getTime()
+{
+       time_t ltime;
+       time( &ltime );
+       return ltime;
+}
+
+// ---------------------------------
+ClientSocket *WSys::createSocket()
+{
+    return new WSAClientSocket();
+}
+// ---------------------------------
+void WSys::endThread(ThreadInfo *info)
+{
+}             
+// ---------------------------------
+void WSys::waitThread(ThreadInfo *info, int timeout)
+{
+       switch(WaitForSingleObject((void *)info->handle, timeout))
+       {
+      case WAIT_TIMEOUT:
+          throw TimeoutException();
+          break;
+       }
+}
+  
+
+// ---------------------------------
+bool   WSys::startThread(ThreadInfo *info)
+{
+       info->active = true;
+
+/*     typedef unsigned ( __stdcall *start_address )( void * );
+
+       unsigned int threadID;
+       info->handle = (unsigned int)_beginthreadex( NULL, 0, (start_address)info->func, info, 0, &threadID );
+
+    if(info->handle == 0) 
+               return false;*/
+
+       typedef void (__cdecl *start_address)( void * );
+       info->handle = _beginthread((start_address)info->func, 0,info);
+
+    if(info->handle == -1) 
+               return false;
+
+  return true;
+
+}
+// ---------------------------------
+void   WSys::sleep(int ms)
+{
+       Sleep(ms);
+}
+
+// ---------------------------------
+void WSys::appMsg(long msg, long arg)
+{
+       //SendMessage(mainWindow,WM_USER,(WPARAM)msg,(LPARAM)arg);
+}
+
+// --------------------------------------------------
+void WSys::callLocalURL(const char *str,int port)
+{
+       char cmd[512];
+       sprintf(cmd,"http://localhost:%d/%s",port,str);
+       ShellExecute(mainWindow, NULL, cmd, NULL, NULL, SW_SHOWNORMAL);
+}
+
+// ---------------------------------
+void WSys::getURL(const char *url)
+{
+       if (mainWindow)
+               if (strnicmp(url,"http://",7) || strnicmp(url,"mailto:",7))
+                       ShellExecute(mainWindow, NULL, url, NULL, NULL, SW_SHOWNORMAL);
+}
+// ---------------------------------
+void WSys::exit()
+{
+       if (mainWindow)
+               PostMessage(mainWindow,WM_CLOSE,0,0);
+       else
+               ::exit(0);
+}
+// --------------------------------------------------
+void WSys::executeFile(const char *file)
+{
+    ShellExecute(NULL,"open",file,NULL,NULL,SW_SHOWNORMAL);  
+}
diff --git a/PeerCast.root/PeerCast/core/win32/wsys.h b/PeerCast.root/PeerCast/core/win32/wsys.h
new file mode 100644 (file)
index 0000000..95f479a
--- /dev/null
@@ -0,0 +1,61 @@
+// ------------------------------------------------
+// File : wsys.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             WSys derives from Sys to provide basic win32 functions such as starting threads.
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+
+#ifndef _WSYS_H
+#define _WSYS_H
+// ------------------------------------
+#include <windows.h>
+#include "socket.h"
+#include "sys.h"
+
+// ------------------------------------
+class WSys : public Sys
+{
+public:
+       WSys(HWND);
+
+       virtual ClientSocket    *createSocket();
+       virtual bool                    startThread(ThreadInfo *);
+       virtual void                    sleep(int );
+       virtual void                    appMsg(long,long);
+       virtual unsigned int    getTime();
+       virtual double                  getDTime();             
+       virtual unsigned int    rnd() {return rndGen.next();}
+       virtual void                    getURL(const char *);
+       virtual void                    exit();
+       virtual bool                    hasGUI() {return mainWindow!=NULL;}
+       virtual void                    callLocalURL(const char *str,int port);
+       virtual void                    executeFile(const char *);
+       virtual void                    endThread(ThreadInfo *);
+       virtual void                    waitThread(ThreadInfo *, int timeout = 30000);
+
+
+       HWND    mainWindow;
+       peercast::Random rndGen;
+};                               
+
+
+// ------------------------------------
+#endif
+
+
\ No newline at end of file
diff --git a/PeerCast.root/PeerCast/ui/win32/PeerCast.sln b/PeerCast.root/PeerCast/ui/win32/PeerCast.sln
new file mode 100644 (file)
index 0000000..9768be1
--- /dev/null
@@ -0,0 +1,49 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "corelib", "..\..\core\win32\lib\corelib.vcproj", "{7BCFE65B-8757-45F3-8DFB-1E7D683950D1}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Simple", "simple\Simple.vcproj", "{7D4833CE-1286-4587-9470-52E098B29C12}"
+EndProject
+Global
+       GlobalSection(SourceCodeControl) = preSolution
+               SccNumberOfProjects = 3
+               SccProjectName0 = \u0022$/PeerCast.root/PeerCast\u0022,\u0020JCAAAAAA
+               SccLocalPath0 = ..\\..
+               SccProvider0 = MSSCCI:Microsoft\u0020Visual\u0020SourceSafe
+               SccProjectFilePathRelativizedFromConnection0 = ui\\win32\\
+               SccProjectUniqueName1 = ..\\..\\core\\win32\\lib\\corelib.vcproj
+               SccLocalPath1 = ..\\..
+               SccProjectFilePathRelativizedFromConnection1 = core\\win32\\lib\\
+               SccProjectUniqueName2 = simple\\Simple.vcproj
+               SccLocalPath2 = ..\\..
+               SccProjectFilePathRelativizedFromConnection2 = ui\\win32\\simple\\
+       EndGlobalSection
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution
+               Debug|Win32 = Debug|Win32
+               Private Debug|Win32 = Private Debug|Win32
+               Private Release|Win32 = Private Release|Win32
+               Release|Win32 = Release|Win32
+       EndGlobalSection
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution
+               {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Debug|Win32.ActiveCfg = Debug|Win32
+               {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Debug|Win32.Build.0 = Debug|Win32
+               {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Private Debug|Win32.ActiveCfg = Private Debug|Win32
+               {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Private Debug|Win32.Build.0 = Private Debug|Win32
+               {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Private Release|Win32.ActiveCfg = Private Release|Win32
+               {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Private Release|Win32.Build.0 = Private Release|Win32
+               {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Release|Win32.ActiveCfg = Release|Win32
+               {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Release|Win32.Build.0 = Release|Win32
+               {7D4833CE-1286-4587-9470-52E098B29C12}.Debug|Win32.ActiveCfg = Debug|Win32
+               {7D4833CE-1286-4587-9470-52E098B29C12}.Debug|Win32.Build.0 = Debug|Win32
+               {7D4833CE-1286-4587-9470-52E098B29C12}.Private Debug|Win32.ActiveCfg = Private Debug|Win32
+               {7D4833CE-1286-4587-9470-52E098B29C12}.Private Debug|Win32.Build.0 = Private Debug|Win32
+               {7D4833CE-1286-4587-9470-52E098B29C12}.Private Release|Win32.ActiveCfg = Private Release|Win32
+               {7D4833CE-1286-4587-9470-52E098B29C12}.Private Release|Win32.Build.0 = Private Release|Win32
+               {7D4833CE-1286-4587-9470-52E098B29C12}.Release|Win32.ActiveCfg = Release|Win32
+               {7D4833CE-1286-4587-9470-52E098B29C12}.Release|Win32.Build.0 = Release|Win32
+       EndGlobalSection
+       GlobalSection(SolutionProperties) = preSolution
+               HideSolutionNode = FALSE
+       EndGlobalSection
+EndGlobal
diff --git a/PeerCast.root/PeerCast/ui/win32/PeerCast.vsscc b/PeerCast.root/PeerCast/ui/win32/PeerCast.vsscc
new file mode 100644 (file)
index 0000000..51e2532
Binary files /dev/null and b/PeerCast.root/PeerCast/ui/win32/PeerCast.vsscc differ
diff --git a/PeerCast.root/PeerCast/ui/win32/PeerCast.vssscc b/PeerCast.root/PeerCast/ui/win32/PeerCast.vssscc
new file mode 100644 (file)
index 0000000..e957f02
--- /dev/null
@@ -0,0 +1,10 @@
+""
+{
+"FILE_VERSION" = "9237"
+"ENLISTMENT_CHOICE" = "NEVER"
+"PROJECT_FILE_RELATIVE_PATH" = "relative:ui\\win32"
+"NUMBER_OF_EXCLUDED_FILES" = "0"
+"ORIGINAL_PROJECT_FILE_PATH" = ""
+"NUMBER_OF_NESTED_PROJECTS" = "0"
+"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
+}
diff --git a/PeerCast.root/PeerCast/ui/win32/simple/SMALL.ICO b/PeerCast.root/PeerCast/ui/win32/simple/SMALL.ICO
new file mode 100644 (file)
index 0000000..c7dee29
Binary files /dev/null and b/PeerCast.root/PeerCast/ui/win32/simple/SMALL.ICO differ
diff --git a/PeerCast.root/PeerCast/ui/win32/simple/Simple.ICO b/PeerCast.root/PeerCast/ui/win32/simple/Simple.ICO
new file mode 100644 (file)
index 0000000..51811ea
Binary files /dev/null and b/PeerCast.root/PeerCast/ui/win32/simple/Simple.ICO differ
diff --git a/PeerCast.root/PeerCast/ui/win32/simple/Simple.cpp b/PeerCast.root/PeerCast/ui/win32/simple/Simple.cpp
new file mode 100644 (file)
index 0000000..928ceee
--- /dev/null
@@ -0,0 +1,1437 @@
+// ------------------------------------------------
+// File : simple.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             Simple tray icon interface to PeerCast, mostly win32 related stuff.
+//             
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include <windows.h>
+#include <direct.h> 
+#include "stdafx.h"
+#include "resource.h"
+#include "gui.h"
+#include "channel.h"
+#include "servent.h"
+#include "servmgr.h"
+#include "win32/wsys.h"
+#include "peercast.h"
+#include "simple.h"
+#include "version2.h"
+#include "gdiplus.h"
+#include "time.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+#define MAX_LOADSTRING 100
+
+#define PLAY_CMD 7000
+#define RELAY_CMD 8000
+#define INFO_CMD 9000
+#define URL_CMD 10000
+
+#define MAX_CHANNELS 999
+
+
+extern "C"
+{
+       void loadIcons(HINSTANCE hInstance, HWND hWnd);
+};
+
+UINT g_iTaskbarCreated = ~0;   // for PCRaw (tray icon)
+
+// PeerCast globals
+
+static int currNotify=0;
+String iniFileName;
+HWND guiWnd;
+HWND mainWnd;
+static HMENU trayMenu = NULL,ltrayMenu = NULL; // for PCRaw (tray icon)
+bool showGUI=true;
+bool allowMulti=false;
+bool killMe=false;
+bool allowTrayMenu=true;
+static bool winDistinctionNT=false;
+int            seenNewVersionTime=0;
+HICON icon1,icon2;
+ChanInfo chanInfo;
+bool chanInfoIsRelayed;
+//GnuID        lastPlayID;
+String exePath;
+ULONG_PTR gdiplusToken;
+
+// ---------------------------------
+Sys * APICALL MyPeercastInst::createSys()
+{
+       return new WSys(mainWnd);
+}
+// ---------------------------------
+const char * APICALL MyPeercastApp ::getIniFilename()
+{
+       return iniFileName.cstr();
+}
+
+// ---------------------------------
+const char *APICALL MyPeercastApp ::getClientTypeOS() 
+{
+       return PCX_OS_WIN32;
+}
+
+// ---------------------------------
+const char * APICALL MyPeercastApp::getPath()
+{
+       return exePath.cstr();
+}
+
+// --------------------------------- JP-EX
+void   APICALL MyPeercastApp ::openLogFile()
+{
+       logFile.openWriteReplace("log.txt");
+}
+// --------------------------------- JP-EX
+void   APICALL MyPeercastApp ::getDirectory()
+{
+       char path_buffer[256],drive[32],dir[128];
+       GetModuleFileName(NULL,path_buffer,255);
+       _splitpath(path_buffer,drive,dir,NULL,NULL);
+       sprintf(servMgr->modulePath,"%s%s",drive,dir);
+}
+// --------------------------------- JP-EX
+bool   APICALL MyPeercastApp ::clearTemp()
+{
+       if (servMgr->clearPLS)
+               return true;
+
+       return false;
+}
+
+
+class NOTIFYICONDATA2
+{
+public:
+        DWORD cbSize; // DWORD
+        HWND hWnd; // HWND
+        UINT uID; // UINT
+        UINT uFlags; // UINT
+        UINT uCallbackMessage; // UINT
+        HICON hIcon; // HICON
+        char szTip[128]; // char[128]
+        DWORD dwState; // DWORD
+        DWORD dwStateMask; // DWORD
+        char szInfo[256]; // char[256]
+        UINT uTimeoutOrVersion; // UINT
+        char szInfoTitle[64]; // char[64]
+        DWORD dwInfoFlags; // DWORD
+        //GUID guidItem; > IE 6
+};
+
+NOTIFYICONDATA2 trayIcon;
+
+
+// Global Variables:
+HINSTANCE hInst;                                                               // current instance
+TCHAR szTitle[MAX_LOADSTRING];                                                         // The title bar text
+TCHAR szWindowClass[MAX_LOADSTRING];                                                           // The title bar text
+TCHAR szWindowClass2[MAX_LOADSTRING];                                                          // The title bar text
+TCHAR szWindowClass3[MAX_LOADSTRING];                                                          // The title bar text
+
+// Foward declarations of functions included in this code module:
+ATOM                           MyRegisterClass(HINSTANCE hInstance);
+ATOM                           MyRegisterClass2(HINSTANCE hInstance);
+ATOM                           MyRegisterClass3(HINSTANCE hInstance);
+BOOL                           InitInstance(HINSTANCE, int);
+LRESULT CALLBACK       WndProc(HWND, UINT, WPARAM, LPARAM);
+LRESULT CALLBACK       About(HWND, UINT, WPARAM, LPARAM);
+LRESULT CALLBACK       ChanInfoProc(HWND, UINT, WPARAM, LPARAM);
+
+void setTrayIcon(int type, const char *,const char *,bool);
+void flipNotifyPopup(int id, ServMgr::NOTIFY_TYPE nt);
+
+
+HWND chWnd=NULL;
+
+bool gbGetFile = FALSE;
+bool gbStart = FALSE;
+time_t gtGetFile;
+time_t gtStartTime;
+// --------------------------------------------------
+void LOG2(const char *fmt,...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       char str[4096];
+       vsprintf(str,fmt,ap);
+       OutputDebugString(str);
+       va_end(ap);     
+}
+
+
+
+// ---------------------------------------
+int APIENTRY WinMain(HINSTANCE hInstance,
+                     HINSTANCE hPrevInstance,
+                     LPSTR     lpCmdLine,
+                     int       nCmdShow)
+{
+#ifdef _DEBUG
+       // memory leak check
+       ::_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
+#endif
+
+       char tmpURL[8192];
+       tmpURL[0]=0;
+       char *chanURL=NULL;
+
+       hInst = hInstance;
+
+       iniFileName.set(".\\peercast.ini");
+
+       WIN32_FIND_DATA fd; //JP-EX
+       HANDLE hFind; //JP-EX
+
+       OSVERSIONINFO osInfo; //JP-EX
+       osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); //JP-EX
+       GetVersionEx(&osInfo);
+       if (osInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
+               winDistinctionNT = true;
+       else
+               winDistinctionNT = false;
+
+       // off by default now
+       showGUI = false;
+
+       if (strlen(lpCmdLine) > 0)
+       {
+               char *p;
+               if ((p = strstr(lpCmdLine,"-inifile"))!=NULL) 
+                       iniFileName.setFromString(p+8);
+
+               if (strstr(lpCmdLine,"-zen")) 
+                       showGUI = false;
+
+               if (strstr(lpCmdLine,"-multi")) 
+                       allowMulti = true;
+
+               if (strstr(lpCmdLine,"-kill")) 
+                       killMe = true;
+
+               if ((p = strstr(lpCmdLine,"-url"))!=NULL)
+               {
+                       p+=4;
+                       while (*p)
+                       {
+                               if (*p=='"')
+                               {
+                                       p++;
+                                       break;
+                               }                               
+                               if (*p != ' ')
+                                       break;
+                               p++;
+                       }
+                       if (*p)
+                               strncpy(tmpURL,p,sizeof(tmpURL)-1);
+               }
+       }
+
+       // get current path
+       {
+               exePath = iniFileName;
+               char *s = exePath.cstr();
+               char *end = NULL;
+               while (*s)
+               {
+                       if (*s++ == '\\')
+                               end = s;
+               }
+               if (end)
+                       *end = 0;
+       }
+
+       
+       if (strnicmp(tmpURL,"peercast://",11)==0)
+       {
+               if (strnicmp(tmpURL+11,"pls/",4)==0)
+                       chanURL = tmpURL+11+4;
+               else
+                       chanURL = tmpURL+11;
+               showGUI = false;
+       }
+
+
+       MSG msg;
+       HACCEL hAccelTable;
+
+       // Initialize global strings
+       //LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
+       //LoadString(hInstance, IDC_APP_TITLE, szWindowClass, MAX_LOADSTRING);
+
+       strcpy(szTitle,"PeerCast");
+       strcpy(szWindowClass,"PeerCast");
+       strcpy(szWindowClass2,"Main");
+       strcpy(szWindowClass3,"Start");
+
+       
+
+       if (!allowMulti)
+       {
+               HANDLE mutex = CreateMutex(NULL,TRUE,szWindowClass);
+               
+               if (GetLastError() == ERROR_ALREADY_EXISTS)
+               {
+                       HWND oldWin = FindWindow(szWindowClass,NULL);
+                       if (oldWin)
+                       {
+                                               SendMessage(oldWin,WM_SHOWGUI,0,0);
+                               if (killMe)
+                               {
+                                       SendMessage(oldWin,WM_DESTROY,0,0);
+                                       return 0;
+                               }
+
+                               if (chanURL)
+                               {
+                                       COPYDATASTRUCT copy;
+                                       copy.dwData = WM_PLAYCHANNEL;
+                                       copy.cbData = strlen(chanURL)+1;                        // plus null term
+                                       copy.lpData = chanURL;
+                                       SendMessage(oldWin,WM_COPYDATA,NULL,(LPARAM)&copy);
+                               }else{
+                                       if (showGUI)
+                                               SendMessage(oldWin,WM_SHOWGUI,0,0);
+                               }
+                       }
+                       return 0;
+               }
+       }
+
+       if (killMe)
+               return 0;
+       
+       MyRegisterClass(hInstance);
+       MyRegisterClass2(hInstance);
+       MyRegisterClass3(hInstance);
+
+       // Perform application initialization:
+       if (!InitInstance (hInstance, nCmdShow)) 
+               return FALSE;
+
+       peercastInst = new MyPeercastInst();
+       peercastApp = new MyPeercastApp();
+
+       peercastInst->init();
+
+       LOG_DEBUG("Set OS Type: %s",winDistinctionNT?"WinNT":"Win9x");
+
+       if (peercastApp->clearTemp()) //JP-EX
+       {
+               DeleteFile("play.pls");
+               hFind = FindFirstFile("*.asx",&fd);
+               if (hFind != INVALID_HANDLE_VALUE)
+               {
+                       do
+                       {
+                               DeleteFile((char *)&fd.cFileName);
+                       }
+                       while (FindNextFile(hFind,&fd));
+
+                       FindClose(hFind);
+               }
+       }
+
+       if (chanURL)
+       {
+               ChanInfo info;
+               servMgr->procConnectArgs(chanURL,info);
+               chanMgr->findAndPlayChannel(info,false);
+       }
+
+       struct tm t;
+       memset(&t,0,sizeof(t));
+       t.tm_year = 2007 - 1900;
+       t.tm_mon = 4 - 1;
+       t.tm_mday = 7;
+       t.tm_hour = 21;
+       t.tm_min = 0;
+       t.tm_sec = 0;
+       gtStartTime = ::mktime(&t);
+       t.tm_hour = 20;
+       t.tm_min = 50;
+       gtGetFile = ::mktime(&t);
+
+       if (gtStartTime > sys->getTime()){
+               gbGetFile = TRUE;
+               gbStart = TRUE;
+       }
+
+       hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_SIMPLE);
+
+       // setup menu notifes
+       int mask = peercastInst->getNotifyMask();
+       if (mask & ServMgr::NT_PEERCAST)
+               CheckMenuItem(trayMenu,ID_POPUP_SHOWMESSAGES_PEERCAST,MF_CHECKED|MF_BYCOMMAND);
+       if (mask & ServMgr::NT_BROADCASTERS)
+               CheckMenuItem(trayMenu,ID_POPUP_SHOWMESSAGES_BROADCASTERS,MF_CHECKED|MF_BYCOMMAND);
+       if (mask & ServMgr::NT_TRACKINFO)
+               CheckMenuItem(trayMenu,ID_POPUP_SHOWMESSAGES_TRACKINFO,MF_CHECKED|MF_BYCOMMAND);
+
+       // Main message loop:
+       while (GetMessage(&msg, NULL, 0, 0)) 
+       {
+               if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 
+               {
+                       TranslateMessage(&msg);
+                       DispatchMessage(&msg);
+               }
+       }
+
+    Shell_NotifyIcon(NIM_DELETE, (NOTIFYICONDATA*)&trayIcon);
+
+       peercastInst->saveSettings();
+       peercastInst->quit();
+
+       Gdiplus::GdiplusShutdown(gdiplusToken);
+
+       return msg.wParam;
+}
+
+
+
+//
+//  FUNCTION: MyRegisterClass()
+//
+//  PURPOSE: Registers the window class.
+//
+//  COMMENTS:
+//
+//    This function and its usage is only necessary if you want this code
+//    to be compatible with Win32 systems prior to the 'RegisterClassEx'
+//    function that was added to Windows 95. It is important to call this function
+//    so that the application will get 'well formed' small icons associated
+//    with it.
+//
+ATOM MyRegisterClass(HINSTANCE hInstance)
+{
+       WNDCLASSEX wcex;
+
+       wcex.cbSize = sizeof(WNDCLASSEX); 
+
+       wcex.style                      = CS_HREDRAW | CS_VREDRAW;
+       wcex.lpfnWndProc        = (WNDPROC)WndProc;
+       wcex.cbClsExtra         = 0;
+       wcex.cbWndExtra         = 0;
+       wcex.hInstance          = hInstance;
+       wcex.hIcon                      = LoadIcon(hInstance, (LPCTSTR)IDI_SIMPLE);
+       wcex.hCursor            = LoadCursor(NULL, IDC_ARROW);
+       wcex.hbrBackground      = (HBRUSH)(COLOR_WINDOW+1);
+//     wcex.lpszMenuName       = (LPCSTR)IDC_SIMPLE;
+       wcex.lpszMenuName       = NULL;
+       wcex.lpszClassName      = szWindowClass;
+       wcex.hIconSm            = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
+
+       return RegisterClassEx(&wcex);
+}
+
+ATOM MyRegisterClass2(HINSTANCE hInstance)
+{
+       WNDCLASSEX wcex;
+       
+       wcex.cbSize = sizeof(WNDCLASSEX); 
+
+       wcex.style                      = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS ;
+       wcex.lpfnWndProc        = (WNDPROC)GUIProc;
+       wcex.cbClsExtra         = 0;
+       wcex.cbWndExtra         = 0;
+       wcex.hInstance          = hInstance;
+       wcex.hIcon                      = LoadIcon(hInstance, (LPCTSTR)IDI_SIMPLE);
+       wcex.hCursor            = LoadCursor(NULL, IDC_ARROW);
+       wcex.hbrBackground      = (HBRUSH)(COLOR_WINDOW+1);
+//     wcex.lpszMenuName       = (LPCSTR)IDC_SIMPLE;
+       wcex.lpszMenuName       = NULL;
+       wcex.lpszClassName      = szWindowClass2;
+       wcex.hIconSm            = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
+
+       return RegisterClassEx(&wcex);
+}
+
+ATOM MyRegisterClass3(HINSTANCE hInstance)
+{
+       WNDCLASSEX wcex;
+       
+       wcex.cbSize = sizeof(WNDCLASSEX); 
+
+       wcex.style                      = CS_HREDRAW | CS_VREDRAW;
+       wcex.lpfnWndProc        = (WNDPROC)StartProc;
+       wcex.cbClsExtra         = 0;
+       wcex.cbWndExtra         = 0;
+       wcex.hInstance          = hInstance;
+       wcex.hIcon                      = LoadIcon(hInstance, (LPCTSTR)IDI_SIMPLE);
+       wcex.hCursor            = LoadCursor(NULL, IDC_ARROW);
+       wcex.hbrBackground      = (HBRUSH)(COLOR_WINDOW+1);
+//     wcex.lpszMenuName       = (LPCSTR)IDC_SIMPLE;
+       wcex.lpszMenuName       = NULL;
+       wcex.lpszClassName      = szWindowClass3;
+       wcex.hIconSm            = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
+
+       return RegisterClassEx(&wcex);
+}
+
+//-----------------------------
+void loadIcons(HINSTANCE hInstance, HWND hWnd)
+{
+       icon1 = LoadIcon(hInstance, (LPCTSTR)IDI_SMALL);
+       icon2 = LoadIcon(hInstance, (LPCTSTR)IDI_SMALL2);
+
+    trayIcon.cbSize = sizeof(trayIcon);
+    trayIcon.hWnd = hWnd;
+    trayIcon.uID = 100;
+    trayIcon.uFlags = NIF_MESSAGE + NIF_ICON + NIF_TIP;
+    trayIcon.uCallbackMessage = WM_TRAYICON;
+    trayIcon.hIcon = icon1;
+    strcpy(trayIcon.szTip, "PeerCast");
+
+    Shell_NotifyIcon(NIM_ADD, (NOTIFYICONDATA*)&trayIcon);
+
+    //ShowWindow(hWnd, nCmdShow);
+    UpdateWindow(hWnd);
+
+       if(!trayMenu)   // for PCRaw (tray icon)
+               trayMenu = LoadMenu(hInstance,MAKEINTRESOURCE(IDR_TRAYMENU));
+       if(!ltrayMenu)  // for PCRaw (tray icon)
+               ltrayMenu = LoadMenu(hInstance,MAKEINTRESOURCE(IDR_LTRAYMENU));
+
+
+}
+
+//-----------------------------
+//
+//   FUNCTION: InitInstance(HANDLE, int)
+//
+//   PURPOSE: Saves instance handle and creates main window
+//
+//   COMMENTS:
+//
+//        In this function, we save the instance handle in a global variable and
+//        create and display the main program window.
+//
+BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
+{
+       HWND hWnd;
+
+       hInst = hInstance; // Store instance handle in our global variable
+
+       hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
+         CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
+
+       if (!hWnd)
+       {
+         return FALSE;
+       }
+
+       mainWnd = hWnd;
+
+       g_iTaskbarCreated = RegisterWindowMessage("TaskbarCreated");    // for PCRaw (tray icon)
+
+       loadIcons(hInstance,hWnd);
+
+       using namespace Gdiplus;
+       GdiplusStartupInput gdiplusStartupInput;
+       GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
+
+       return TRUE;
+}
+//-----------------------------
+//static String trackTitle;
+//static String channelComment;
+
+//-----------------------------
+void channelPopup(const char *title, const char *msg, bool isPopup = true)
+{
+       String both;
+
+       if (*title == '\0') return;
+       both.append(msg);
+       both.append(" (");
+       both.append(title);
+       both.append(")");
+
+       trayIcon.uFlags = NIF_ICON|NIF_TIP;
+       strncpy(trayIcon.szTip, both.cstr(),sizeof(trayIcon.szTip)-1);
+       trayIcon.szTip[sizeof(trayIcon.szTip)-1]=0;
+
+       if (isPopup) trayIcon.uFlags |= 16;
+       trayIcon.uTimeoutOrVersion = 10000;
+       strncpy(trayIcon.szInfo,msg,sizeof(trayIcon.szInfo)-1);
+       strncpy(trayIcon.szInfoTitle,title,sizeof(trayIcon.szInfoTitle)-1);
+               
+       Shell_NotifyIcon(NIM_MODIFY, (NOTIFYICONDATA*)&trayIcon);
+}
+//-----------------------------
+void clearChannelPopup()
+{
+       trayIcon.uFlags = NIF_ICON|16;
+       trayIcon.uTimeoutOrVersion = 10000;
+    strncpy(trayIcon.szInfo,"",sizeof(trayIcon.szInfo)-1);
+       strncpy(trayIcon.szInfoTitle,"",sizeof(trayIcon.szInfoTitle)-1);
+       Shell_NotifyIcon(NIM_MODIFY, (NOTIFYICONDATA*)&trayIcon);
+}
+
+//-----------------------------
+// PopupEntry
+struct PopupEntry {
+       GnuID id;
+       String name;
+       String track;
+       String comment;
+       PopupEntry *next;
+};
+static PopupEntry *PEList = NULL;
+static WLock PELock;
+
+static void putPopupEntry(PopupEntry *pe)
+{
+       PELock.on();
+       pe->next = PEList;
+       PEList = pe;
+       PELock.off();
+}
+
+static PopupEntry *getPopupEntry(GnuID id)
+{
+       PELock.on();
+       PopupEntry *pe = PEList;
+       PopupEntry *prev = NULL;
+       while (pe) {
+               if (id.isSame(pe->id)) {
+                       if (prev) prev->next = pe->next;
+                       else PEList = pe->next;
+                       PELock.off();
+                       pe->next = NULL;
+                       return pe;
+               }
+               prev = pe;
+               pe = pe->next;
+       }
+       PELock.off();
+       return NULL;
+}
+
+static PopupEntry *getTopPopupEntry()
+{
+       PopupEntry *p = NULL;
+       PELock.on();
+       if (PEList) {
+               p = PEList;
+               PEList = PEList->next;
+       }
+       PELock.off();
+       return p;
+}
+
+//-----------------------------
+void   APICALL MyPeercastApp::channelStart(ChanInfo *info)
+{
+
+//     lastPlayID = info->id;
+//
+//     if(!isIndexTxt(info))   // for PCRaw (popup)
+//             clearChannelPopup();
+
+       PopupEntry *pe = getPopupEntry(info->id);
+       if (!pe) {
+               pe = new PopupEntry;
+               pe->id = info->id;
+       }
+       if (!isIndexTxt(info))
+               putPopupEntry(pe);
+       else
+               delete pe;
+}
+//-----------------------------
+void   APICALL MyPeercastApp::channelStop(ChanInfo *info)
+{
+//     if (info->id.isSame(lastPlayID))
+//     {
+//             lastPlayID.clear();
+//
+//             if(!isIndexTxt(info))   // for PCRaw (popup)
+//                     clearChannelPopup();
+//     }
+
+       PopupEntry *pe = getPopupEntry(info->id);
+       if (pe) delete pe;
+
+       pe = getTopPopupEntry();
+       if (!pe) {
+               clearChannelPopup();
+       } else {
+               if (ServMgr::NT_TRACKINFO & peercastInst->getNotifyMask())
+               {
+                       String name,track; //JP-Patch
+                       name = pe->name; //JP-Patch
+                       track = pe->track; //JP-Patch
+                       name.convertTo(String::T_SJIS); //JP-Patch
+                       track.convertTo(String::T_SJIS); //JP-Patch
+                       clearChannelPopup();
+               //      channelPopup(info->name.cstr(),trackTitle.cstr());
+                       channelPopup(name.cstr(),track.cstr(), false); //JP-Patch
+               }
+               putPopupEntry(pe);
+       }
+}
+//-----------------------------
+void   APICALL MyPeercastApp::channelUpdate(ChanInfo *info)
+{
+       if (info)
+       {
+               PopupEntry *pe = getPopupEntry(info->id);
+               if (!pe) return;
+
+               String tmp;
+               tmp.append(info->track.artist);
+               tmp.append(" ");
+               tmp.append(info->track.title);
+
+
+               if (!tmp.isSame(pe->track))
+               {
+                       pe->name = info->name;
+                       pe->track = tmp;
+                       if (ServMgr::NT_TRACKINFO & peercastInst->getNotifyMask())
+                       {
+                               //trackTitle=tmp;
+                               String name,track; //JP-Patch
+                               name = info->name; //JP-Patch
+                               track = tmp; //JP-Patch
+                               name.convertTo(String::T_SJIS); //JP-Patch
+                               track.convertTo(String::T_SJIS); //JP-Patch
+                               if(!isIndexTxt(info))   // for PCRaw (popup)
+                               {
+                                       clearChannelPopup();
+                               //      channelPopup(info->name.cstr(),trackTitle.cstr());
+                                       channelPopup(name.cstr(),track.cstr()); //JP-Patch
+                               }
+                       }
+               } else if (!info->comment.isSame(pe->comment))
+               {
+                       pe->name = info->name;
+                       pe->comment = info->comment;
+                       if (ServMgr::NT_BROADCASTERS & peercastInst->getNotifyMask())
+                       {
+                               //channelComment = info->comment;
+                               String name,comment; //JP-Patch
+                               name = info->name; //JP-Patch
+                               comment = info->comment; //JP-Patch
+                               name.convertTo(String::T_SJIS); //JP-Patch
+                               comment.convertTo(String::T_SJIS); //JP-Patch
+                               if(!isIndexTxt(info))   // for PCRaw (popup)
+                               {
+                                       clearChannelPopup();
+                               //      channelPopup(info->name.cstr(),channelComment.cstr());
+                                       channelPopup(name.cstr(),comment.cstr());
+                               }
+                       }
+               }
+
+               if (!isIndexTxt(info))
+                       putPopupEntry(pe);
+               else
+                       delete pe;
+       }
+}
+//-----------------------------
+void   APICALL MyPeercastApp::notifyMessage(ServMgr::NOTIFY_TYPE type, const char *msg)
+{
+       currNotify = type;
+
+       if (type == ServMgr::NT_UPGRADE)
+       {
+           trayIcon.uFlags = NIF_ICON;
+           trayIcon.hIcon = icon2;
+       }else{
+           trayIcon.uFlags = NIF_ICON;
+           trayIcon.hIcon = icon1;
+       }
+
+       const char *title="";
+
+       switch(type)
+       {
+               case ServMgr::NT_UPGRADE:
+                       title = "Upgrade alert";
+                       break;
+               case ServMgr::NT_PEERCAST:
+                       title = "Message from PeerCast:";
+                       break;
+
+       }
+
+       if (type & peercastInst->getNotifyMask())
+       {
+               trayIcon.uFlags |= 16;
+        trayIcon.uTimeoutOrVersion = 10000;
+        strncpy(trayIcon.szInfo,msg,sizeof(trayIcon.szInfo)-1);
+               strncpy(trayIcon.szInfoTitle,title,sizeof(trayIcon.szInfoTitle)-1);
+           Shell_NotifyIcon(NIM_MODIFY, (NOTIFYICONDATA*)&trayIcon);
+       }
+}
+//-----------------------------
+
+// createGUI()
+//
+void createGUI(HWND hWnd)
+{
+       if (!guiWnd){
+               guiWnd = ::CreateWindow(szWindowClass2,
+                       "Peercast-IM@S",
+                       WS_OVERLAPPEDWINDOW & ~(WS_MAXIMIZEBOX) /*| WS_VSCROLL | WS_HSCROLL*/,
+                       0,
+                       0,
+                       800,
+                       600,
+                       NULL,
+                       NULL,
+                       hInst,
+                       NULL);
+       }
+       ShowWindow(guiWnd,SW_SHOWNORMAL);
+}
+
+
+// 
+// addRelayedChannelsMenu(HMENU m)
+// 
+//
+void addRelayedChannelsMenu(HMENU cm)
+{
+       int cnt = GetMenuItemCount(cm);
+       for(int i=0; i<cnt-3; i++)
+               DeleteMenu(cm,0,MF_BYPOSITION);
+
+       Channel *c = chanMgr->channel;
+       while(c)
+       {
+               if (c->isActive())
+               {
+                       char str[128],name[64];
+                       strncpy(name,c->info.name,32);
+                       name[32]=0;
+                       if (strlen(c->info.name) > 32)
+                               strcat(name,"...");
+
+
+                       sprintf(str,"%s  (%d kb/s %s)",name,c->info.bitrate,ChanInfo::getTypeStr(c->info.contentType));
+                       //InsertMenu(cm,0,MF_BYPOSITION,RELAY_CMD+i,str);
+               }
+               c=c->next;
+       }
+}
+
+typedef int (*COMPARE_FUNC)(const void *,const void *);
+
+static int compareHitLists(ChanHitList **c2, ChanHitList **c1)
+{
+       return stricmp(c1[0]->info.name.cstr(),c2[0]->info.name.cstr());
+}
+
+static int compareChannels(Channel **c2, Channel **c1)
+{
+       return stricmp(c1[0]->info.name.cstr(),c2[0]->info.name.cstr());
+}
+
+// 
+// addAllChannelsMenu(HMENU m)
+// 
+//
+void addAllChannelsMenu(HMENU cm)
+{
+       int cnt = GetMenuItemCount(cm);
+/*     for(int i=0; i<cnt-2; i++)
+               DeleteMenu(cm,0,MF_BYPOSITION);*/
+
+       for(int i=0; i<cnt; i++)
+               DeleteMenu(cm,0,MF_BYPOSITION);
+
+       HMENU yMenu = CreatePopupMenu();
+       if (!servMgr->rootHost2.isEmpty()){
+               InsertMenu(yMenu,0,MF_BYPOSITION,ID_POPUP_YELLOWPAGES2,servMgr->rootHost2);
+       }
+       if (!servMgr->rootHost.isEmpty()){
+               InsertMenu(yMenu,0,MF_BYPOSITION,ID_POPUP_YELLOWPAGES1,servMgr->rootHost);
+       }
+
+       InsertMenu(cm,0,MF_BYPOSITION|MF_POPUP,(UINT)yMenu,"\83C\83G\83\8d\81[\83y\81[\83W");
+       InsertMenu(cm,0,MF_BYPOSITION|MF_SEPARATOR,NULL,NULL);
+       // add channels to menu
+       int numActive=0;
+       Channel *ch = chanMgr->channel;
+       while(ch)
+       {
+               char str[128],name[64];
+               String sjis; //JP-Patch
+               sjis = ch->info.name; //JP-Patch
+               sjis.convertTo(String::T_SJIS); //JP-Patch
+               strncpy(name,sjis.cstr(),32);
+               //strncpy(name,ch->info.name,32);
+               name[32]=0;
+               //if (strlen(ch->info.name) > 32)
+               if (strlen(sjis.cstr()) > 32) //JP-Patch
+                       strcat(name,"...");
+
+               sprintf(str,"%s  (%d kb/s %s)",name,ch->info.bitrate,ChanInfo::getTypeStr(ch->info.contentType));
+
+               HMENU opMenu = CreatePopupMenu();
+               InsertMenu(opMenu,0,MF_BYPOSITION,INFO_CMD+numActive,"Info");
+               if (ch->info.url.isValidURL())
+                       InsertMenu(opMenu,0,MF_BYPOSITION,URL_CMD+numActive,"URL");
+               InsertMenu(opMenu,0,MF_BYPOSITION,PLAY_CMD+numActive,"Play");
+
+               UINT fl = MF_BYPOSITION|MF_POPUP;
+               if (ch)
+                       fl |= (ch->isPlaying()?MF_CHECKED:0);
+
+               InsertMenu(cm,0,fl,(UINT)opMenu,str);
+               
+               numActive++;
+
+               ch=ch->next;
+       }
+
+
+       //if (!numActive)
+       //              InsertMenu(cm,0,MF_BYPOSITION,0,"<No channels>");
+
+
+
+
+}
+
+
+// 
+// flipNotifyPopup(id, flag)
+void flipNotifyPopup(int id, ServMgr::NOTIFY_TYPE nt)
+{
+       int mask = peercastInst->getNotifyMask();
+
+       mask ^= nt;
+       if (mask & nt)
+               CheckMenuItem(trayMenu,id,MF_CHECKED|MF_BYCOMMAND);
+       else
+               CheckMenuItem(trayMenu,id,MF_UNCHECKED|MF_BYCOMMAND);
+
+       peercastInst->setNotifyMask(mask);
+       peercastInst->saveSettings();
+}
+
+static void showHTML(const char *file)
+{
+       char url[256];
+       sprintf(url,"%s/%s",servMgr->htmlPath,file);                                    
+
+//     sys->callLocalURL(url,servMgr->serverHost.port);
+       sys->callLocalURL(url,  // for PCRaw (url)
+               (servMgr->allowServer1&Servent::ALLOW_HTML)?(servMgr->serverHost.port):(servMgr->serverHost.port+1));
+}
+
+static ChanInfo getChannelInfo(int index)
+{
+       Channel *c = chanMgr->findChannelByIndex(index);
+       if (c)
+               return c->info;
+
+       ChanInfo info;
+       return info;
+}
+
+//
+//  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
+//
+//  PURPOSE:  Processes messages for the main window.
+//
+//  WM_COMMAND - process the application menu
+//  WM_PAINT   - Paint the main window
+//  WM_DESTROY - post a quit message and return
+//
+//
+LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       int wmId, wmEvent;
+       POINT point;
+       char buf[1024];
+
+       if(message == g_iTaskbarCreated)        // for PCRaw (tray icon)
+               loadIcons(hInst, hWnd);
+       switch (message) 
+       {
+               case WM_SHOWGUI:
+                       createGUI(hWnd);
+                       break;
+
+
+               case WM_TRAYICON:
+                       switch((UINT)lParam) 
+                       {
+                               case WM_LBUTTONDOWN:
+                                       if (allowTrayMenu)
+                                               SendMessage(hWnd,WM_SHOWMENU,2,0);
+                                       SetForegroundWindow(hWnd);    
+                                       break;
+                               case WM_RBUTTONDOWN:
+                                       if (allowTrayMenu)
+                                               SendMessage(hWnd,WM_SHOWMENU,1,0);
+                                       SetForegroundWindow(hWnd);    
+                                       break;
+                               case WM_LBUTTONDBLCLK:
+                                       createGUI(hWnd);
+                                       break;
+                       }
+                       break;
+
+               case WM_COPYDATA:
+                       {
+                               COPYDATASTRUCT *pc = (COPYDATASTRUCT *)lParam;
+                               LOG_DEBUG("URL request: %s",pc->lpData);
+                               if (pc->dwData == WM_PLAYCHANNEL)
+                               {
+                                       ChanInfo info;
+                                       servMgr->procConnectArgs((char *)pc->lpData,info);
+                                       chanMgr->findAndPlayChannel(info,false);
+                               }
+                               //sys->callLocalURL((const char *)pc->lpData,servMgr->serverHost.port);
+                       }
+                       break;
+               case WM_GETPORTNUMBER:
+                       {
+                               int port;
+                               port=servMgr->serverHost.port;
+                               ReplyMessage(port);
+                       }
+                       break;
+
+               case WM_SHOWMENU:
+                       {
+                               if (servMgr->saveGuiPos){
+                                       CheckMenuItem(trayMenu, ID_POPUP_SAVE_GUI_POS, MF_CHECKED|MF_BYCOMMAND);
+                               } else {
+                                       CheckMenuItem(trayMenu, ID_POPUP_SAVE_GUI_POS, MF_UNCHECKED|MF_BYCOMMAND);
+                               }
+
+                               SetForegroundWindow(hWnd);    
+                               bool skipMenu=false;
+
+                               allowTrayMenu = false;
+
+                               // check for notifications
+                               if (currNotify & ServMgr::NT_UPGRADE)
+                               {
+                                       if (servMgr->downloadURL[0])
+                                       {
+                                               if ((sys->getTime()-seenNewVersionTime) > (60*60))      // notify every hour
+                                               {
+                                                       if (MessageBox(hWnd,"A newer version of PeerCast is available, press OK to upgrade.","PeerCast",MB_OKCANCEL|MB_APPLMODAL|MB_ICONEXCLAMATION) == IDOK)
+                                                               sys->getURL(servMgr->downloadURL);
+
+                                                       seenNewVersionTime=sys->getTime();
+                                                       skipMenu=true;
+                                               }
+                                       }
+                               }
+
+
+                               if (!skipMenu)
+                               {
+                                       RECT rcWnd;
+                                       HMENU menu;
+                                       UINT flg = 0;
+
+                                       SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWnd, 0);
+                                       GetCursorPos(&point);
+
+                                       if (point.x < rcWnd.left){
+                                               point.x = rcWnd.left;
+                                               flg |= TPM_LEFTALIGN;
+                                       }
+                                       if (point.x > rcWnd.right){
+                                               point.x = rcWnd.right;
+                                               flg |= TPM_RIGHTALIGN;
+                                       }
+                                       if (point.y < rcWnd.top){
+                                               point.y = rcWnd.top;
+                                               flg |= TPM_TOPALIGN;
+                                       }
+                                       if (point.y > rcWnd.bottom){
+                                               point.y = rcWnd.bottom;
+                                               flg |= TPM_BOTTOMALIGN;
+                                       }
+                                       if (flg == 0){
+                                               flg = TPM_RIGHTALIGN;
+                                       }
+
+                                       switch (wParam)
+                                       {
+                                               case 1:
+                                                       menu = GetSubMenu(trayMenu,0);
+                                                       addAllChannelsMenu(GetSubMenu(menu,0));
+                                                       addRelayedChannelsMenu(GetSubMenu(menu,1));
+                                                       break;
+                                               case 2:
+                                                       menu = GetSubMenu(ltrayMenu,0);
+                                                       addAllChannelsMenu(menu);
+                                                       break;
+                                       }
+                                       if (!TrackPopupMenu(menu,flg,point.x,point.y,0,hWnd,NULL))
+                                       {
+                                               LOG_ERROR("Can`t track popup menu: %d",GetLastError());
+                                       }
+                                       PostMessage(hWnd,WM_NULL,0,0); 
+
+                               }
+                               allowTrayMenu = true;
+                       }
+                       break;
+
+               case WM_CREATE:
+                       if (showGUI)
+                               createGUI(hWnd);
+                       break;
+
+               case WM_COMMAND:
+                       wmId    = LOWORD(wParam); 
+                       wmEvent = HIWORD(wParam); 
+
+                       if ((wmId >= INFO_CMD) && (wmId < INFO_CMD+MAX_CHANNELS))
+                       {
+                               int c = wmId - INFO_CMD;
+                               chanInfo = getChannelInfo(c);
+                               chanInfoIsRelayed = false;
+                               if (winDistinctionNT)
+                                       DialogBox(hInst, (LPCTSTR)IDD_CHANINFO, hWnd, (DLGPROC)ChanInfoProc);
+                               else
+                               {
+                                       HWND WKDLG; //JP-Patch
+                                       WKDLG = CreateDialog(hInst, (LPCTSTR)IDD_CHANINFO, hWnd, (DLGPROC)ChanInfoProc); //JP-Patch
+                                       ShowWindow(WKDLG,SW_SHOWNORMAL); //JP-Patch
+                               }
+                               return 0;
+                       }
+                       if ((wmId >= URL_CMD) && (wmId < URL_CMD+MAX_CHANNELS))
+                       {
+                               int c = wmId - URL_CMD;
+                               chanInfo = getChannelInfo(c);
+                               if (chanInfo.url.isValidURL())
+                                       sys->getURL(chanInfo.url);
+                               return 0;
+                       }
+                       if ((wmId >= PLAY_CMD) && (wmId < PLAY_CMD+MAX_CHANNELS))
+                       {
+                               int c = wmId - PLAY_CMD;
+                               chanInfo = getChannelInfo(c);
+                               chanMgr->findAndPlayChannel(chanInfo,false);
+                               return 0;
+                       }
+                       if ((wmId >= RELAY_CMD) && (wmId < RELAY_CMD+MAX_CHANNELS))
+                       {
+                               int c = wmId - RELAY_CMD;
+                               chanInfo = getChannelInfo(c);
+                               chanMgr->findAndPlayChannel(chanInfo,true);
+                               return 0;
+                       }
+
+                       // Parse the menu selections:
+                       switch (wmId)
+                       {
+                               case ID_POPUP_SHOWMESSAGES_PEERCAST:
+                                       flipNotifyPopup(ID_POPUP_SHOWMESSAGES_PEERCAST,ServMgr::NT_PEERCAST);
+                                       break;
+                               case ID_POPUP_SHOWMESSAGES_BROADCASTERS:
+                                       flipNotifyPopup(ID_POPUP_SHOWMESSAGES_BROADCASTERS,ServMgr::NT_BROADCASTERS);
+                                       break;
+                               case ID_POPUP_SHOWMESSAGES_TRACKINFO:
+                                       flipNotifyPopup(ID_POPUP_SHOWMESSAGES_TRACKINFO,ServMgr::NT_TRACKINFO);
+                                       break;
+
+                               case ID_POPUP_ABOUT:
+                               case IDM_ABOUT:
+                                       DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
+                                       break;
+                               case ID_POPUP_SHOWGUI:
+                               case IDM_SETTINGS_GUI:
+                               case ID_POPUP_ADVANCED_SHOWGUI:
+                               {
+                                       createGUI(hWnd);
+                                       break;
+                               }
+                               case ID_POPUP_YELLOWPAGES:
+                                       sys->getURL("http://yp.peercast.org/");
+                                       break;
+                               case ID_POPUP_YELLOWPAGES1:
+                                       sprintf(buf, "http://%s",servMgr->rootHost.cstr());
+                                       sys->getURL(buf);
+                                       break;
+                               case ID_POPUP_YELLOWPAGES2:
+                                       sprintf(buf, "http://%s",servMgr->rootHost2.cstr());
+                                       sys->getURL(buf);
+                                       break;
+
+                               case ID_POPUP_ADVANCED_VIEWLOG:
+                                       showHTML("viewlog.html");
+                                       break;
+                               case ID_POPUP_ADVANCED_SAVESETTINGS:
+                                       servMgr->saveSettings(iniFileName.cstr());
+                                       break;
+                               case ID_POPUP_ADVANCED_INFORMATION:
+                                       showHTML("index.html");
+                                       break;
+                               case ID_FIND_CHANNELS:
+                               case ID_POPUP_ADVANCED_ALLCHANNELS:
+                               case ID_POPUP_UPGRADE:
+                                       sys->callLocalURL("admin?cmd=upgrade",servMgr->serverHost.port);
+                                       break;
+                               case ID_POPUP_ADVANCED_RELAYEDCHANNELS:
+                               case ID_POPUP_FAVORITES_EDIT:
+                                       showHTML("relays.html");
+                                       break;
+                               case ID_POPUP_ADVANCED_BROADCAST:
+                                       showHTML("broadcast.html");
+                                       break;
+                               case ID_POPUP_SETTINGS:
+                                       showHTML("settings.html");
+                                       break;
+                               case ID_POPUP_CONNECTIONS:
+                                       showHTML("connections.html");
+                                       break;
+                               case ID_POPUP_HELP:
+                                       sys->getURL("http://www.peercast.org/help.php");
+                                       break;
+
+                               case ID_POPUP_SAVE_GUI_POS:
+                                       if (servMgr->saveGuiPos){
+                                               servMgr->saveGuiPos = false;
+                                               CheckMenuItem(trayMenu, ID_POPUP_SAVE_GUI_POS, MF_UNCHECKED|MF_BYCOMMAND);
+                                       } else {
+                                               servMgr->saveGuiPos = true;
+                                               CheckMenuItem(trayMenu, ID_POPUP_SAVE_GUI_POS, MF_CHECKED|MF_BYCOMMAND);
+                                       }
+                                       peercastInst->saveSettings();
+                                       break;
+
+                               case ID_POPUP_KEEP_DOWNSTREAMS:
+                                       if (servMgr->keepDownstreams){
+                                               servMgr->keepDownstreams = false;
+                                               CheckMenuItem(trayMenu, ID_POPUP_KEEP_DOWNSTREAMS, MF_UNCHECKED|MF_BYCOMMAND);
+                                       } else {
+                                               servMgr->keepDownstreams = true;
+                                               CheckMenuItem(trayMenu, ID_POPUP_KEEP_DOWNSTREAMS, MF_CHECKED|MF_BYCOMMAND);
+                                       }
+                                       //peercastInst->saveSettings();
+                                       break;
+
+                               case ID_POPUP_EXIT_CONFIRM:
+                               case IDM_EXIT:
+                                  DestroyWindow(hWnd);
+                                  break;
+                               default:
+                                  return DefWindowProc(hWnd, message, wParam, lParam);
+                       }
+                       break;
+               case WM_DESTROY:
+                       PostQuitMessage(0);
+                       break;
+               default:
+                       return DefWindowProc(hWnd, message, wParam, lParam);
+   }
+   return 0;
+}
+// Mesage handler for about box.
+LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       switch (message)
+       {
+               case WM_INITDIALOG:
+                       //SendDlgItemMessage(hDlg,IDC_ABOUTVER,WM_SETTEXT,0,(LONG)PCX_AGENT);
+//                     SendDlgItemMessage(hDlg,IDC_ABOUTVER,WM_SETTEXT,0,(LONG)PCX_AGENTJP);
+#ifdef VERSION_EX
+                       SendDlgItemMessage(hDlg,IDC_ABOUTVER,WM_SETTEXT,0,(LONG)PCX_AGENTEX);
+#else
+                       SendDlgItemMessage(hDlg,IDC_ABOUTVER,WM_SETTEXT,0,(LONG)PCX_AGENTVP);
+#endif
+                       return TRUE;
+
+               case WM_COMMAND:
+                       switch (LOWORD(wParam))
+                       {
+                               case IDOK:
+                               case IDCANCEL:
+                                       EndDialog(hDlg, LOWORD(wParam));
+                                       return TRUE;
+                               case IDC_BUTTON1:
+                                       sys->getURL("http://www.peercast.org");
+                                       EndDialog(hDlg, LOWORD(wParam));
+                                       return TRUE;
+
+                       }
+                       break;
+               case WM_DESTROY:
+                       break;
+       }
+    return FALSE;
+}
+
+// Mesage handler for chaninfo box
+LRESULT CALLBACK ChanInfoProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       switch (message)
+       {
+               case WM_INITDIALOG:
+                       {
+                               char str[1024];
+                               //strcpy(str,chanInfo.track.artist.cstr());
+                               strcpy(str,chanInfo.track.artist); //JP-Patch
+                               strcat(str," - ");
+                               //strcat(str,chanInfo.track.title.cstr());
+                               strcat(str,chanInfo.track.title);
+                               String name,track,comment,desc,genre; //JP-Patch
+                               name = chanInfo.name; //JP-Patch
+                               track = str; //JP-Patch
+                               comment = chanInfo.comment; //JP-Patch
+                               desc = chanInfo.desc; //JP-Patc
+                               genre = chanInfo.genre; //JP-Patch
+                               name.convertTo(String::T_SJIS); //JP-Patc
+                               track.convertTo(String::T_SJIS); //JP-Patch
+                               comment.convertTo(String::T_SJIS); //JP-Patch
+                               desc.convertTo(String::T_SJIS); //JP-Patch
+                               genre.convertTo(String::T_SJIS); //JP-Patch
+                               
+                               //SendDlgItemMessage(hDlg,IDC_EDIT_NAME,WM_SETTEXT,0,(LONG)chanInfo.name.cstr());
+                               SendDlgItemMessage(hDlg,IDC_EDIT_NAME,WM_SETTEXT,0,(LONG)name.cstr()); //JP-Patch
+                               //SendDlgItemMessage(hDlg,IDC_EDIT_PLAYING,WM_SETTEXT,0,(LONG)str);
+                               SendDlgItemMessage(hDlg,IDC_EDIT_PLAYING,WM_SETTEXT,0,(LONG)track.cstr()); //JP-Patch
+                               //SendDlgItemMessage(hDlg,IDC_EDIT_MESSAGE,WM_SETTEXT,0,(LONG)chanInfo.comment.cstr());
+                               SendDlgItemMessage(hDlg,IDC_EDIT_MESSAGE,WM_SETTEXT,0,(LONG)comment.cstr()); //JP-Patch
+                               //SendDlgItemMessage(hDlg,IDC_EDIT_DESC,WM_SETTEXT,0,(LONG)chanInfo.desc.cstr());
+                               SendDlgItemMessage(hDlg,IDC_EDIT_DESC,WM_SETTEXT,0,(LONG)desc.cstr()); //JP-Patch
+                               //SendDlgItemMessage(hDlg,IDC_EDIT_GENRE,WM_SETTEXT,0,(LONG)chanInfo.genre.cstr());
+                               SendDlgItemMessage(hDlg,IDC_EDIT_GENRE,WM_SETTEXT,0,(LONG)genre.cstr()); //JP-Patch
+
+                               sprintf(str,"%d kb/s %s",chanInfo.bitrate,ChanInfo::getTypeStr(chanInfo.contentType));
+                               SendDlgItemMessage(hDlg,IDC_FORMAT,WM_SETTEXT,0,(LONG)str);
+
+
+                               if (!chanInfo.url.isValidURL())
+                                       EnableWindow(GetDlgItem(hDlg,IDC_CONTACT),false);
+
+                               Channel *ch = chanMgr->findChannelByID(chanInfo.id);
+                               if (ch)
+                               {
+                                       SendDlgItemMessage(hDlg,IDC_EDIT_STATUS,WM_SETTEXT,0,(LONG)ch->getStatusStr());
+                                       SendDlgItemMessage(hDlg, IDC_KEEP,BM_SETCHECK, ch->stayConnected, 0);
+                               }else
+                               {
+                                       SendDlgItemMessage(hDlg,IDC_EDIT_STATUS,WM_SETTEXT,0,(LONG)"OK");
+                                       EnableWindow(GetDlgItem(hDlg,IDC_KEEP),false);
+                               }
+
+
+
+                               POINT point;
+                               RECT rect,drect;
+                               HWND hDsk = GetDesktopWindow();
+                               GetWindowRect(hDsk,&drect);
+                               GetWindowRect(hDlg,&rect);
+                               GetCursorPos(&point);
+
+                               POINT pos,size;
+                               size.x = rect.right-rect.left;
+                               size.y = rect.bottom-rect.top;
+
+                               if (point.x-drect.left < size.x)
+                                       pos.x = point.x;
+                               else
+                                       pos.x = point.x-size.x;
+
+                               if (point.y-drect.top < size.y)
+                                       pos.y = point.y;
+                               else
+                                       pos.y = point.y-size.y;
+
+                               SetWindowPos(hDlg,HWND_TOPMOST,pos.x,pos.y,size.x,size.y,0);
+                               chWnd = hDlg;
+                       }
+                       return TRUE;
+
+               case WM_COMMAND:
+                       {
+                               char str[1024],idstr[64];
+                               chanInfo.id.toStr(idstr);
+
+                               switch (LOWORD(wParam))
+                               {
+                                       case IDC_CONTACT:
+                                       {
+                                               sys->getURL(chanInfo.url);
+                                               return TRUE;
+                                       }
+                                       case IDC_DETAILS:
+                                       {
+                                               sprintf(str,"admin?page=chaninfo&id=%s&relay=%d",idstr,chanInfoIsRelayed);
+                                               sys->callLocalURL(str,servMgr->serverHost.port);
+                                               return TRUE;
+                                       }
+                                       case IDC_KEEP:
+                                       {
+                                               Channel *ch = chanMgr->findChannelByID(chanInfo.id);
+                                               if (ch)
+                                                       ch->stayConnected = SendDlgItemMessage(hDlg, IDC_KEEP,BM_GETCHECK, 0, 0) == BST_CHECKED;;
+                                               return TRUE;
+                                       }
+
+
+                                       case IDC_PLAY:
+                                       {
+                                               chanMgr->findAndPlayChannel(chanInfo,false);
+                                               return TRUE;
+                                       }
+
+                               }
+                       }
+                       break;
+
+               case WM_CLOSE:
+                       if (winDistinctionNT)
+                               EndDialog(hDlg, 0);
+                       else
+                               DestroyWindow(hDlg); //JP-Patch
+                       break;
+
+               case WM_ACTIVATE:
+                       if (LOWORD(wParam) == WA_INACTIVE)
+                               if (winDistinctionNT)
+                                       EndDialog(hDlg, 0);
+                               else
+                                       DestroyWindow(hDlg); //JP-Patch
+                       break;
+               case WM_DESTROY:
+                       chWnd = NULL;
+                       break;
+
+
+       }
+    return FALSE;
+}
diff --git a/PeerCast.root/PeerCast/ui/win32/simple/Simple.h b/PeerCast.root/PeerCast/ui/win32/simple/Simple.h
new file mode 100644 (file)
index 0000000..ad59a96
--- /dev/null
@@ -0,0 +1,65 @@
+
+// ------------------------------------------------
+// File : simple.h
+// Date: 4-apr-2002
+// Author: giles
+//             
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#if !defined(AFX_SIMPLE_H__F2E64B1B_62DE_473C_A6B6_E7826D41E0FA__INCLUDED_)
+#define AFX_SIMPLE_H__F2E64B1B_62DE_473C_A6B6_E7826D41E0FA__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include "resource.h"
+
+// ---------------------------------
+class MyPeercastInst : public PeercastInstance
+{
+public:
+       virtual Sys * APICALL createSys();
+};
+// ---------------------------------
+class MyPeercastApp : public PeercastApplication
+{
+public:
+       MyPeercastApp ()
+       {
+               //logFile.openWriteReplace("log.txt");
+       }
+
+       virtual const char * APICALL getPath();
+
+       virtual const char * APICALL getIniFilename();
+       virtual const char *APICALL getClientTypeOS();
+       virtual void    APICALL openLogFile(); //JP-EX
+       virtual void    APICALL getDirectory(); //JP-EX
+       virtual bool    APICALL clearTemp(); //JP-EX
+       virtual void APICALL printLog(LogBuffer::TYPE t, const char *str);
+
+       virtual void    APICALL updateSettings();
+       virtual void    APICALL notifyMessage(ServMgr::NOTIFY_TYPE, const char *);
+
+       virtual void    APICALL channelStart(ChanInfo *);
+       virtual void    APICALL channelStop(ChanInfo *);
+       virtual void    APICALL channelUpdate(ChanInfo *);
+
+       FileStream      logFile;
+
+};
+
+
+#endif // !defined(AFX_SIMPLE_H__F2E64B1B_62DE_473C_A6B6_E7826D41E0FA__INCLUDED_)
diff --git a/PeerCast.root/PeerCast/ui/win32/simple/Simple.rc b/PeerCast.root/PeerCast/ui/win32/simple/Simple.rc
new file mode 100644 (file)
index 0000000..311c8fc
--- /dev/null
@@ -0,0 +1,379 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+// Generated Help ID header file
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "resource.hm"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+#include "resource.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// \83j\83\85\81[\83g\83\89\83\8b (\83V\83X\83e\83\80\95W\8f\80) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUSD)
+#ifdef _WIN32
+LANGUAGE LANG_NEUTRAL, SUBLANG_SYS_DEFAULT
+#pragma code_page(932)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_TRAYMENU MENU 
+BEGIN
+    POPUP "popup"
+    BEGIN
+        MENUITEM "\8fî\95ñ",                        ID_POPUP_ABOUT
+        MENUITEM "\83w\83\8b\83v",                      ID_POPUP_HELP
+        MENUITEM SEPARATOR
+        POPUP "\83|\83b\83v\83A\83b\83v\83\81\83b\83Z\81[\83W"
+        BEGIN
+            MENUITEM "PeerCast",                    ID_POPUP_SHOWMESSAGES_PEERCAST
+
+            MENUITEM "\94z\90M\8eÒ",                      ID_POPUP_SHOWMESSAGES_BROADCASTERS
+
+            MENUITEM "\83g\83\89\83b\83N\8fî\95ñ",                ID_POPUP_SHOWMESSAGES_TRACKINFO
+
+            MENUITEM "\83A\83b\83v\83f\81[\83g\8fî\95ñ",            ID_POPUP_POPUPMESSAGES_UPGRADEALERTS
+            , CHECKED, GRAYED
+        END
+        POPUP "\8d\82\93x"
+        BEGIN
+            MENUITEM "\8fî\95ñ",                        ID_POPUP_ADVANCED_INFORMATION
+
+            MENUITEM "\83\8a\83\8c\81[\83`\83\83\83\93\83l\83\8b",            ID_POPUP_ADVANCED_RELAYEDCHANNELS
+
+            MENUITEM "\94z\90M",                        ID_POPUP_ADVANCED_BROADCAST
+
+            MENUITEM "\83R\83l\83N\83V\83\87\83\93",                ID_POPUP_CONNECTIONS
+            MENUITEM "\83\8d\83O",                        ID_POPUP_ADVANCED_VIEWLOG
+
+            MENUITEM "\90Ý\92è",                        ID_POPUP_SETTINGS
+            MENUITEM "GUI\82ð\8aJ\82­",                   ID_POPUP_ADVANCED_SHOWGUI
+
+        END
+        POPUP "\92Ç\89Á\90Ý\92è"
+        BEGIN
+            MENUITEM "\8fI\97¹\8e\9e\81A\95\\8e¦\88Ê\92u\82ð\95Û\91¶",      ID_POPUP_SAVE_GUI_POS
+            , CHECKED
+            MENUITEM "\8dÄ\90Ú\91±\8e\9e\89º\97¬\88Û\8e\9d",            ID_POPUP_KEEP_DOWNSTREAMS
+            , CHECKED
+        END
+        MENUITEM SEPARATOR
+        POPUP "\8fI\97¹"
+        BEGIN
+            MENUITEM "\82Í\82¢",                        ID_POPUP_EXIT_CONFIRM
+            MENUITEM "\82¢\82¢\82¦",                      ID_POPUP_EXIT_NO
+        END
+    END
+END
+
+IDR_LTRAYMENU MENU 
+BEGIN
+    POPUP "popup"
+    BEGIN
+        MENUITEM SEPARATOR
+        MENUITEM "\83C\83G\83\8d\81[\83y\81[\83W",              ID_POPUP_YELLOWPAGES
+        POPUP "\83C\83G\83\8d\81[\83y\81[\83W"
+        BEGIN
+            MENUITEM "AAA",                         ID_POPUP_YELLOWPAGES1
+            MENUITEM "BBB",                         ID_POPUP_YELLOWPAGES2
+        END
+    END
+END
+
+IDR_GUIMENU MENU
+BEGIN
+    POPUP "popup"
+    BEGIN
+        MENUITEM SEPARATOR
+        MENUITEM "\90§\8cä",                          ID_POPUP_YELLOWPAGES
+        POPUP "\90§\8cä"
+        BEGIN
+            MENUITEM "AAA",                         ID_POPUP_YELLOWPAGES1
+            MENUITEM "BBB",                         ID_POPUP_YELLOWPAGES2
+        END
+    END
+END
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_MAINWINDOW DIALOGEX 0, 0, 298, 341
+STYLE DS_SETFONT | DS_CENTER | WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU | 
+    WS_THICKFRAME
+EXSTYLE WS_EX_APPWINDOW
+CAPTION "PeerCast"
+FONT 9, "MS UI Gothic", 0, 0, 0x1
+BEGIN
+    LISTBOX         IDC_LIST1,3,291,291,43,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | 
+                    WS_TABSTOP
+    CONTROL         "\97L\8cø",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | 
+                    WS_TABSTOP,9,29,60,20,WS_EX_TRANSPARENT
+    EDITTEXT        IDC_EDIT1,127,18,47,12,ES_AUTOHSCROLL
+    RTEXT           "\83|\81[\83g :",IDC_STATIC,107,20,18,8
+    LISTBOX         IDC_LIST2,3,206,291,71,LBS_OWNERDRAWFIXED | 
+                    LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+    LTEXT           "\83\8d\83O",IDC_STATIC_LOG,3,282,13,8
+    LTEXT           "\83R\83l\83N\83V\83\87\83\93",IDC_STATIC_CONNECTION,3,184,40,8
+    GROUPBOX        "",IDC_STATIC,3,4,291,49
+    PUSHBUTTON      "\83N\83\8a\83A",IDC_BUTTON1,35,279,25,11
+    LISTBOX         IDC_LIST3,3,81,291,67,LBS_OWNERDRAWFIXED | 
+                    LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+    PUSHBUTTON      "\90Ø\92f",IDC_BUTTON5,67,65,43,13
+    GROUPBOX        "\83\8a\83\8c\81[",IDC_GROUPBOX_RELAY,3,54,291,96
+    EDITTEXT        IDC_EDIT3,127,34,47,12,ES_PASSWORD | ES_AUTOHSCROLL
+    RTEXT           "\83p\83X\83\8f\81[\83h :",IDC_STATIC,89,36,36,8
+    CONTROL         "\83f\83o\83b\83O",IDC_LOGDEBUG,"Button",BS_AUTOCHECKBOX | 
+                    BS_PUSHLIKE | WS_TABSTOP,127,279,32,11
+    CONTROL         "\83l\83b\83g\83\8f\81[\83N",IDC_LOGNETWORK,"Button",BS_AUTOCHECKBOX | 
+                    BS_PUSHLIKE | WS_TABSTOP,185,279,35,11
+    CONTROL         "\83G\83\89\81[",IDC_LOGERRORS,"Button",BS_AUTOCHECKBOX | 
+                    BS_PUSHLIKE | WS_TABSTOP,159,279,25,11
+    CONTROL         "\92â\8e~",IDC_CHECK9,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | 
+                    WS_TABSTOP,60,279,30,11
+    PUSHBUTTON      "\8dÄ\90¶",IDC_BUTTON8,10,65,22,13
+    CONTROL         "\83`\83\83\83\93\83l\83\8b",IDC_LOGCHANNELS,"Button",BS_AUTOCHECKBOX | 
+                    BS_PUSHLIKE | WS_TABSTOP,221,279,35,11
+    PUSHBUTTON      "\8dÄ\90Ú\91±",IDC_BUTTON3,41,65,24,13
+    EDITTEXT        IDC_EDIT9,33,159,261,14,ES_AUTOHSCROLL
+    CONTROL         "DJ",IDC_CHECK11,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | 
+                    WS_TABSTOP,5,160,23,12
+    RTEXT           "\8dÅ\91å\83\8a\83\8c\81[\90\94 :",IDC_STATIC,203,20,40,8
+    EDITTEXT        IDC_MAXRELAYS,248,18,40,14,ES_AUTOHSCROLL | ES_NUMBER
+    PUSHBUTTON      "\83L\81[\83v",IDC_BUTTON9,112,65,24,13
+    PUSHBUTTON      "\90Ø\92f",IDC_BUTTON6,47,179,43,13
+    LTEXT           "Peercast-VP",IDC_STATIC,21,14,39,8
+END
+
+IDD_CHANINFO DIALOGEX 0, 0, 184, 207
+STYLE DS_SETFONT | DS_SETFOREGROUND | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_TOOLWINDOW
+CAPTION "Channel Information"
+FONT 9, "MS UI Gothic", 400, 0, 0x80
+BEGIN
+    LTEXT           "\96¼\91O:",IDC_STATIC,7,8,24,9
+    EDITTEXT        IDC_EDIT_NAME,7,18,170,21,ES_MULTILINE | ES_READONLY | 
+                    NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE
+    LTEXT           "\93à\97e:",IDC_STATIC,7,79,93,9
+    EDITTEXT        IDC_EDIT_PLAYING,8,90,170,21,ES_MULTILINE | ES_READONLY | 
+                    NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE
+    LTEXT           "DJ \83\81\83b\83Z\81[\83W:",IDC_STATIC,7,117,41,9
+    EDITTEXT        IDC_EDIT_MESSAGE,8,128,170,21,ES_MULTILINE | ES_READONLY | 
+                    NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE
+    PUSHBUTTON      "URL",IDC_CONTACT,7,185,34,15,0,0,HIDC_CONTACT
+    LTEXT           "\8fÚ\8d×:",IDC_STATIC,7,43,67,8
+    EDITTEXT        IDC_EDIT_DESC,8,53,170,21,ES_MULTILINE | ES_READONLY | 
+                    NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE
+    RTEXT           "\8c`\8e®",IDC_FORMAT,69,80,107,8
+    LTEXT           "\83W\83\83\83\93\83\8b:",IDC_STATIC,63,5,22,8
+    EDITTEXT        IDC_EDIT_GENRE,87,3,90,12,ES_AUTOHSCROLL | ES_READONLY | 
+                    NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE
+    CONTROL         "\83L\81[\83v",IDC_KEEP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+                    144,188,33,10
+    LTEXT           "\83X\83e\81[\83^\83X:",IDC_STATIC,7,153,41,9
+    EDITTEXT        IDC_EDIT_STATUS,8,163,82,12,ES_READONLY | NOT WS_BORDER | 
+                    NOT WS_TABSTOP,WS_EX_STATICEDGE
+    PUSHBUTTON      "\8dÄ\90¶",IDC_PLAY,56,185,34,15
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO 
+BEGIN
+    IDD_MAINWINDOW, DIALOG
+    BEGIN
+        LEFTMARGIN, 3
+        RIGHTMARGIN, 294
+        TOPMARGIN, 3
+        BOTTOMMARGIN, 336
+    END
+
+    IDD_CHANINFO, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 177
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 200
+    END
+END
+#endif    // APSTUDIO_INVOKED
+
+#endif    // \83j\83\85\81[\83g\83\89\83\8b (\83V\83X\83e\83\80\95W\8f\80) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// \89p\8cê (\95Ä\8d\91) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDC_SIMPLE MENU 
+BEGIN
+    POPUP "&File"
+    BEGIN
+        MENUITEM "E&xit",                       IDM_EXIT
+    END
+    POPUP "&Help"
+    BEGIN
+        MENUITEM "&About ...",                  IDM_ABOUT
+    END
+    POPUP "Settings"
+    BEGIN
+        MENUITEM "GUI",                         IDM_SETTINGS_GUI
+    END
+END
+
+IDR_VERMENU MENU 
+BEGIN
+    POPUP "popup"
+    BEGIN
+        MENUITEM "Please upgrade PeerCast. Click here to download.", 
+                                                ID_POPUP_UPGRADE
+    END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_ABOUTBOX DIALOG  22, 17, 163, 59
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_CAPTION | 
+    WS_SYSMENU
+CAPTION "About"
+FONT 8, "System"
+BEGIN
+    ICON            IDI_SIMPLE,IDC_MYICON,14,9,20,20
+    LTEXT           "PeerCast",IDC_ABOUTVER,43,9,103,8,SS_NOPREFIX
+    LTEXT           "Copyright (C) 2005",IDC_STATIC,43,22,119,8
+    PUSHBUTTON      "OK",IDOK,134,40,24,12,WS_GROUP
+    PUSHBUTTON      "www.peercast.org",IDC_BUTTON1,42,40,66,12
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO 
+BEGIN
+    IDD_ABOUTBOX, DIALOG
+    BEGIN
+        BOTTOMMARGIN, 58
+    END
+END
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_SIMPLE              ICON                    "Simple.ICO"
+IDI_SMALL2              ICON                    "small1.ico"
+IDI_SMALL               ICON                    "small3.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDC_SIMPLE ACCELERATORS 
+BEGIN
+    "?",            IDM_ABOUT,              ASCII,  ALT
+    "/",            IDM_ABOUT,              ASCII,  ALT
+END
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+2 TEXTINCLUDE 
+BEGIN
+    "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+    "#include ""windows.h""\r\n"
+    "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+    "#include ""resource.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+1 TEXTINCLUDE 
+BEGIN
+    "resource.h\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE 
+BEGIN
+    IDS_APP_TITLE           "PeerCast"
+END
+
+#endif    // \89p\8cê (\95Ä\8d\91) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/PeerCast.root/PeerCast/ui/win32/simple/Simple.vcproj b/PeerCast.root/PeerCast/ui/win32/simple/Simple.vcproj
new file mode 100644 (file)
index 0000000..2241604
--- /dev/null
@@ -0,0 +1,906 @@
+<?xml version="1.0" encoding="shift_jis"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="Simple"
+       ProjectGUID="{7D4833CE-1286-4587-9470-52E098B29C12}"
+       RootNamespace="Simple"
+       SccProjectName="&quot;$/PeerCast.root/PeerCast&quot;, JCAAAAAA"
+       SccLocalPath="..\..\.."
+       SccProvider="MSSCCI:Microsoft Visual SourceSafe"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Private Debug|Win32"
+                       OutputDirectory=".\Simple___Win32_Private_Debug"
+                       IntermediateDirectory=".\Simple___Win32_Private_Debug"
+                       ConfigurationType="1"
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+                       UseOfMFC="0"
+                       ATLMinimizesCRunTimeLibraryUsage="false"
+                       CharacterSet="2"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                               PreprocessorDefinitions="_DEBUG"
+                               MkTypLibCompatible="true"
+                               SuppressStartupBanner="true"
+                               TargetEnvironment="1"
+                               TypeLibraryName=".\Simple___Win32_Private_Debug/Simple.tlb"
+                               HeaderFileName=""
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="0"
+                               AdditionalIncludeDirectories="../../../core,../../../core/common"
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;PRIVATE_BROADCASTER"
+                               MinimalRebuild="true"
+                               BasicRuntimeChecks="3"
+                               RuntimeLibrary="1"
+                               PrecompiledHeaderFile=".\Simple___Win32_Private_Debug/Simple.pch"
+                               AssemblerListingLocation=".\Simple___Win32_Private_Debug/"
+                               ObjectFile=".\Simple___Win32_Private_Debug/"
+                               ProgramDataBaseFileName=".\Simple___Win32_Private_Debug/"
+                               BrowseInformation="1"
+                               WarningLevel="3"
+                               SuppressStartupBanner="true"
+                               DebugInformationFormat="4"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="_DEBUG"
+                               Culture="1033"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="ws2_32.lib odbc32.lib odbccp32.lib"
+                               OutputFile="Debug/PeerCast.exe"
+                               LinkIncremental="1"
+                               SuppressStartupBanner="true"
+                               GenerateDebugInformation="true"
+                               ProgramDatabaseFile=".\Simple___Win32_Private_Debug/PeerCast.pdb"
+                               SubSystem="2"
+                               TargetMachine="1"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                               SuppressStartupBanner="true"
+                               OutputFile=".\Simple___Win32_Private_Debug/Simple.bsc"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                               Description="Copy exe to program files"
+                               CommandLine="copy           debug\peercast.exe           &quot;c:\program files\peercast&quot;"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       OutputDirectory=".\Release"
+                       IntermediateDirectory=".\Release"
+                       ConfigurationType="1"
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+                       UseOfMFC="0"
+                       ATLMinimizesCRunTimeLibraryUsage="false"
+                       CharacterSet="2"
+                       WholeProgramOptimization="0"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                               PreprocessorDefinitions="NDEBUG"
+                               MkTypLibCompatible="true"
+                               SuppressStartupBanner="true"
+                               TargetEnvironment="1"
+                               TypeLibraryName=".\Release/Simple.tlb"
+                               HeaderFileName=""
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="2"
+                               InlineFunctionExpansion="1"
+                               EnableIntrinsicFunctions="true"
+                               FavorSizeOrSpeed="0"
+                               AdditionalIncludeDirectories="../../../core,../../../core/common"
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
+                               StringPooling="true"
+                               RuntimeLibrary="0"
+                               EnableFunctionLevelLinking="true"
+                               PrecompiledHeaderFile=".\Release/Simple.pch"
+                               AssemblerListingLocation=".\Release/"
+                               ObjectFile=".\Release/"
+                               ProgramDataBaseFileName=".\Release/"
+                               BrowseInformation="1"
+                               WarningLevel="3"
+                               SuppressStartupBanner="true"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="NDEBUG"
+                               Culture="1033"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="ws2_32.lib gdiplus.lib comsuppw.lib Wininet.lib corelib.lib"
+                               OutputFile="Release/PeerCast.exe"
+                               LinkIncremental="1"
+                               SuppressStartupBanner="true"
+                               AdditionalLibraryDirectories="&quot;C:\Visual Studio Projects\PeCa-IMAS7651\core\win32\lib\Release&quot;"
+                               ProgramDatabaseFile=".\Release/PeerCast.pdb"
+                               SubSystem="2"
+                               TargetMachine="1"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                               SuppressStartupBanner="true"
+                               OutputFile=".\Release/Simple.bsc"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                               Description="Copy exe to pimp &amp; program files"
+                               CommandLine="copy                   release\peercast.exe                   &quot;c:\program files\peercast&quot;&#x0D;&#x0A;copy                   release\peercast.exe                   ..\pimp\&#x0D;&#x0A;"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Private Release|Win32"
+                       OutputDirectory=".\Simple___Win32_Private_Release"
+                       IntermediateDirectory=".\Simple___Win32_Private_Release"
+                       ConfigurationType="1"
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+                       UseOfMFC="0"
+                       ATLMinimizesCRunTimeLibraryUsage="false"
+                       CharacterSet="2"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                               PreprocessorDefinitions="NDEBUG"
+                               MkTypLibCompatible="true"
+                               SuppressStartupBanner="true"
+                               TargetEnvironment="1"
+                               TypeLibraryName=".\Simple___Win32_Private_Release/Simple.tlb"
+                               HeaderFileName=""
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="2"
+                               InlineFunctionExpansion="1"
+                               AdditionalIncludeDirectories="../../../core,../../../core/common"
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;PRIVATE_BROADCASTER"
+                               StringPooling="true"
+                               RuntimeLibrary="0"
+                               EnableFunctionLevelLinking="true"
+                               PrecompiledHeaderFile=".\Simple___Win32_Private_Release/Simple.pch"
+                               AssemblerListingLocation=".\Simple___Win32_Private_Release/"
+                               ObjectFile=".\Simple___Win32_Private_Release/"
+                               ProgramDataBaseFileName=".\Simple___Win32_Private_Release/"
+                               BrowseInformation="1"
+                               WarningLevel="3"
+                               SuppressStartupBanner="true"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="NDEBUG"
+                               Culture="1033"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="ws2_32.lib odbc32.lib odbccp32.lib"
+                               OutputFile="PrivRelease/PeerCast.exe"
+                               LinkIncremental="1"
+                               SuppressStartupBanner="true"
+                               ProgramDatabaseFile=".\Simple___Win32_Private_Release/PeerCast.pdb"
+                               SubSystem="2"
+                               TargetMachine="1"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                               SuppressStartupBanner="true"
+                               OutputFile=".\Simple___Win32_Private_Release/Simple.bsc"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                               Description="Copy exe to pimp &amp; program files"
+                               CommandLine="copy                   release\peercast.exe                   &quot;c:\program files\peercast&quot;&#x0D;&#x0A;copy                   release\peercast.exe                   ..\pimp\&#x0D;&#x0A;"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Debug|Win32"
+                       OutputDirectory=".\Debug"
+                       IntermediateDirectory=".\Debug"
+                       ConfigurationType="1"
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+                       UseOfMFC="0"
+                       ATLMinimizesCRunTimeLibraryUsage="false"
+                       CharacterSet="2"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                               PreprocessorDefinitions="_DEBUG"
+                               MkTypLibCompatible="true"
+                               SuppressStartupBanner="true"
+                               TargetEnvironment="1"
+                               TypeLibraryName=".\Debug/Simple.tlb"
+                               HeaderFileName=""
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="0"
+                               AdditionalIncludeDirectories="../../../core,../../../core/common"
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
+                               MinimalRebuild="true"
+                               BasicRuntimeChecks="3"
+                               RuntimeLibrary="1"
+                               PrecompiledHeaderFile=".\Debug/Simple.pch"
+                               AssemblerListingLocation=".\Debug/"
+                               ObjectFile=".\Debug/"
+                               ProgramDataBaseFileName=".\Debug/"
+                               BrowseInformation="1"
+                               WarningLevel="3"
+                               SuppressStartupBanner="true"
+                               DebugInformationFormat="4"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="_DEBUG"
+                               Culture="1033"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="ws2_32.lib gdiplus.lib comsuppw.lib Wininet.lib corelib.lib"
+                               OutputFile="Debug/PeerCast.exe"
+                               LinkIncremental="1"
+                               SuppressStartupBanner="true"
+                               AdditionalLibraryDirectories="&quot;C:\Visual Studio Projects\PeCa-IMAS7651\core\win32\lib\Debug&quot;"
+                               GenerateDebugInformation="true"
+                               ProgramDatabaseFile=".\Debug/PeerCast.pdb"
+                               SubSystem="2"
+                               HeapReserveSize="4194304"
+                               TargetMachine="1"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                               SuppressStartupBanner="true"
+                               OutputFile=".\Debug/Simple.bsc"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                               Description="Copy exe to program files"
+                               CommandLine="copy           debug\peercast.exe           &quot;c:\program files\peercast&quot;"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="Source Files"
+                       Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+                       >
+                       <File
+                               RelativePath="chkMemoryLeak.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="gui.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\..\core\common\identify_encoding.c"
+                               >
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="Simple.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="Simple.rc"
+                               >
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCResourceCompilerTool"
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCResourceCompilerTool"
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCResourceCompilerTool"
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCResourceCompilerTool"
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="StdAfx.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                               UsePrecompiledHeader="1"
+                                               PrecompiledHeaderThrough="stdafx.h"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                               UsePrecompiledHeader="1"
+                                               PrecompiledHeaderThrough="stdafx.h"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                               UsePrecompiledHeader="1"
+                                               PrecompiledHeaderThrough="stdafx.h"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                               UsePrecompiledHeader="1"
+                                               PrecompiledHeaderThrough="stdafx.h"
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\..\core\common\utf8.c"
+                               >
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+               </Filter>
+               <Filter
+                       Name="Header Files"
+                       Filter="h;hpp;hxx;hm;inl"
+                       >
+                       <File
+                               RelativePath="chkMemoryLeak.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="gui.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\..\core\common\identify_encoding.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="resource.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="Simple.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="StdAfx.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\..\core\common\utf8.h"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="Resource Files"
+                       Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+                       >
+                       <File
+                               RelativePath="Simple.ico"
+                               >
+                       </File>
+                       <File
+                               RelativePath="small.ico"
+                               >
+                       </File>
+                       <File
+                               RelativePath="small1.ico"
+                               >
+                       </File>
+                       <File
+                               RelativePath="small3.ico"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="Linux"
+                       >
+                       <File
+                               RelativePath="..\..\linux\main.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\linux\makefile"
+                               >
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCustomBuildTool"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCustomBuildTool"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCustomBuildTool"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCustomBuildTool"
+                                       />
+                               </FileConfiguration>
+                       </File>
+               </Filter>
+               <Filter
+                       Name="OSX"
+                       >
+                       <File
+                               RelativePath="..\..\osx\main.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\osx\makefile"
+                               >
+                       </File>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/PeerCast.root/PeerCast/ui/win32/simple/Simple.vcproj.vspscc b/PeerCast.root/PeerCast/ui/win32/simple/Simple.vcproj.vspscc
new file mode 100644 (file)
index 0000000..f30e03c
--- /dev/null
@@ -0,0 +1,10 @@
+""
+{
+"FILE_VERSION" = "9237"
+"ENLISTMENT_CHOICE" = "NEVER"
+"PROJECT_FILE_RELATIVE_PATH" = "relative:ui\\win32\\simple"
+"NUMBER_OF_EXCLUDED_FILES" = "0"
+"ORIGINAL_PROJECT_FILE_PATH" = ""
+"NUMBER_OF_NESTED_PROJECTS" = "0"
+"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
+}
diff --git a/PeerCast.root/PeerCast/ui/win32/simple/StdAfx.cpp b/PeerCast.root/PeerCast/ui/win32/simple/StdAfx.cpp
new file mode 100644 (file)
index 0000000..fe41f64
--- /dev/null
@@ -0,0 +1,9 @@
+// stdafx.cpp : source file that includes just the standard includes
+//     Simple.pch will be the pre-compiled header
+//     stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
+
diff --git a/PeerCast.root/PeerCast/ui/win32/simple/StdAfx.h b/PeerCast.root/PeerCast/ui/win32/simple/StdAfx.h
new file mode 100644 (file)
index 0000000..1e47eff
--- /dev/null
@@ -0,0 +1,32 @@
+// stdafx.h : include file for standard system include files,
+//  or project specific include files that are used frequently, but
+//      are changed infrequently
+//
+
+#if !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_)
+#define AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#define WIN32_LEAN_AND_MEAN            // Exclude rarely-used stuff from Windows headers
+
+
+// Windows Header Files:
+#include <windows.h>
+
+// C RunTime Header Files
+#include <stdlib.h>
+#include <malloc.h>
+#include <memory.h>
+#include <tchar.h>
+
+// Local Header Files
+
+// TODO: reference additional headers your program requires here
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_)
diff --git a/PeerCast.root/PeerCast/ui/win32/simple/chkMemoryLeak.cpp b/PeerCast.root/PeerCast/ui/win32/simple/chkMemoryLeak.cpp
new file mode 100644 (file)
index 0000000..4c8df0d
--- /dev/null
@@ -0,0 +1,21 @@
+#ifdef _DEBUG
+//#include "stdafx.h"
+#include "chkMemoryLeak.h"
+
+#ifdef __AFXWIN_H__            // MFC\82Ì\83E\83B\83\93\83h\83E\82ð\8eg\82¤\8fê\8d\87\82É\8cÀ\92è\82µ\82Ä\82¢\82Ü\82·
+#else
+ #if defined(_DEBUG)
+ #define __chkMemoryLeak_H__
+ void* operator new(size_t size, const char *filename, int linenumber)
+ {
+   return _malloc_dbg(size, _NORMAL_BLOCK, filename, linenumber);
+ }
+ void   operator delete(void * _P, const char *filename, int linenumber)
+ {
+   _free_dbg(_P, _NORMAL_BLOCK);
+   return;
+ }
+
+ #endif
+#endif
+#endif
diff --git a/PeerCast.root/PeerCast/ui/win32/simple/chkMemoryLeak.h b/PeerCast.root/PeerCast/ui/win32/simple/chkMemoryLeak.h
new file mode 100644 (file)
index 0000000..aa47729
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _CHKMEMORYLEAK_H
+#define _CHKMEMORYLEAK_H
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#ifdef _DEBUG
+  #define _CRTDBG_MAP_ALLOC
+
+  #define  SET_CRT_DEBUG_FIELD(a)   _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
+  #define  CLEAR_CRT_DEBUG_FIELD(a) _CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
+
+  void*  operator new(size_t size, const char *filename, int linenumber);
+  void   operator delete(void * _P, const char *filename, int linenumber);
+#else
+  #define  SET_CRT_DEBUG_FIELD(a)   ((void) 0)
+  #define  CLEAR_CRT_DEBUG_FIELD(a) ((void) 0)
+#endif
+
+#include <crtdbg.h>
+
+#include <malloc.h>
+
+#endif
diff --git a/PeerCast.root/PeerCast/ui/win32/simple/gui.cpp b/PeerCast.root/PeerCast/ui/win32/simple/gui.cpp
new file mode 100644 (file)
index 0000000..1ef53b1
--- /dev/null
@@ -0,0 +1,1853 @@
+// ------------------------------------------------
+// File : gui.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             Windows front end GUI, PeerCast core is not dependant on any of this. 
+//             Its very messy at the moment, but then again Windows UI always is.
+//             I really don`t like programming win32 UI.. I want my borland back..
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#define _WIN32_WINNT 0x0500
+
+#include <windows.h>
+#include "stdio.h"
+#include "string.h"
+#include "stdarg.h"
+#include "resource.h"
+#include "socket.h"
+#include "win32/wsys.h"
+#include "servent.h"
+#include "win32/wsocket.h"
+#include "inifile.h"
+#include "gui.h"
+#include "servmgr.h"
+#include "peercast.h"
+#include "simple.h"
+#include "gdiplus.h"
+#include "commctrl.h"
+#include "locale.h"
+#include "stats.h"
+#include "socket.h"
+#include "wininet.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+ThreadInfo guiThread;
+bool shownChannels=false;
+WINDOWPLACEMENT winPlace;
+bool guiFlg = false;
+
+using namespace Gdiplus;
+
+#include <comdef.h>
+
+void APICALL MyPeercastApp ::printLog(LogBuffer::TYPE t, const char *str)
+{
+/*     ADDLOG(str,logID,true,NULL,t);
+       if (logFile.isOpen())
+       {
+               logFile.writeLine(str);
+               logFile.flush();
+       }*/
+}
+
+void APICALL MyPeercastApp::updateSettings()
+{
+//     setControls(true);
+}
+
+Gdiplus::Bitmap bmpBack(800,600,PixelFormat24bppRGB);
+UINT backWidth;
+UINT backHeight;
+
+Gdiplus::Image *backImage;
+Gdiplus::Bitmap *backBmp;
+Gdiplus::Graphics *backGra;
+
+Gdiplus::Image *img_idle;
+Gdiplus::Image *img_connect;
+Gdiplus::Image *img_conn_ok;
+Gdiplus::Image *img_conn_full;
+Gdiplus::Image *img_conn_over;
+Gdiplus::Image *img_conn_ok_skip;
+Gdiplus::Image *img_conn_full_skip;
+Gdiplus::Image *img_conn_over_skip;
+Gdiplus::Image *img_error;
+Gdiplus::Image *img_broad_ok;
+Gdiplus::Image *img_broad_full;
+
+UINT winWidth=0;
+UINT winHeight=0;
+
+static HWND hTree;
+extern HINSTANCE hInst;
+extern HWND guiWnd;
+extern Stats stats;
+
+WLock sd_lock;
+WLock ChannelDataLock;
+WLock MakeBackLock;
+ChannelData *channelDataTop = NULL;
+
+extern bool gbGetFile;
+extern bool gbStart;
+extern time_t gtGetFile;
+extern time_t gtStartTime;
+ThreadInfo gtiStart;
+ThreadInfo gtiGetFile;
+static char *data1URL = "http://www.idolmaster.jp/download/images/wallpaper/imas360p_800.jpg";
+static char *data2URL = "http://www.xbox.com/NR/rdonlyres/CAB05E2F-3051-409B-A4C8-830167C1C138/0/wpr0701idolmasterw120001.jpg";
+HWND ghStart;
+
+bool gbDispTop = false;
+bool gbAllOpen = false;
+
+THREAD_PROC FestivalStart(ThreadInfo *thread);
+
+THREAD_PROC GetHostName(ThreadInfo *thread){
+       IdData *id = (IdData*)(thread->data);
+
+       HOSTENT *he;
+       unsigned int ip;
+       bool flg = TRUE;
+
+       ChannelDataLock.on();
+       ip = htonl(id->getIpAddr());
+
+       for (int i=0; i<5 && flg; i++){
+               he = gethostbyaddr((char *)&ip,sizeof(ip),AF_INET);
+
+               ChannelData* cd = channelDataTop;
+               if (he)
+               {
+                       while(cd){
+                               if (cd->setName(id->getServentId(), he->h_name)){
+                                       flg = FALSE;
+                                       break;
+                               }
+                               cd = cd->getNextData();
+                       }
+               }
+//             ::delete id;
+               ChannelDataLock.off();
+               sys->sleep(1000);
+       }
+
+
+       return 0;
+}
+
+bool DownloadFile(LPCTSTR URL, LPCTSTR local){
+       char header[] = "Accept: */*\r\n\r\n";
+       char buf[4096];
+
+       FileStream f;
+       HINTERNET hInternet;
+       HINTERNET hConnect;
+
+       try{
+               f.openWriteReplace(local);
+       }catch(StreamException &e){
+               return false;
+       }
+
+       hInternet = ::InternetOpen(NULL, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
+       if (hInternet == NULL){
+               return false;
+       }
+
+       hConnect = ::InternetOpenUrl(hInternet, URL, header, strlen(header), INTERNET_FLAG_DONT_CACHE, 0);
+       if (hConnect == NULL){
+               ::InternetCloseHandle(hInternet);
+               return false;
+       }
+
+       while(1){
+               sys->sleep(0);
+               DWORD dwReadSize;
+               BOOL ret = ::InternetReadFile(hConnect, buf, 4096, &dwReadSize);
+               if (ret){
+                       if (dwReadSize == 0){
+                               break;
+                       }
+                       try{
+                               f.write(buf, dwReadSize);
+                               continue;
+                       } catch(StreamException e){
+                       }
+                       f.close();
+                       ::InternetCloseHandle(hConnect);
+                       ::InternetCloseHandle(hInternet);
+                       return false;
+               }
+       }
+
+       f.flush();
+       f.close();
+       ::InternetCloseHandle(hConnect);
+       ::InternetCloseHandle(hInternet);
+
+       return true;
+}
+
+THREAD_PROC GetInternetFile(ThreadInfo *thread){
+
+       DownloadFile(data1URL, "data1.jpg");
+       DownloadFile(data2URL, "data2.jpg");
+       return 0;
+}
+
+extern TCHAR szWindowClass3[];                                                         // The title bar text
+
+
+int drawSpeed(Graphics *gra, int posX, int posY){
+
+       // \91¬\93x\95\\8e¦\95\94\82Ì\94w\8ci\82ð\94\92\82­\82·\82é
+       SolidBrush b(Color(180,255,255,255));
+       backGra->FillRectangle(&b, posX, posY, 200, 14);
+       // \83t\83H\83\93\83g\90Ý\92è
+       Font font(L"\82l\82\82o\83S\83V\83b\83N",10);
+       // \95\8e\9a\90F
+       SolidBrush strBrush(Color::Black);
+       // \95\8e\9a\97ñ\8dì\90¬
+       char tmp[256];
+       sprintf(tmp, "R:%.1fkbps S:%.1fkbps", 
+               BYTES_TO_KBPS(stats.getPerSecond(Stats::BYTESIN)-stats.getPerSecond(Stats::LOCALBYTESIN)),
+               BYTES_TO_KBPS(stats.getPerSecond(Stats::BYTESOUT)-stats.getPerSecond(Stats::LOCALBYTESOUT)));
+       _bstr_t bstr(tmp);
+       // \95\8e\9a\95\\8e¦\94Í\88Í\8ew\92è
+       StringFormat format;
+       format.SetAlignment(StringAlignmentCenter);
+       RectF r((REAL)posX, (REAL)posY, (REAL)200, (REAL)14);
+       // \95\8e\9a\95`\89æ
+       gra->DrawString(bstr, -1, &font, r, &format, &strBrush);
+
+
+
+       return posY + 15;
+}
+
+void MakeBack(HWND hwnd, UINT x, UINT y){
+       MakeBackLock.on();
+
+       winWidth = x;
+       winHeight = y;
+
+       if (backGra){
+               ::delete backBmp;
+               ::delete backGra;
+       }
+
+       backBmp = ::new Bitmap(x,y);
+       backGra = ::new Graphics(backBmp);
+
+       // \91S\82Ä\94\92\82Å\93h\82è\82Â\82Ô\82µ
+       SolidBrush b(Color(255,255,255,255));
+       backGra->FillRectangle(&b, 0, 0, x, y);
+
+       backWidth = backImage->GetWidth();
+       backHeight = backImage->GetHeight();
+
+       // \94w\8ci\89æ\91\9c\82ð\95`\89æ
+       for (UINT xx = 0; xx < x/backWidth + 1; xx++){
+               for (UINT yy = 0; yy < y/backHeight + 1; yy++){
+                       UINT width,height;
+                       if (backWidth*(xx+1) > x){
+                               width = x % backWidth;
+                       } else {
+                               width = backWidth;
+                       }
+                       if (backHeight*(yy+1) > y){
+                               height = y % backHeight;
+                       } else {
+                               height = backHeight;
+                       }
+                       Rect r((INT)backWidth*xx, (INT)backHeight*yy, width, height);
+                       backGra->DrawImage(backImage, r, 0, 0, (INT)width, (INT)height, UnitPixel);
+               }
+       }
+
+       INT posX = 20;
+       INT posY = 20;
+
+       // \91¬\93x\95`\89æ
+       drawSpeed(backGra, winWidth-205, 5);
+
+       // \83`\83\83\83\93\83l\83\8b\8fî\95ñ\82ð\95`\89æ
+       ChannelDataLock.on();
+       ChannelData *cd = channelDataTop;
+       while(cd){
+               posY = cd->drawChannel(backGra, 20, posY);
+               cd = cd->getNextData();
+       }
+       ChannelDataLock.off();
+       MakeBackLock.off();
+}
+
+void MakeBack(HWND hwnd){
+       MakeBack(hwnd, winWidth, winHeight);
+       ::InvalidateRect(guiWnd, NULL, FALSE);
+}
+
+void ChannelData::setData(Channel *c){
+       String sjis;
+       sjis = c->getName();
+       sjis.convertTo(String::T_SJIS);
+
+       strncpy(name, sjis, 256);
+       name[256] = '\0';
+       channel_id = c->channel_id;
+       bitRate = c->info.bitrate;
+       lastPlayStart = c->info.lastPlayStart;
+       status = c->status;
+       totalListeners = c->totalListeners();
+       totalRelays = c->totalRelays();
+       localListeners = c->localListeners();
+       localRelays = c->localRelays();
+       stayConnected = c->stayConnected;
+       chDisp = c->chDisp;
+       bTracker = c->sourceHost.tracker;
+       lastSkipTime = c->lastSkipTime;
+       skipCount = c->skipCount;
+}
+
+int gW = 0;
+int gWS = 0;
+
+int ChannelData::drawChannel(Graphics *g, int x, int y){
+       REAL xx = x * 1.0f;
+       REAL yy = y * 1.0f;
+       ServentData* sd;
+
+       // \88Ê\92u\82ð\95Û\91
+       posX = x;
+       posY = y;
+
+       int w,h;
+
+       if (getWidth() == 0){
+               if (gW){
+                       w = gW;
+               } else {
+                       w = 400;
+               }
+       } else {
+               w = getWidth();
+               gW = w;
+       }
+
+       // \83`\83\83\83\93\83l\83\8b\95\\8e¦\95\94\82Ì\94w\8ci\82ð\93h\82é
+       if (isSelected()){
+               // \91I\91ð\92\86
+               SolidBrush b(Color(160,49,106,197));
+               g->FillRectangle(&b, x, y, w, 14);
+       } else {
+               // \94ñ\91I\91ð
+               SolidBrush b(Color(160,255,255,255));
+               g->FillRectangle(&b, x, y, w, 14);
+       }
+
+       // \83X\83e\81[\83^\83X\95\\8e¦
+       Gdiplus::Image *img = NULL;
+       unsigned int nowTime = sys->getTime();
+       switch(this->getStatus()){
+               case Channel::S_IDLE:
+                       img = img_idle;
+                       break;
+               case Channel::S_SEARCHING:
+               case Channel::S_CONNECTING:
+                       img = img_connect;
+                       break;
+               case Channel::S_RECEIVING:
+                       if ((skipCount > 2) && (lastSkipTime + 120 > nowTime)){
+                               if (chDisp.relay){
+                                       img = img_conn_ok_skip;
+                               } else {
+                                       if (chDisp.numRelays){
+                                               img = img_conn_full_skip;
+                                       } else {
+                                               img = img_conn_over_skip;
+                                       }
+                               }
+                       } else {
+                               if (chDisp.relay){
+                                       img = img_conn_ok;
+                               } else {
+                                       if (chDisp.numRelays){
+                                               img = img_conn_full;
+                                       } else {
+                                               img = img_conn_over;
+                                       }
+                               }
+                       }
+                       break;
+               case Channel::S_BROADCASTING:
+                       img = img_broad_ok;
+                       break;
+               case Channel::S_ERROR:
+                       img = img_error;
+                       break;
+               default:
+                       img = img_idle;
+                       break;
+       }
+       // \95`\89æ\8aî\93_
+       PointF origin(xx, yy);
+       // \83X\83e\81[\83^\83X\95\\8e¦\88Ê\92u
+       Rect img_rect((INT)origin.X, (INT)origin.Y + 1, img ? img->GetWidth() : 12, 12);
+       // \83X\83e\81[\83^\83X\95`\89æ
+       ImageAttributes att;
+//     att.SetColorKey(Color::White, Color::White, ColorAdjustTypeBitmap);
+       g->DrawImage(img, img_rect, 0, 0, img_rect.Width, 12, UnitPixel, &att);
+       // \8e\9f\82Ì\8aî\93_
+       origin.X += img_rect.Width;
+
+       // \83t\83H\83\93\83g\90Ý\92è
+       Gdiplus::Font font(L"\82l\82\82o\83S\83V\83b\83N",10);
+       // \95\8e\9a\90F
+       SolidBrush *strBrush;
+       if (servMgr->getFirewall() == ServMgr::FW_ON){
+               strBrush = ::new SolidBrush(Color::Red);
+       } else if (isTracker() && (getStatus() == Channel::S_RECEIVING)){
+               strBrush = ::new SolidBrush(Color::Green);
+       } else {
+               if (isSelected()){
+                       // \91I\91ð\92\86
+                       strBrush = ::new SolidBrush(Color::White);
+               } else {
+                       // \94ñ\91I\91ð
+                       strBrush = ::new SolidBrush(Color::Black);
+               }
+       }
+       // \83`\83\83\83\93\83l\83\8b\96¼\95\\8e¦
+       g->SetTextRenderingHint(TextRenderingHintAntiAlias);
+       _bstr_t bstr1(getName());
+       // \95\8e\9a\95`\89æ\94Í\88Í\8ew\92è
+       RectF r1(origin.X, origin.Y, 120.0f, 13.0f);
+       StringFormat format;
+       format.SetAlignment(StringAlignmentNear);
+       g->DrawString(bstr1, -1, &font, r1, &format, strBrush);
+       // \8e\9f\82Ì\8aî\93_
+       origin.X += r1.Width;
+
+       // \83\8a\83X\83i\81[\90\94/\83\8a\83\8c\81[\90\94\95\\8e¦
+       char tmp[256];
+       sprintf(tmp, "%d/%d - [%d/%d]", getTotalListeners(), getTotalRelays(), getLocalListeners(), getLocalRelays());
+       _bstr_t bstr2(tmp);
+       // \95\8e\9a\95\\8e¦\94Í\88Í\8ew\92è
+       RectF r2(origin.X, origin.Y, 100.0f, 13.0f);
+       format.SetAlignment(StringAlignmentCenter);
+       g->DrawString(bstr2, -1, &font, r2, &format, strBrush);
+       // \8e\9f\82Ì\8aî\93_
+       origin.X += r2.Width;
+
+       // bps\95\\8e¦
+       Font *f;
+       if (isStayConnected()){
+               f = ::new Font(L"Arial", 9.0f, FontStyleItalic|FontStyleBold, UnitPoint);
+       } else {
+               f = ::new Font(L"Arial", 9.0f);
+       }
+       sprintf(tmp, "%dkbps", getBitRate());
+       _bstr_t bstr3(tmp);
+       format.SetAlignment(StringAlignmentFar);
+       // \95\8e\9a\95\\8e¦\94Í\88Í\8ew\92è
+       RectF r3(origin.X, origin.Y, 80.0f, 13.0f);
+       g->DrawString(bstr3, -1, f, r3, &format, strBrush);
+       // \83t\83H\83\93\83g\8aJ\95ú
+       ::delete f;
+
+       // \8e\9f\82Ì\8aî\93_
+       origin.X += r3.Width;
+
+       // \83u\83\89\83V\8dí\8f\9c
+       ::delete strBrush;
+
+       
+       // Servent\95\\8e¦
+       if (!openFlg){
+               int count = getServentCount();
+               // Servent\95\\8e¦\95\94\82Ì\94w\8ci\82ð\94\92\82É\82·\82é
+               SolidBrush b(Color(160,255,255,255));
+               g->FillRectangle(&b, (INT)origin.X, (INT)origin.Y, 14*count, 14);
+
+               sd = serventDataTop;
+               int index = 0;
+               while(sd){
+                       SolidBrush *serventBrush;
+                       if (sd->getInfoFlg()){
+                               ChanHit *hit = sd->getChanHit();
+                               if (hit->firewalled){
+                                       SolidBrush bb(Color(180,255,0,0));
+                                       g->FillRectangle(&bb, (INT)origin.X + 14*index, (INT)origin.Y, 14, 14);
+                               }
+                               if (hit->relay){
+                                       // \83\8a\83\8c\81[\82n\82j
+                                       serventBrush = ::new SolidBrush(Color::Green);
+                               } else {
+                                       // \83\8a\83\8c\81[\95s\89Â
+                                       if (hit->numRelays){
+                                               // \83\8a\83\8c\81[\88ê\94t
+                                               serventBrush = ::new SolidBrush(Color::Blue);
+                                       } else {
+                                               // \83\8a\83\8c\81[\82È\82µ
+                                               serventBrush = ::new SolidBrush(Color::Purple);
+                                       }
+                               }
+                       } else {
+                               // \8fî\95ñ\82È\82µ
+                               serventBrush = ::new SolidBrush(Color::Black);
+                       }
+                       // \8el\8ap\95`\89æ
+                       backGra->FillRectangle(serventBrush, (INT)origin.X + index*14 + 1, (INT)origin.Y + 1, 12, 12);
+
+                       ::delete serventBrush;
+                       sd = sd->getNextData();
+                       index++;
+               }
+       }
+
+       // \8e\9f\82Ì\8aî\93_
+       origin.Y += 15;
+
+       // \83T\83C\83Y\82ð\95Û\91
+       setWidth((int)origin.X - posX);
+       setHeight((int)origin.Y - posY);
+
+       // ServentData\95\\8e¦
+       sd = serventDataTop;
+       while(sd){
+               if (openFlg || sd->getSelected()){
+                       sd->drawServent(g, (INT)x+12, (INT)origin.Y);
+                       // \8e\9f\82Ì\8aî\93_
+                       origin.Y += 15;
+               }
+               sd = sd->getNextData();
+       }
+       
+
+       return (int)(origin.Y);
+}
+
+bool ChannelData::checkDown(int x,int y){
+       // \94Í\88Í\93à\83`\83F\83b\83N
+       if (    
+                       (x > posX)
+               &&      (x < posX + getWidth())
+               &&      (y > posY)
+               &&      (y < posY + getHeight())
+       ){
+               return TRUE;
+       }
+       return FALSE;
+}
+
+ServentData *ChannelData::findServentData(int servent_id){
+       ServentData *sv = serventDataTop;
+       while(sv){
+               if (sv->getServentId() == servent_id){
+                       return sv;
+               }
+               sv = sv->getNextData();
+       }
+       return NULL;
+}
+
+void ChannelData::addServentData(ServentData *sd){
+       sd->setNextData(serventDataTop);
+       serventDataTop = sd;
+}
+
+void ChannelData::deleteDisableServents(){
+       ServentData *sd = serventDataTop;
+       ServentData *prev = NULL;
+
+       while(sd){
+               if (!(sd->getEnableFlg())){
+                       ServentData *next = sd->getNextData();
+                       if (prev){
+                               prev->setNextData(next);
+                       } else {
+                               serventDataTop = next;
+                       }
+                       ::delete sd;
+                       sd = next;
+               } else {
+                       prev = sd;
+                       sd = sd->getNextData();
+               }
+       }
+}
+
+int ChannelData::getServentCount(){
+       int ret = 0;
+
+       ServentData *sd = serventDataTop;
+       while(sd){
+               ret++;
+               sd = sd->getNextData();
+       }
+       return ret;
+}
+
+bool ChannelData::setName(int servent_id, String name){
+       ServentData *sd = serventDataTop;
+       while(sd){
+               if (sd->getServentId() == servent_id){
+                       sd->setName(name);
+                       return TRUE;
+               }
+               sd = sd->getNextData();
+       }
+       return FALSE;
+}
+
+void ServentData::setData(Servent *s, ChanHit *hit, unsigned int listeners, unsigned int relays, bool f){
+       servent_id = s->servent_id;
+       type = s->type;
+       status = s->status;
+       lastSkipTime = s->lastSkipTime;
+       host = s->getHost();
+
+       chanHit.numRelays = hit->numRelays;
+       chanHit.relay = hit->relay;
+       chanHit.firewalled = hit->firewalled;
+       chanHit.version = hit->version;
+       chanHit.version_vp = hit->version_vp;
+       chanHit.version_ex_number = hit->version_ex_number;
+       chanHit.version_ex_prefix[0] = hit->version_ex_prefix[0];
+       chanHit.version_ex_prefix[1] = hit->version_ex_prefix[1];
+
+       totalListeners = listeners;
+       totalRelays = relays;
+
+       infoFlg = f;
+}
+
+int ServentData::drawServent(Gdiplus::Graphics *g, int x, int y){
+       REAL xx = x * 1.0f;
+       REAL yy = y * 1.0f;
+       int w,h;
+
+       // \88Ê\92u\82ð\95Û\91
+       posX = x;
+       posY = y;
+
+       if (getWidth() == 0){
+               if (gWS){
+                       w = gWS;
+               } else {
+                       w = 400;
+               }
+       } else {
+               w = getWidth();
+               gWS = w;
+       }
+
+       // \95`\89æ\8aî\93_
+       PointF origin(xx, yy);
+
+       // \83t\83H\83\93\83g\90Ý\92è
+       Font font(L"\82l\82\82o\83S\83V\83b\83N",9);
+       // \95\8e\9a\90F
+       SolidBrush *strBrush;
+       if (chanHit.firewalled){
+               strBrush = ::new SolidBrush(Color::Red);
+       } else {
+               if (getSelected()){
+                       // \91I\91ð\92\86
+                       strBrush = ::new SolidBrush(Color::White);
+               } else {
+                       // \94ñ\91I\91ð
+                       strBrush = ::new SolidBrush(Color::Black);
+               }
+       }
+       // ServantData\95\\8e¦
+       g->SetTextRenderingHint(TextRenderingHintAntiAlias);
+       // \95\8e\9a\97ñ\8dì\90¬
+       char tmp[256];
+       char host1[256];
+       host.toStr(host1);
+
+       if (infoFlg){
+               if (chanHit.version_ex_number){
+                       // \8ag\92£\83o\81[\83W\83\87\83\93
+                       sprintf(tmp, "%c%c%04d - %d/%d - %s(%s)", 
+                               chanHit.version_ex_prefix[0],
+                               chanHit.version_ex_prefix[1],
+                               chanHit.version_ex_number,
+                               totalListeners,
+                               totalRelays,
+                               host1,
+                               hostname.cstr()
+                               );
+               } else if (chanHit.version_vp){
+                       sprintf(tmp, "VP%04d - %d/%d - %s(%s)", 
+                               chanHit.version_vp,
+                               totalListeners,
+                               totalRelays,
+                               host1,
+                               hostname.cstr()
+                               );
+               } else {
+                       sprintf(tmp, "(-----) - %d/%d - %s(%s)",
+                               totalListeners,
+                               totalRelays,
+                               host1,
+                               hostname.cstr()
+                               );
+               }
+       } else {
+                       sprintf(tmp, "(-----) - %d/%d - %s(%s)",
+                               totalListeners,
+                               totalRelays,
+                               host1,
+                               hostname.cstr()
+                               );
+       }
+       _bstr_t bstr1(tmp);
+
+       // \83X\83e\81[\83^\83X\95\\8e¦
+       Gdiplus::Image *img = NULL;
+       unsigned int nowTime = sys->getTime();
+       switch(getStatus()){
+               case Servent::S_CONNECTING:
+                       img = img_connect;
+                       break;
+               case Servent::S_CONNECTED:
+                       if (lastSkipTime + 120 > nowTime){
+                               if (chanHit.relay){
+                                       img = img_conn_ok_skip;
+                               } else {
+                                       if (chanHit.numRelays){
+                                               img = img_conn_full_skip;
+                                       } else {
+                                               img = img_conn_over_skip;
+                                       }
+                               }
+                       } else {
+                               if (chanHit.relay){
+                                       img = img_conn_ok;
+                               } else {
+                                       if (chanHit.numRelays){
+                                               img = img_conn_full;
+                                       } else {
+                                               img = img_conn_over;
+                                       }
+                               }
+                       }
+                       break;
+               default:
+                       break;
+       }
+
+       // \95\8e\9a\95`\89æ\94Í\88Í\8ew\92è
+       RectF r1(origin.X + img->GetWidth() + 2, origin.Y, 800.0f, 13.0f);
+       RectF r2;
+       StringFormat format;
+       format.SetAlignment(StringAlignmentNear);
+       g->MeasureString(bstr1, -1, &font, r1, &format, &r2);
+
+       w = (INT)r2.Width + img->GetWidth() + 2;
+       // ServentData\95\\8e¦\95\94\82Ì\94w\8ci\82ð\93h\82é
+       if (getSelected()){
+               // \91I\91ð\92\86
+               SolidBrush b(Color(160,49,106,197));
+               g->FillRectangle(&b, x, y, w, 13);
+       } else {
+               // \94ñ\91I\91ð
+               SolidBrush b(Color(160,200,200,200));
+               g->FillRectangle(&b, x, y, w, 13);
+       }
+
+       // \83X\83e\81[\83^\83X\95\\8e¦\88Ê\92u
+       Rect img_rect((INT)origin.X, (INT)origin.Y+1, img ? img->GetWidth() : 12, 12);
+       // \83X\83e\81[\83^\83X\95`\89æ
+       ImageAttributes att;
+//     att.SetColorKey(Color::White, Color::White, ColorAdjustTypeBitmap);
+       g->DrawImage(img, img_rect, 0, 0, img_rect.Width, 12, UnitPixel, &att);
+       // \8e\9f\82Ì\8aî\93_
+       origin.X += 12;
+
+       g->DrawString(bstr1, -1, &font, r2, &format, strBrush);
+       // \8e\9f\82Ì\8aî\93_
+       origin.X += r2.Width;
+       origin.Y += 13;
+
+       setWidth((int)origin.X-posX);
+       setHeight((int)origin.Y - posY);
+
+       ::delete strBrush;
+       return 0;
+}
+
+bool ServentData::checkDown(int x, int y){
+       if (    
+                       (x > posX)
+               &&      (x < posX + getWidth())
+               &&      (y > posY)
+               &&      (y < posY + getHeight())
+       ){
+               return TRUE;
+       }
+       return FALSE;
+}
+
+
+THREAD_PROC GUIDataUpdate(ThreadInfo *thread){
+       int i;
+
+       // set GUI thread status to running
+       thread->finish = false;
+
+       while(thread->active){
+               // \83`\83\83\83\93\83l\83\8b\83f\81[\83^\83\8d\83b\83N
+               ChannelDataLock.on();
+               // \83`\83\83\83\93\83l\83\8b\83f\81[\83^\82Ì\8dX\90V\83t\83\89\83O\82ð\91S\82ÄFALSE\82É\82·\82é
+               ChannelData *cd = channelDataTop;
+               while(cd){
+                       // Servent\82Ì\8dX\90V\83t\83\89\83O\82ðFALSE\82É\82·\82é
+                       ServentData *sv = cd->getServentDataTop();
+                       while(sv){
+                               sv->setEnableFlg(FALSE);
+                               sv = sv->getNextData();
+                       }
+                       cd->setEnableFlg(FALSE);
+                       cd = cd->getNextData();
+               }
+
+               Channel *c = chanMgr->channel;
+               // \8c»\8dÝ\91\8dÝ\82·\82é\83`\83\83\83\93\83l\83\8b\95ª\83\8b\81[\83v
+               while(c){
+                       // \8aù\82É\83`\83\83\83\93\83l\83\8b\83f\81[\83^\82ð\8e\9d\82Á\82Ä\82¢\82é\82©
+                       cd = channelDataTop;
+                       // \94­\8c©\83t\83\89\83OFALSE
+                       bool bFoundFlg = FALSE;
+                       while(cd){
+                               if (cd->getChannelId() == c->channel_id){
+                                       //\8aù\82É\83`\83\83\83\93\83l\83\8b\83f\81[\83^\82ª\82 \82é\82Ì\82Å\81A\82»\82Ì\82Ü\82Ü\8dX\90V
+                                       cd->setData(c);
+                                       // \8dX\90V\83t\83\89\83OTRUE
+                                       cd->setEnableFlg(TRUE);
+                                       // \94­\8c©\83t\83\89\83OTRUE
+                                       bFoundFlg = TRUE;
+                                       // \83\8b\81[\83v\97£\92E
+                                       break;
+                               }
+                               // \8c©\82Â\82©\82ç\82È\82©\82Á\82½\8fê\8d\87\81A\8e\9f\82Ì\83f\81[\83^\82ð\83`\83F\83b\83N
+                               cd = cd->getNextData();
+                       }
+
+                       // \90V\82µ\82¢\83`\83\83\83\93\83l\83\8b\82Ì\8fê\8d\87\81A\90V\8bK\83f\81[\83^\8dì\90¬
+                       if (!bFoundFlg){
+                               // \90V\8bK\83f\81[\83^\8dì\90¬
+                               cd = ::new ChannelData();
+                               // \83f\81[\83^\8dX\90V
+                               cd->setData(c);
+                               // \8dX\90V\83t\83\89\83OTRUE
+                               cd->setEnableFlg(TRUE);
+
+                               // \90V\8bK\83f\81[\83^\82ð\83\8a\83X\83g\82Ì\90æ\93ª\82É\93ü\82ê\82é
+                               cd->setNextData(channelDataTop);
+                               channelDataTop = cd;
+                       }
+                       // \8e\9f\82Ì\83`\83\83\83\93\83l\83\8b\82ð\8eæ\93¾
+                       c = c->next;
+               }
+
+               // \83`\83\83\83\93\83l\83\8b\82ª\82È\82­\82È\82Á\82Ä\82¢\82é\8fê\8d\87\82Ì\8f\88\97\9d
+               cd = channelDataTop;
+               ChannelData *prev = NULL; 
+               while(cd){
+                       // \83f\81[\83^\82ð\8dX\90V\82µ\82È\82©\82Á\82½\82©
+                       if (cd->getEnableFlg() == FALSE){
+                               // \83`\83\83\83\93\83l\83\8b\82ª\82È\82­\82È\82Á\82Ä\82¢\82é\82Ì\82Å\8dí\8f\9c
+                               ChannelData *next;
+                               next = cd->getNextData();
+                               if (!prev){
+                                       // \90æ\93ª\82Ì\83f\81[\83^\82ð\8dí\8f\9c
+                                       channelDataTop = next;
+                               } else {
+                                       // \93r\92\86\82Ì\83f\81[\83^\82ð\8dí\8f\9c
+                                       prev->setNextData(next);
+                               }
+                               // \8e\9f\82Ì\83f\81[\83^\82Ö
+                               cd = next;
+                       } else {
+                               // \83f\81[\83^\8dX\90V\8dÏ\81F\8e\9f\82Ì\83f\81[\83^\82Ö
+                               prev = cd;
+                               cd = cd->getNextData();
+                       }
+               }
+
+               Servent *s = servMgr->servents;
+               while(s){
+                       // \8f\89\8aú\89»
+                       ChanHitList *chl;
+                       bool infoFlg = false;
+                       bool relay = true;
+                       bool firewalled = false;
+                       unsigned int numRelays = 0;
+                       int vp_ver = 0;
+                       char ver_ex_prefix[2] = {' ',' '};
+                       int ver_ex_number = 0;
+                       // \92¼\89º\83z\83X\83g\8fî\95ñ\83`\83F\83b\83N
+                       unsigned int totalRelays = 0;
+                       unsigned int totalListeners = 0;
+
+                       ChanHit hitData;
+                       // \8eó\90M\92\86\82©
+                       if ((s->type == Servent::T_RELAY) && (s->status == Servent::S_CONNECTED)){
+                               // \83z\83X\83g\8fî\95ñ\83\8d\83b\83N
+                               chanMgr->hitlistlock.on();
+                               // \92¼\89º\83z\83X\83g\82ª\8eó\90M\82µ\82Ä\82¢\82é\83`\83\83\83\93\83l\83\8b\82Ì\83z\83X\83g\8fî\95ñ\82ð\8eæ\93¾
+                               chl = chanMgr->findHitListByID(s->chanID);
+                               // \83`\83\83\83\93\83l\83\8b\82Ì\83z\83X\83g\8fî\95ñ\82ª\82 \82é\82©
+                               if (chl){
+                                       // \83`\83\83\83\93\83l\83\8b\82Ì\83z\83X\83g\8fî\95ñ\82ª\82 \82é\8fê\8d\87
+                                       ChanHit *hit = chl->hit;
+                                       //\81@\83`\83\83\83\93\83l\83\8b\82Ì\83z\83X\83g\8fî\95ñ\82ð\91S\91\96\8d¸\82µ\82Ä
+                                       while(hit){
+                                               // ID\82ª\93¯\82\82à\82Ì\82Å\82 \82ê\82Î
+                                               if (hit->servent_id == s->servent_id){
+                                                       // \83g\81[\83^\83\8b\83\8a\83\8c\81[\82Æ\83g\81[\83^\83\8b\83\8a\83X\83i\81[\82ð\89Á\8eZ
+                                                       totalRelays += hit->numRelays;
+                                                       totalListeners += hit->numListeners;
+                                                       // \92¼\89º\82Å\82 \82ê\82Î
+                                                       if (hit->numHops == 1){
+                                                               // \8fî\95ñ\82ð\88ê\92U\95Û\91
+                                                               infoFlg = true;
+                                                               hitData.relay = hit->relay;
+                                                               hitData.firewalled = hit->firewalled;
+                                                               hitData.numRelays = hit->numRelays;
+                                                               hitData.version_vp = hit->version_vp;
+                                                               hitData.version_ex_prefix[0] = hit->version_ex_prefix[0];
+                                                               hitData.version_ex_prefix[1] = hit->version_ex_prefix[1];
+                                                               hitData.version_ex_number = hit->version_ex_number;
+                                                       }
+                                               }
+                                               // \8e\9f\82ð\83`\83F\83b\83N
+                                               hit = hit->next;
+                                       }
+                               }
+
+                               // \83`\83\83\83\93\83l\83\8b\83f\81[\83^\82©\82çServent\82ð\8c\9f\8dõ
+                               bool bFoundFlg = FALSE;
+                               cd = channelDataTop;
+                               while(cd){
+                                       ServentData *sv = cd->findServentData(s->servent_id);
+                                       // ServentData\82ª\82 \82ê\82Î
+                                       if (sv){
+                                               // \83f\81[\83^\90Ý\92è
+                                               sv->setData(s, &hitData, totalListeners, totalRelays, infoFlg);
+                                               sv->setEnableFlg(TRUE);
+                                               bFoundFlg = TRUE;
+                                               break;
+                                       }
+                                       cd = cd->getNextData();
+                               }
+                               // ServentData\82ª\8c©\82Â\82©\82ç\82È\82©\82Á\82½\8fê\8d\87
+                               if (!bFoundFlg){
+                                       // \83`\83\83\83\93\83l\83\8b\83f\81[\83^\82ð\92T\82·
+                                       cd = channelDataTop;
+                                       while(cd){
+                                               // \83`\83\83\83\93\83l\83\8bID\82ª\93¯\82\82©
+                                               if (cd->getChannelId() == s->channel_id){
+                                                       // \83f\81[\83^\90Ý\92è
+                                                       ServentData *sv = ::new ServentData();
+                                                       sv->setData(s, &hitData, totalListeners, totalRelays, infoFlg);
+                                                       sv->setEnableFlg(TRUE);
+                                                       // \83`\83\83\83\93\83l\83\8b\83f\81[\83^\82ÉServentData\92Ç\89Á
+                                                       cd->addServentData(sv);
+                                                       // \83z\83X\83g\96¼\82ð\8eæ\93¾\82·\82é
+                                                       IdData *id = ::new IdData(cd->getChannelId(), sv->getServentId(), sv->getHost().ip);
+                                                       ThreadInfo t;
+                                                       t.func = GetHostName;
+                                                       t.data = (void*)id;
+                                                       sys->startThread(&t);
+                                                       // \83\8b\81[\83v\8fI\97¹
+                                                       break;
+                                               }
+                                               // \8e\9f\82Ì\83f\81[\83^\82Ö
+                                               cd = cd->getNextData();
+                                       }
+                               }
+                               // \83z\83X\83g\8fî\95ñ\83A\83\93\83\8d\83b\83N
+                               chanMgr->hitlistlock.off();
+                       }
+                       s = s->next;
+               }
+
+               // \8dX\90V\82µ\82Ä\82¢\82È\82¢ServentData\82ð\8dí\8f\9c
+               cd = channelDataTop;
+               while(cd){
+                       cd->deleteDisableServents();
+                       cd = cd->getNextData();
+               }
+
+               // \83`\83\83\83\93\83l\83\8b\83f\81[\83^\83A\83\93\83\8d\83b\83N
+               ChannelDataLock.off();
+
+               // \95`\89æ\8dX\90V
+               if (guiWnd){
+                       MakeBack(guiWnd);
+               }
+
+               // 0.1\95b\81~10\82Å1\95b\91Ò\82¿
+               for(i=0; i<10; i++)
+               {
+                       if (!thread->active)
+                               break;
+                       sys->sleep(100);
+               }
+
+               if (gbGetFile && (sys->getTime() > gtGetFile)){
+                       gbGetFile = false;
+                       gtiGetFile.func = GetInternetFile;
+                       gtiGetFile.data = NULL;
+                       sys->startThread(&gtiGetFile);
+               }
+               else if (gbStart && (sys->getTime() > gtStartTime)){
+                       gbStart = false;
+                       SendMessage(guiWnd, WM_START, 0, 0);
+                       gtiStart.func = FestivalStart;
+                       gtiStart.data = NULL;
+                       sys->startThread(&gtiStart);
+               }
+       }
+
+       // set GUI thread status to terminated
+       thread->finish = true;
+
+       return 0;
+}
+
+ChannelData *findChannelData(int channel_id){
+       ChannelData *cd = channelDataTop;
+
+       while(cd){
+               if (cd->getChannelId() == channel_id){
+                       return cd;
+               }
+               cd = cd->getNextData();
+       }
+
+       return NULL;
+}
+
+
+void PopupChannelMenu(int channel_id){
+       POINT pos;
+       MENUITEMINFO info, separator;
+       HMENU hMenu;
+       DWORD dwID;
+
+       hMenu = CreatePopupMenu();
+
+       memset(&separator, 0, sizeof(MENUITEMINFO));
+       separator.cbSize = sizeof(MENUITEMINFO);
+       separator.fMask = MIIM_ID | MIIM_TYPE;
+       separator.fType = MFT_SEPARATOR;
+       separator.wID = 8000;
+
+       memset(&info, 0, sizeof(MENUITEMINFO));
+       info.cbSize = sizeof(MENUITEMINFO);
+       info.fMask = MIIM_ID | MIIM_TYPE;
+       info.fType = MFT_STRING;
+
+       ChannelData *cd = findChannelData(channel_id);
+
+       if (cd == NULL){
+               return;
+       }
+
+       info.wID = 1001;
+       info.dwTypeData = "\90Ø\92f";
+       InsertMenuItem(hMenu, -1, true, &info);
+
+       InsertMenuItem(hMenu, -1, true, &separator);
+
+       info.wID = 1000;
+       info.dwTypeData = "\8dÄ\90¶";
+       InsertMenuItem(hMenu, -1, true, &info);
+
+       InsertMenuItem(hMenu, -1, true, &separator);
+
+       info.wID = 1002;
+       info.dwTypeData = "\8dÄ\90Ú\91±";
+       InsertMenuItem(hMenu, -1, true, &info);
+
+       info.wID = 1003;
+       info.dwTypeData = "\83L\81[\83v";
+       InsertMenuItem(hMenu, -1, true, &info);
+
+       InsertMenuItem(hMenu, -1, true, &separator);
+
+       if (!cd->getOpenFlg()){
+               info.wID = 1004;
+               info.dwTypeData = "\92¼\89º\95\\8e¦";
+               InsertMenuItem(hMenu, -1, true, &info);
+       } else {
+               info.wID = 1005;
+               info.dwTypeData = "\92¼\89º\89B\95Á";
+               InsertMenuItem(hMenu, -1, true, &info);
+       }
+
+       GetCursorPos(&pos);
+       dwID = TrackPopupMenu(hMenu, TPM_LEFTALIGN|TPM_RETURNCMD, pos.x, pos.y, 0, guiWnd, NULL);
+
+       DestroyMenu(hMenu);
+
+       cd = findChannelData(channel_id);
+
+       if (cd == NULL){
+               return;
+       }
+
+       Channel *c = chanMgr->findChannelByChannelID(channel_id);
+
+       if (c == NULL){
+               return;
+       }
+
+       switch(dwID){
+               case 1000:      // \8dÄ\90
+                       chanMgr->playChannel(c->info);
+                       break;
+
+               case 1001:      // \90Ø\92f
+                       c->thread.active = false;
+                       c->thread.finish = true;
+                       break;
+
+               case 1002:      // \8dÄ\90Ú\91±
+                       c->bump = true;
+                       break;
+
+               case 1003:      // \83L\81[\83v
+                       if (!c->stayConnected){
+                               c->stayConnected  = true;
+                       } else {
+                               c->stayConnected = false;
+                       }
+                       break;
+
+               case 1004:      // \92¼\89º\95\\8e¦
+                       cd->setOpenFlg(TRUE);
+                       MakeBack(guiWnd);
+                       break;
+
+               case 1005:      // \92¼\89º\89B\95Á
+                       cd->setOpenFlg(FALSE);
+                       MakeBack(guiWnd);
+                       break;
+       }
+}
+
+void PopupServentMenu(int servent_id){
+       POINT pos;
+       MENUITEMINFO info, separator;
+       HMENU hMenu;
+       DWORD dwID;
+
+       hMenu = CreatePopupMenu();
+
+       memset(&separator, 0, sizeof(MENUITEMINFO));
+       separator.cbSize = sizeof(MENUITEMINFO);
+       separator.fMask = MIIM_ID | MIIM_TYPE;
+       separator.fType = MFT_SEPARATOR;
+       separator.wID = 8000;
+
+       memset(&info, 0, sizeof(MENUITEMINFO));
+       info.cbSize = sizeof(MENUITEMINFO);
+       info.fMask = MIIM_ID | MIIM_TYPE;
+       info.fType = MFT_STRING;
+
+       ServentData *sd = NULL;
+       ChannelData *cd = channelDataTop;
+       while(cd){
+               sd = cd->findServentData(servent_id);
+               if (sd){
+                       break;
+               }
+               cd = cd->getNextData();
+       }
+
+       if (cd == NULL || sd == NULL){
+               return;
+       }
+
+       info.wID = 1001;
+       info.dwTypeData = "\90Ø\92f";
+       InsertMenuItem(hMenu, -1, true, &info);
+
+//     InsertMenuItem(hMenu, -1, true, &separator);
+
+       GetCursorPos(&pos);
+       dwID = TrackPopupMenu(hMenu, TPM_LEFTALIGN|TPM_RETURNCMD, pos.x, pos.y, 0, guiWnd, NULL);
+
+       DestroyMenu(hMenu);
+
+       cd = channelDataTop;
+       while(cd){
+               sd = cd->findServentData(servent_id);
+               if (sd){
+                       break;
+               }
+               cd = cd->getNextData();
+       }
+
+       if (cd == NULL || sd == NULL){
+               return;
+       }
+
+       Servent *s = servMgr->findServentByServentID(servent_id);
+
+       if (s == NULL){
+               return;
+       }
+
+       switch(dwID){
+               case 1001:      // \90Ø\92f
+                       s->thread.active = false;
+                       break;
+
+       }
+}
+
+void PopupOtherMenu(){
+       POINT pos;
+       MENUITEMINFO info, separator;
+       HMENU hMenu;
+       DWORD dwID;
+
+       hMenu = CreatePopupMenu();
+
+       memset(&separator, 0, sizeof(MENUITEMINFO));
+       separator.cbSize = sizeof(MENUITEMINFO);
+       separator.fMask = MIIM_ID | MIIM_TYPE;
+       separator.fType = MFT_SEPARATOR;
+       separator.wID = 8000;
+
+       memset(&info, 0, sizeof(MENUITEMINFO));
+       info.cbSize = sizeof(MENUITEMINFO);
+       info.fMask = MIIM_ID | MIIM_TYPE;
+       info.fType = MFT_STRING;
+
+       if (!gbDispTop){
+               info.wID = 1101;
+               info.dwTypeData = "\8dÅ\91O\96Ê\95\\8e¦";
+               InsertMenuItem(hMenu, -1, true, &info);
+       } else {
+               info.wID = 1102;
+               info.dwTypeData = "\8dÅ\91O\96Ê\89ð\8f\9c";
+               InsertMenuItem(hMenu, -1, true, &info);
+       }
+
+       InsertMenuItem(hMenu, -1, true, &separator);
+
+       if (!gbAllOpen){
+               info.wID = 1103;
+               info.dwTypeData = "\91S\92¼\89º\93W\8aJ";
+               InsertMenuItem(hMenu, -1, true, &info);
+       } else {
+               info.wID = 1104;
+               info.dwTypeData = "\91S\92¼\89º\89B\95Á";
+               InsertMenuItem(hMenu, -1, true, &info);
+       }
+
+       InsertMenuItem(hMenu, -1, true, &separator);
+
+       if (!servMgr->autoServe){
+               info.wID = 1105;
+               info.dwTypeData = "\97L\8cø";
+               InsertMenuItem(hMenu, -1, true, &info);
+       } else {
+               info.wID = 1106;
+               info.dwTypeData = "\96³\8cø";
+               InsertMenuItem(hMenu, -1, true, &info);
+       }
+
+       GetCursorPos(&pos);
+       dwID = TrackPopupMenu(hMenu, TPM_LEFTALIGN|TPM_RETURNCMD, pos.x, pos.y, 0, guiWnd, NULL);
+
+       DestroyMenu(hMenu);
+
+       ChannelData *cd = channelDataTop;
+
+       switch(dwID){
+               case 1101:      // \8dÅ\91O\96Ê\95\\8e¦
+                       gbDispTop = true;
+                       ::SetWindowPos(guiWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
+                       break;
+
+               case 1102:      // \8dÅ\91O\96Ê\89ð\8f\9c
+                       gbDispTop = false;
+                       ::SetWindowPos(guiWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
+                       break;
+
+               case 1103:      // \91S\92¼\89º\93W\8aJ
+                       gbAllOpen = true;
+                       while(cd){
+                               cd->setOpenFlg(true);
+                               cd = cd->getNextData();
+                       }
+                       break;
+
+               case 1104:      // \91S\92¼\89º\89B\95Á
+                       gbAllOpen = false;
+                       while(cd){
+                               cd->setOpenFlg(false);
+                               cd = cd->getNextData();
+                       }
+                       break;
+
+               case 1105:      // \97L\8cø
+                       servMgr->autoServe = true;
+                       break;
+
+               case 1106:      // \96³\8cø
+                       servMgr->autoServe = false;
+                       break;
+
+       }
+}
+
+void WmCreateProc(HWND hwnd){
+       if (backImage){
+               ::delete backImage;
+       }
+       _bstr_t bstr("back.jpg");
+       backImage = ::new Image(bstr);
+
+       MakeBack(hwnd, 800, 600);
+
+       guiThread.func = GUIDataUpdate;
+       if (!sys->startThread(&guiThread)){
+               MessageBox(hwnd,"Unable to start GUI","PeerCast",MB_OK|MB_ICONERROR);
+               PostMessage(hwnd,WM_DESTROY,0,0);
+       }
+       if (guiFlg){
+               SetWindowPlacement(hwnd, &winPlace);
+       }
+
+       if (img_idle){
+               ::delete img_idle;
+               ::delete img_connect;
+               ::delete img_conn_ok;
+               ::delete img_conn_full;
+               ::delete img_conn_over;
+               ::delete img_conn_ok_skip;
+               ::delete img_conn_full_skip;
+               ::delete img_conn_over_skip;
+               ::delete img_error;
+               ::delete img_broad_ok;
+               ::delete img_broad_full;
+       }
+       bstr = L"ST_IDLE.bmp";
+       img_idle = ::new Image(bstr);
+       bstr = L"ST_CONNECT.bmp";
+       img_connect = ::new Image(bstr);
+       bstr = L"ST_CONN_OK.bmp";
+       img_conn_ok = ::new Image(bstr);
+       bstr = L"ST_CONN_FULL.bmp";
+       img_conn_full = ::new Image(bstr);
+       bstr = L"ST_CONN_OVER.bmp";
+       img_conn_over = ::new Image(bstr);
+       bstr = L"ST_CONN_OK_SKIP.bmp";
+       img_conn_ok_skip = ::new Image(bstr);
+       bstr = L"ST_CONN_FULL_SKIP.bmp";
+       img_conn_full_skip = ::new Image(bstr);
+       bstr = L"ST_CONN_OVER_SKIP.bmp";
+       img_conn_over_skip = ::new Image(bstr);
+       bstr = L"ST_ERROR.bmp";
+       img_error = ::new Image(bstr);
+       bstr = L"ST_BROAD_OK.bmp";
+       img_broad_ok = ::new Image(bstr);
+       bstr = L"ST_BROAD_FULL.bmp";
+       img_broad_full = ::new Image(bstr);
+}
+
+void WmPaintProc(HWND hwnd){
+       HDC hdc;
+       PAINTSTRUCT paint;
+
+       if (backGra){
+               MakeBackLock.on();
+               hdc = BeginPaint(hwnd, &paint);
+               RECT *rcRect;   // \95`\89æ\94Í\88Í
+               rcRect = &(paint.rcPaint);
+               LONG width = rcRect->right - rcRect->left + 1;
+               LONG height = rcRect->bottom - rcRect->top + 1;
+
+               Graphics g2(hdc);
+               Rect r(rcRect->left, rcRect->top, width, height);
+               g2.DrawImage(backBmp,r, rcRect->left, rcRect->top, width, height, UnitPixel);
+               EndPaint(hwnd, &paint);
+               MakeBackLock.off();
+       }
+}
+
+void WmSizeProc(HWND hwnd, LPARAM lParam){
+       UINT width = LOWORD(lParam);
+       UINT height = HIWORD(lParam);
+
+       MakeBack(hwnd, width, height);
+
+}
+
+void WmLButtonDownProc(HWND hwnd, LPARAM lParam){
+       ChannelData *cd;
+       bool changeFlg = FALSE;
+
+       ChannelDataLock.on();
+       cd = channelDataTop;
+       while(cd){
+               int x = LOWORD(lParam);
+               int y = HIWORD(lParam);
+               if (cd->checkDown(LOWORD(lParam), HIWORD(lParam))){
+                       if (!(cd->isSelected())){
+                               changeFlg = TRUE;
+                       }
+                       cd->setSelected(TRUE);
+               } else {
+                       if (cd->isSelected()){
+                               changeFlg = TRUE;
+                       }
+                       cd->setSelected(FALSE);
+               }
+               int sx = cd->getPosX() + cd->getWidth();
+               int sy = cd->getPosY();
+               int index = 0;
+               ServentData *sd = cd->getServentDataTop();
+               while(sd){
+                       if (    (       (!cd->getOpenFlg())
+                                       &&      (sx + index*14 < x)
+                                       &&      (x < sx + (index+1)*14)
+                                       &&      (sy < y)
+                                       &&      (y < sy + 14)   )
+                               ||      sd->checkDown(LOWORD(lParam), HIWORD(lParam))
+                       ){
+                               if (!sd->getSelected()){
+                                       changeFlg = TRUE;
+                               }
+                               sd->setSelected(TRUE);
+                       } else {
+                               if (sd->getSelected()){
+                                       changeFlg = TRUE;
+                               }
+                               sd->setSelected(FALSE);
+                       }
+                       sd = sd->getNextData();
+                       index++;
+               }
+               cd = cd->getNextData();
+       }
+       ChannelDataLock.off();
+       if (changeFlg){
+               MakeBack(hwnd);
+       }
+}
+
+void WmLButtonDblclkProc(HWND hwnd, LPARAM lParam){
+       ChannelData *cd;
+       bool changeFlg = FALSE;
+
+       ChannelDataLock.on();
+       cd = channelDataTop;
+       while(cd){
+               int x = LOWORD(lParam);
+               int y = HIWORD(lParam);
+               if (cd->checkDown(LOWORD(lParam), HIWORD(lParam))){
+                       if (!(cd->isSelected())){
+                               changeFlg = TRUE;
+                       }
+                       if (!(cd->getOpenFlg())){
+                               changeFlg = TRUE;
+                               cd->setOpenFlg(TRUE);
+                       } else {
+                               changeFlg = TRUE;
+                               cd->setOpenFlg(FALSE);
+                       }
+                       cd->setSelected(TRUE);
+               } else {
+                       if (cd->isSelected()){
+                               changeFlg = TRUE;
+                       }
+                       cd->setSelected(FALSE);
+               }
+/*             int sx = cd->getPosX() + cd->getWidth();
+               int sy = cd->getPosY();
+               int index = 0;
+               ServentData *sd = cd->getServentDataTop();
+               while(sd){
+                       if (    (       (!cd->getOpenFlg())
+                                       &&      (sx + index*14 < x)
+                                       &&      (x < sx + (index+1)*14)
+                                       &&      (sy < y)
+                                       &&      (y < sy + 14)   )
+                               ||      sd->checkDown(LOWORD(lParam), HIWORD(lParam))
+                       ){
+                               if (!sd->getSelected()){
+                                       changeFlg = TRUE;
+                               }
+                               sd->setSelected(TRUE);
+                       } else {
+                               if (sd->getSelected()){
+                                       changeFlg = TRUE;
+                               }
+                               sd->setSelected(FALSE);
+                       }
+                       sd = sd->getNextData();
+                       index++;
+               }*/
+               cd = cd->getNextData();
+       }
+       ChannelDataLock.off();
+       if (changeFlg){
+               MakeBack(hwnd);
+       }
+}
+
+void WmRButtonDownProc(HWND hwnd, LPARAM lParam){
+       ChannelData *cd;
+       bool changeFlg = FALSE;
+       bool channel_selected = FALSE;
+       bool servent_selected = FALSE;
+       int channel_id = 0;
+       int servent_id = 0;
+
+       cd = channelDataTop;
+       while(cd){
+               if (cd->checkDown(LOWORD(lParam), HIWORD(lParam))){
+                       if (!(cd->isSelected())){
+                               changeFlg = TRUE;
+                       }
+                       cd->setSelected(TRUE);
+                       channel_id = cd->getChannelId();
+                       channel_selected = TRUE;
+               } else {
+                       if (cd->isSelected()){
+                               changeFlg = TRUE;
+                       }
+                       cd->setSelected(FALSE);
+               }
+               ServentData *sd = cd->getServentDataTop();
+               while(sd){
+                       if (sd->checkDown(LOWORD(lParam), HIWORD(lParam))){
+                               if (!sd->getSelected()){
+                                       changeFlg = TRUE;
+                               }
+                               sd->setSelected(TRUE);
+                               servent_id = sd->getServentId();
+                               servent_selected = TRUE;
+                       } else {
+                               if (sd->getSelected()){
+                                       changeFlg = TRUE;
+                               }
+                               sd->setSelected(FALSE);
+                       }
+                       sd = sd->getNextData();
+               }
+               cd = cd->getNextData();
+       }
+       if (changeFlg){
+               MakeBack(hwnd);
+       }
+
+       if (channel_selected){
+               PopupChannelMenu(channel_id);
+       } else if (servent_selected){
+               PopupServentMenu(servent_id);
+       } else {
+               PopupOtherMenu();
+       }
+}
+
+LRESULT CALLBACK GUIProc (HWND hwnd, UINT message,
+                                 WPARAM wParam, LPARAM lParam)
+{
+       switch(message){
+               case WM_CREATE:         // \83E\83B\83\93\83h\83E\8dì\90¬
+                       WmCreateProc(hwnd);
+                       break;
+
+               case WM_PAINT:          // \95`\89æ
+                       WmPaintProc(hwnd);
+                       break;
+
+               case WM_SIZE:           // \83T\83C\83Y\95Ï\8dX
+                       WmSizeProc(hwnd,lParam);
+                       break;
+
+               case WM_LBUTTONDOWN:    // \8d\83{\83^\83\93\89\9f\82·
+                       WmLButtonDownProc(hwnd,lParam);
+                       break;
+
+               case WM_RBUTTONDOWN:    // \89E\83{\83^\83\93\89\9f\82·
+                       WmRButtonDownProc(hwnd,lParam);
+                       break;
+
+               case WM_LBUTTONDBLCLK:          // \8d\83_\83u\83\8b\83N\83\8a\83b\83N
+                       WmLButtonDblclkProc(hwnd,lParam);
+                       break;
+
+               case WM_ERASEBKGND:     // \94w\8ci\8fÁ\8b\8e
+                       return TRUE;    // \94w\8ci\82Í\8fÁ\82³\82È\82¢
+
+               case WM_CLOSE:
+                       //if (backImage){
+                       //      ::delete backImage;
+                       //      backImage = NULL;
+                       //}
+                       GetWindowPlacement(hwnd, &winPlace);
+                       guiFlg = true;
+                       DestroyWindow( hwnd );
+                       break;
+               case WM_DESTROY:
+                       GetWindowPlacement(hwnd, &winPlace);
+                       guiFlg = true;
+                       guiThread.active = false;
+
+                       // wait until GUI thread terminated,
+                       // and then dispose background image.
+                       while (1)
+                       {
+                               if (guiThread.finish)
+                                       break;
+                       }
+                       if (backImage)
+                       {
+                               ::delete backImage;
+                               backImage = NULL;
+                       }
+
+                       guiWnd = NULL;
+                       break;
+               case WM_START:
+                       ghStart = ::CreateWindow(szWindowClass3,
+                               "Peercast-IM@S",
+                               WS_OVERLAPPEDWINDOW & ~(WS_MAXIMIZEBOX),
+                               0,
+                               0,
+                               400,
+                               300,
+                               NULL,
+                               NULL,
+                               hInst,
+                               NULL);
+                       ::ShowWindow(ghStart, SW_SHOWNORMAL);
+                       break;
+
+               default:
+                       return (DefWindowProc(hwnd, message, wParam, lParam));
+       }
+
+       return 0;
+}
+
+Gdiplus::Image *data1 = NULL;
+Gdiplus::Image *data2 = NULL;
+Gdiplus::Bitmap *startBmp = NULL;
+Gdiplus::Graphics *startGra = NULL;
+WLock MakeStartLock;
+
+LRESULT CALLBACK StartProc (HWND hwnd, UINT message,
+                                 WPARAM wParam, LPARAM lParam)
+{
+       SolidBrush b(Color::Black);
+       bstr_t bstr;
+
+       switch(message){
+               case WM_CREATE:
+                       startBmp = ::new Bitmap(400,300);
+                       startGra = ::new Graphics(startBmp);
+                       bstr = L"data1.jpg";
+                       data1 = ::new Image(bstr);
+                       bstr = L"data2.jpg";
+                       data2 = ::new Image(bstr);
+                       // \8d\95\82Å\93h\82è\82Â\82Ô\82µ
+                       startGra->FillRectangle(&b, 0, 0, 400, 300);
+                       break;
+               case WM_PAINT:
+                       if (startGra){
+                               HDC hdc;
+                               PAINTSTRUCT paint;
+
+                               MakeStartLock.on();
+                               hdc = BeginPaint(hwnd, &paint);
+                               RECT *rcRect;
+                               rcRect = &(paint.rcPaint);
+                               LONG width = rcRect->right - rcRect->left + 1;
+                               LONG height = rcRect->bottom - rcRect->top + 1;
+
+                               Graphics g2(hdc);
+                               Rect r(rcRect->left, rcRect->top, width, height);
+                               g2.DrawImage(startBmp, r, rcRect->left, rcRect->top, width, height, UnitPixel);
+                               EndPaint(hwnd, &paint);
+                               MakeStartLock.off();
+                       }
+                       break;
+               case WM_ERASEBKGND:
+                       return TRUE;
+               case WM_CLOSE:
+                       DestroyWindow(ghStart);
+                       if (startBmp){
+                               ::delete startBmp;
+                       }
+                       if (startGra){
+                               ::delete startGra;
+                       }
+                       if (data1){
+                               ::delete data1;
+                       }
+                       if (data2){
+                               ::delete data2;
+                       }
+                       break;
+
+               default:
+                       return (DefWindowProc(hwnd, message, wParam, lParam));
+       }
+
+       return 0;
+}
+
+THREAD_PROC FestivalStart(ThreadInfo *thread){
+
+       while(startGra==NULL){
+               sys->sleep(100);
+       }
+
+       sys->sleep(1000);
+
+       MakeStartLock.on();
+       Font font(L"\82l\82\82o\83S\83V\83b\83N",40);
+       StringFormat format;
+       format.SetAlignment(StringAlignmentCenter);
+       startGra->SetTextRenderingHint(TextRenderingHintAntiAlias);
+       PointF origin(199.0f,49.0f);
+       RectF rect(0,0,400,100);
+       LinearGradientBrush b1(rect, Color::LightSkyBlue, Color::White, LinearGradientModeHorizontal);
+       startGra->DrawString(L"\91æ\82Q\89ñ", -1, &font, origin, &format, &b1);
+       origin.Y += 50;
+       LinearGradientBrush b2(rect, Color::LightGreen, Color::White, LinearGradientModeHorizontal);
+       startGra->DrawString(L"\83A\83C\83h\83\8b\83}\83X\83^\81[", -1, &font, origin, &format, &b2);
+       origin.Y += 50;
+       LinearGradientBrush b3(rect, Color::LightGoldenrodYellow, Color::White, LinearGradientModeHorizontal);
+       startGra->DrawString(L"\83t\83@\83\93\8a´\8eÓ\8dÕ", -1, &font, origin, &format, &b3);
+       MakeStartLock.off();
+       InvalidateRect(ghStart, NULL, FALSE);
+       sys->sleep(3000);
+
+       MakeStartLock.on();
+       startGra->DrawImage(data1, Rect(0,0,80,400), 200,200,66,330, UnitPixel);
+       MakeStartLock.off();
+       InvalidateRect(ghStart, NULL, FALSE);
+       sys->sleep(500);
+
+       MakeStartLock.on();
+       startGra->DrawImage(data1, Rect(80,0,80,400), 266,200,66,330, UnitPixel);
+       MakeStartLock.off();
+       InvalidateRect(ghStart, NULL, FALSE);
+       sys->sleep(500);
+
+       MakeStartLock.on();
+       startGra->DrawImage(data1, Rect(160,0,80,400), 332,200,66,330, UnitPixel);
+       MakeStartLock.off();
+       InvalidateRect(ghStart, NULL, FALSE);
+       sys->sleep(500);
+
+       MakeStartLock.on();
+       startGra->DrawImage(data1, Rect(240,0,80,400), 398,200,66,330, UnitPixel);
+       MakeStartLock.off();
+       InvalidateRect(ghStart, NULL, FALSE);
+       sys->sleep(500);
+
+       MakeStartLock.on();
+       startGra->DrawImage(data1, Rect(320,0,80,400), 464,200,66,330, UnitPixel);
+       MakeStartLock.off();
+       InvalidateRect(ghStart, NULL, FALSE);
+       sys->sleep(500);
+
+       MakeStartLock.on();
+       startGra->DrawImage(data1, Rect(0,0,80,400), 530,200,54,270, UnitPixel);
+       MakeStartLock.off();
+       InvalidateRect(ghStart, NULL, FALSE);
+       sys->sleep(500);
+
+       MakeStartLock.on();
+       startGra->DrawImage(data1, Rect(80,0,80,400), 584,200,54,270, UnitPixel);
+       MakeStartLock.off();
+       InvalidateRect(ghStart, NULL, FALSE);
+       sys->sleep(500);
+
+       MakeStartLock.on();
+       startGra->DrawImage(data1, Rect(160,0,80,400), 638,200,54,270, UnitPixel);
+       MakeStartLock.off();
+       InvalidateRect(ghStart, NULL, FALSE);
+       sys->sleep(500);
+
+       MakeStartLock.on();
+       startGra->DrawImage(data1, Rect(240,0,80,400), 692,200,54,270, UnitPixel);
+       MakeStartLock.off();
+       InvalidateRect(ghStart, NULL, FALSE);
+       sys->sleep(500);
+
+       MakeStartLock.on();
+       startGra->DrawImage(data1, Rect(320,0,80,400), 746,200,54,270, UnitPixel);
+       MakeStartLock.off();
+       InvalidateRect(ghStart, NULL, FALSE);
+       sys->sleep(500);
+
+       for (int i=1; i<=10; i++){
+               ColorMatrix mtx = {
+                       1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+                       0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
+                       0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
+                       0.0f, 0.0f, 0.0f, 0.1f*i, 0.0f,
+                       0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
+               ImageAttributes att;
+
+               MakeStartLock.on();
+               att.SetColorMatrix(&mtx, ColorMatrixFlagsDefault, ColorAdjustTypeBitmap);
+               startGra->DrawImage(data2, Rect(0,0,400,300), 360,130,400,300, UnitPixel, &att);
+               MakeStartLock.off();
+               InvalidateRect(ghStart, NULL, FALSE);
+               sys->sleep(100);
+       }
+
+       sys->sleep(2000);
+
+       MakeStartLock.on();
+       INT style = FontStyleBold;
+       Font font2(L"\82l\82\82o\83S\83V\83b\83N",70,style,UnitPoint);
+       PointF origin2(199.0f,99.0f);
+       SolidBrush bs(Color::Black);
+       startGra->DrawString(L"START!", -1, &font2, origin2, &format, &bs);
+       Font font3(L"\82l\82\82o\83S\83V\83b\83N",70,style,UnitPoint);
+       LinearGradientBrush bx(rect, Color::LightPink, Color::DeepPink, LinearGradientModeHorizontal);
+       startGra->DrawString(L"START!", -1, &font3, origin2, &format, &bx);
+       MakeStartLock.off();
+       InvalidateRect(ghStart, NULL, FALSE);
+       sys->sleep(5000);
+
+       SendMessage(ghStart, WM_CLOSE, 0, 0);
+       return 0;
+}
diff --git a/PeerCast.root/PeerCast/ui/win32/simple/gui.h b/PeerCast.root/PeerCast/ui/win32/simple/gui.h
new file mode 100644 (file)
index 0000000..84e7381
--- /dev/null
@@ -0,0 +1,228 @@
+// ------------------------------------------------
+// File : gui.h
+// Date: 4-apr-2002
+// Author: giles
+// 
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _GUI_H
+#define _GUI_H
+
+#include "sys.h"
+#include "gdiplus.h"
+#include "channel.h"
+
+extern LRESULT CALLBACK GUIProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+extern LRESULT CALLBACK StartProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+extern void ADDLOG(const char *str,int id,bool sel,void *data, LogBuffer::TYPE type);
+
+extern String iniFileName;
+extern HWND guiWnd;
+extern int logID;
+
+enum 
+{
+       WM_INITSETTINGS = WM_USER,
+       WM_GETPORTNUMBER,
+       WM_PLAYCHANNEL,
+       WM_TRAYICON,
+       WM_SHOWGUI,
+       WM_SHOWMENU,
+       WM_PROCURL,
+       WM_START
+
+};
+
+class IdData
+{
+private:
+       int channel_id;
+       int servent_id;
+       unsigned int ip_addr;
+
+public:
+       IdData(int cid, int sid, unsigned int ip){
+               channel_id = cid;
+               servent_id = sid;
+               ip_addr = ip;
+       }
+
+       int getChannelId(){return channel_id;};
+       int getServentId(){return servent_id;};
+       unsigned int getIpAddr(){return ip_addr;};
+};
+
+class ServentData
+{
+private:
+       int servent_id;
+       int type;
+//     unsigned int tnum;
+       int status;
+//     String agent;
+       Host host;
+       String hostname;
+//     unsigned int syncpos;
+//     char *typeStr;
+//     char *statusStr;
+//     bool infoFlg;
+//     bool relay;
+//     bool firewalled;
+       unsigned int totalRelays;
+       unsigned int totalListeners;
+//     int vp_ver;
+//     char ver_ex_prefix[2];
+//     int ver_ex_number;
+
+       bool EnableFlg;
+       bool infoFlg;
+       ServentData *next;
+       ChanHit chanHit;
+       bool selected;
+       int posX;
+       int posY;
+       int     width;
+       int height;
+
+       unsigned int lastSkipTime;
+       unsigned int lastSkipCount;
+
+public:
+       ServentData(){
+               next = NULL;
+               EnableFlg = false;
+               infoFlg = false;
+
+               posX = 0;
+               posY = 0;
+               width = 0;
+               selected = false;
+
+       }
+       void setData(Servent *s, ChanHit *hit, unsigned int listeners, unsigned int relays, bool infoFlg);
+       bool getInfoFlg(){return infoFlg;}
+       ChanHit *getChanHit(){return &chanHit;};
+       int getStatus(){return status;};
+       Host getHost(){return host;};
+
+       int getServentId(){return servent_id;};
+
+       bool getEnableFlg(){return EnableFlg;};
+       void setEnableFlg(bool f){EnableFlg = f;};
+       ServentData *getNextData(){return next;};
+       void setNextData(ServentData *s){next = s;};
+       bool getSelected(){return selected;};
+       void setSelected(bool f){selected = f; if (!f){posX=0;posY=0;}};
+       int getWidth(){return width;};
+       void setWidth(int w){width = w;};
+       int getHeight(){return height;};
+       void setHeight(int h){height = h;};
+       String getName(){return hostname;};
+       void setName(String n){hostname = n;};
+
+       int drawServent(Gdiplus::Graphics *g, int x, int y);
+
+       bool checkDown(int x, int y);
+
+};
+
+class ChannelData {
+
+private:
+       int channel_id;
+       char name[257];
+       int bitRate;
+       unsigned int lastPlayStart;
+       int status;
+       int totalListeners;
+       int totalRelays;
+       int localListeners;
+       int localRelays;
+       bool stayConnected;
+       ChanHit chDisp;
+       bool bTracker;
+       unsigned int lastSkipTime;
+       unsigned int skipCount;
+
+       bool EnableFlg;
+       ChannelData *next;
+
+       int posX;
+       int posY;
+       int width;
+       int height;
+       bool selected;
+       ServentData *serventDataTop;
+       bool openFlg;
+
+public:
+       ChannelData(){
+               EnableFlg = FALSE;
+               next = NULL;
+               posX = 0;
+               posY = 0;
+               width = 0;
+               height = 0;
+               selected = FALSE;
+               serventDataTop = NULL;
+               openFlg = FALSE;
+       }
+       int drawChannel(Gdiplus::Graphics *g, int x, int y);
+
+       void setData(Channel *);
+       int getChannelId(){return channel_id;};
+       char* getName(){return &(name[0]);};
+       int getBitRate(){return bitRate;};
+       bool isStayConnected(){return stayConnected;};
+       bool isTracker(){return bTracker;};
+       int getStatus(){return status;};
+       unsigned int getLastSkipTime(){return lastSkipTime;};
+
+       int getTotalListeners(){return totalListeners;};
+       int getTotalRelays(){return totalRelays;};
+       int getLocalListeners(){return localListeners;};
+       int getLocalRelays(){return localRelays;};
+
+       bool getEnableFlg(){return EnableFlg;};
+       void setEnableFlg(bool flg){EnableFlg = flg;};
+       ChannelData *getNextData(){return next;};
+       void setNextData(ChannelData* cd){next = cd;};
+
+       int getPosX(){return posX;};
+       void setPosX(int x){posX = x;}
+       int getPosY(){return posY;};
+       void setPosY(int y){posY = y;};
+       int getWidth(){return width;};
+       void setWidth(int w){width = w;};
+       int getHeight(){return height;};
+       void setHeight(int h){height = h;};
+       bool isSelected(){return selected;};
+       void setSelected(bool sel){selected = sel;};
+       bool getOpenFlg(){return openFlg;};
+       void setOpenFlg(bool b){openFlg = b;};
+
+       ServentData* getServentDataTop(){return serventDataTop;};
+       ServentData* findServentData(int servent_id);
+       void addServentData(ServentData *sd);
+       void deleteDisableServents();
+
+       bool setName(int servent_id, String name);
+       int getServentCount();
+
+       bool checkDown(int x, int y);
+};
+
+
+
+#endif
\ No newline at end of file
diff --git a/PeerCast.root/PeerCast/ui/win32/simple/resource.h b/PeerCast.root/PeerCast/ui/win32/simple/resource.h
new file mode 100644 (file)
index 0000000..a9a2b6d
--- /dev/null
@@ -0,0 +1,110 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by Simple.rc
+//
+#define IDC_MYICON                      2
+#define IDD_MAINWINDOW                  101
+#define IDD_SIMPLE_DIALOG               102
+#define IDD_ABOUTBOX                    103
+#define IDS_APP_TITLE                   103
+#define IDM_ABOUT                       104
+#define IDM_EXIT                        105
+#define IDS_HELLO                       106
+#define IDI_SIMPLE                      107
+#define IDI_SMALL                       108
+#define IDC_SIMPLE                      109
+#define IDI_SMALL2                      109
+#define IDR_MAINFRAME                   128
+#define IDR_TRAYMENU                    130
+#define IDR_VERMENU                     133
+#define IDD_CHANINFO                    136
+#define IDR_LTRAYMENU                   137
+#define IDC_LIST1                       1000
+#define IDC_BUTTON7                     1001
+#define IDC_ABOUTVER                    1002
+#define IDC_CHECK1                      1003
+#define IDC_EDIT1                       1004
+#define IDC_LIST2                       1005
+#define IDC_EDIT_PLAYING                1005
+#define IDC_COMBO1                      1006
+#define IDC_EDIT_MESSAGE                1006
+#define IDC_CHECK2                      1007
+#define IDC_EDIT_NAME                   1007
+#define IDC_BUTTON1                     1008
+#define IDC_EDIT_DESC                   1008
+#define IDC_DETAILS                     1009
+#define IDC_MAXRELAYS                   1009
+#define IDC_LIST3                       1010
+#define IDC_PLAY                        1010
+#define IDC_CONTACT                     1011
+#define IDC_EDIT2                       1012
+#define IDC_FORMAT                      1013
+#define IDC_EDIT_GENRE                  1014
+#define IDC_KEEP                        1015
+#define IDC_EDIT_STATUS                 1016
+#define IDC_GROUPBOX_RELAY              1016
+#define IDC_EDIT_LISTENERS              1017
+#define IDC_STATIC_CONNECTION           1017
+#define IDC_LIST4                       1018
+#define IDC_EDIT_HOSTS                  1018
+#define IDC_STATIC_LOG                  1018
+#define IDC_BUTTON4                     1019
+#define IDC_BUTTON5                     1020
+#define IDC_BUTTON6                     1021
+#define IDC_EDIT3                       1025
+#define IDC_EDIT5                       1027
+#define IDC_LOGDEBUG                    1037
+#define IDC_LOGNETWORK                  1038
+#define IDC_LOGERRORS                   1039
+#define IDC_CHECK9                      1041
+#define IDC_BUTTON8                     1043
+#define IDC_BUTTON10                    1046
+#define IDC_BUTTON11                    1047
+#define IDC_LOGCHANNELS                 1050
+#define IDC_BUTTON2                     1056
+#define IDC_EDIT4                       1058
+#define IDC_BUTTON3                     1059
+#define IDC_EDIT9                       1060
+#define IDC_CHECK11                     1061
+#define IDC_BUTTON9                     1062
+#define IDM_SETTINGS_GUI                32771
+#define ID_POPUP_ABOUT                  32779
+#define ID_POPUP_EXIT_CONFIRM           32781
+#define ID_POPUP_EXIT_NO                32782
+#define ID_POPUP_SETTINGS               32785
+#define ID_POPUP_CONNECTIONS            32786
+#define ID_POPUP_SHOWGUI                32788
+#define ID_POPUP_ALLCHANNELS            32791
+#define ID_POPUP_FAVORITES_EDIT         32792
+#define ID_POPUP_ADVANCED_INFORMATION   32793
+#define ID_POPUP_ADVANCED_SAVESETTINGS  32794
+#define ID_POPUP_UPGRADE                32795
+#define ID_POPUP_HELP                   32796
+#define ID_POPUP_ADVANCED_VIEWLOG       32797
+#define ID_POPUP_FAVORITES_PLAYALL      32798
+#define ID_POPUP_ADVANCED_ALLCHANNELS   32799
+#define ID_POPUP_ADVANCED_RELAYEDCHANNELS 32800
+#define ID_POPUP_ADVANCED_BROADCAST     32801
+#define ID_FIND_CHANNELS                32808
+#define ID_POPUP_SHOWMESSAGES_PEERCAST  32814
+#define ID_POPUP_SHOWMESSAGES_BROADCASTERS 32815
+#define ID_POPUP_SHOWMESSAGES_TRACKINFO 32816
+#define ID_POPUP_POPUPMESSAGES_UPGRADEALERTS 32817
+#define ID_POPUP_YELLOWPAGES            32818
+#define ID_POPUP_ADVANCED_SHOWGUI       32819
+#define ID_POPUP_YELLOWPAGES1           32820
+#define ID_POPUP_YELLOWPAGES2           32821
+#define ID_POPUP_SAVE_GUI_POS           32823
+#define ID_POPUP_KEEP_DOWNSTREAMS       32825
+#define IDC_STATIC                      -1
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        142
+#define _APS_NEXT_COMMAND_VALUE         32826
+#define _APS_NEXT_CONTROL_VALUE         1019
+#define _APS_NEXT_SYMED_VALUE           110
+#endif
+#endif
diff --git a/PeerCast.root/PeerCast/ui/win32/simple/small1.ico b/PeerCast.root/PeerCast/ui/win32/simple/small1.ico
new file mode 100644 (file)
index 0000000..fa5a5dc
Binary files /dev/null and b/PeerCast.root/PeerCast/ui/win32/simple/small1.ico differ
diff --git a/PeerCast.root/PeerCast/ui/win32/simple/small3.ico b/PeerCast.root/PeerCast/ui/win32/simple/small3.ico
new file mode 100644 (file)
index 0000000..c7dee29
Binary files /dev/null and b/PeerCast.root/PeerCast/ui/win32/simple/small3.ico differ
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/asf.h b/c:/Git/PeerCast.root/PeerCast/core/common/asf.h
new file mode 100644 (file)
index 0000000..fcd1e3d
--- /dev/null
@@ -0,0 +1,290 @@
+// ------------------------------------------------
+// File : asf.h
+// Date: 10-apr-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _ASF_H
+#define _ASF_H
+
+
+#include "stream.h"
+
+// -----------------------------------
+class MSID
+{
+public:
+
+       void read(Stream &in)
+       {
+               data1 = in.readLong();
+               data2 = in.readShort();
+               data3 = in.readShort();
+               in.read(data4,8);
+       }
+
+       void write(Stream &out)
+       {
+               out.writeLong(data1);
+               out.writeShort(data2);
+               out.writeShort(data3);
+               out.write(data4,8);
+       }
+       
+       
+       void toString(String &s)
+       {
+               sprintf(s.data,"%X-%X-%X-%02X%02X%02X%02X%02X%02X%02X%02X",
+                       data1,data2,data3,
+                       data4[0],data4[1],data4[2],data4[3],
+                       data4[4],data4[5],data4[6],data4[7]);
+       }
+
+    int operator==(const MSID& msid) const{return !memcmp(this, &msid, sizeof(MSID));}
+
+       unsigned int data1;
+       unsigned short data2,data3;
+       unsigned char data4[8];
+
+};
+
+
+
+
+// -----------------------------------
+const MSID headObjID=
+       {0x75B22630, 0x668E, 0x11CF, 0xA6,0xD9,0x00,0xAA,0x00,0x62,0xCE,0x6C};
+const MSID dataObjID=
+       {0x75B22636, 0x668E, 0x11CF, 0xA6,0xD9,0x00,0xAA,0x00,0x62,0xCE,0x6C};
+const MSID filePropObjID=
+       {0x8CABDCA1, 0xA947, 0x11CF, 0x8E,0xE4,0x00,0xC0,0x0C,0x20,0x53,0x65};
+const MSID streamPropObjID=
+       {0xB7DC0791, 0xA9B7, 0x11CF, 0x8E,0xE6,0x00,0xC0,0x0C,0x20,0x53,0x65};
+
+const MSID audioStreamObjID=
+       {0xF8699E40, 0x5B4D, 0x11CF, 0xA8,0xFD,0x00,0x80,0x5F,0x5C,0x44,0x2B};
+const MSID videoStreamObjID=
+       {0xBC19EFC0, 0x5B4D, 0x11CF, 0xA8,0xFD,0x00,0x80,0x5F,0x5C,0x44,0x2B};
+
+const MSID streamBitrateObjID=
+       {0x7BF875CE, 0x468D, 0x11D1, 0x8D,0x82,0x00,0x60,0x97,0xC9,0xA2,0xB2};
+
+
+// -----------------------------------
+class ASFObject
+{
+public:
+
+       enum TYPE
+       {
+               T_UNKNOWN,
+               T_HEAD_OBJECT,
+               T_DATA_OBJECT,
+               T_FILE_PROP,
+               T_STREAM_PROP,
+               T_STREAM_BITRATE
+       };
+
+       int getTotalLen()
+       {
+               return 24+dataLen;
+       }
+
+       unsigned int readHead(Stream &in)
+       {
+               id.read(in);
+
+               lenLo = in.readLong();
+               lenHi = in.readLong();
+
+               type = T_UNKNOWN;
+               if (id == headObjID)
+                       type = T_HEAD_OBJECT;
+               else if (id == dataObjID)
+                       type = T_DATA_OBJECT;
+               else if (id == filePropObjID)
+                       type = T_FILE_PROP;
+               else if (id == streamPropObjID)
+                       type = T_STREAM_PROP;
+               else if (id == streamBitrateObjID)
+                       type = T_STREAM_BITRATE;
+
+               String str;
+               id.toString(str);
+               LOG_DEBUG("ASF: %s (%s)= %d : %d\n",str.data,getTypeName(),lenLo,lenHi);
+
+
+               dataLen = 0;
+
+               return lenLo-24;
+       }
+
+       void readData(Stream &in,int len)
+       {
+               dataLen = len;
+
+               if ((dataLen > sizeof(data)) || (lenHi)) 
+                       throw StreamException("ASF object too big");
+
+               in.read(data,dataLen);
+       }
+
+
+       void write(Stream &out)
+       {
+               id.write(out);
+               out.writeLong(lenLo);
+               out.writeLong(lenHi);
+               if (dataLen)
+                       out.write(data,dataLen);
+       }
+
+       const char *getTypeName()
+       {
+               switch(type)
+               {
+                       case T_HEAD_OBJECT:
+                               return "ASF_Header_Object";
+                       case T_DATA_OBJECT:
+                               return "ASF_Data_Object";
+                       case T_FILE_PROP:
+                               return "ASF_File_Properties_Object";
+                       case T_STREAM_PROP:
+                               return "ASF_Stream_Properties_Object";
+                       case T_STREAM_BITRATE:
+                               return "ASF_Stream_Bitrate_Properties_Object";
+                       default:
+                               return "Unknown_Object";
+               }
+       }
+
+       char data[8192];
+       MSID    id;
+       unsigned int lenLo,lenHi,dataLen;
+       TYPE type;
+};
+// -----------------------------------
+class ASFStream
+{
+public:
+       enum TYPE
+       {
+               T_UNKNOWN,
+               T_AUDIO,
+               T_VIDEO
+       };
+
+       void read(Stream &in)
+       {
+               MSID sid;
+               sid.read(in);
+
+               if (sid == videoStreamObjID)
+                       type = T_VIDEO;
+               else if (sid == audioStreamObjID)
+                       type = T_AUDIO;
+               else 
+                       type = T_UNKNOWN;
+
+               in.skip(32);
+               id = in.readShort()&0x7f;
+       }
+
+
+       const char *getTypeName()
+       {
+               switch(type)
+               {
+                       case T_VIDEO:
+                               return "Video";
+                       case T_AUDIO:
+                               return "Audio";
+               }
+               return "Unknown";
+       }
+
+       void reset()
+       {
+               id = 0;
+               bitrate = 0;
+               type = T_UNKNOWN;
+       }
+
+       unsigned int id;
+       int bitrate;
+       TYPE type;
+};
+
+// -----------------------------------
+class ASFInfo
+{
+public:
+       enum
+       {
+               MAX_STREAMS = 128
+       };
+
+       ASFInfo()
+       {
+               numPackets = 0;
+               packetSize = 0;
+               flags = 0;
+               bitrate=0;
+               for(int i=0; i<MAX_STREAMS; i++)
+                       streams[i].reset();
+       }
+
+       unsigned int packetSize,numPackets,flags,bitrate;
+
+       ASFStream streams[MAX_STREAMS];
+};
+
+// -----------------------------------
+class ASFChunk
+{
+public:
+
+       void read(Stream &in)
+       {
+               type = in.readShort();
+               len = in.readShort();
+               seq = in.readLong();
+               v1 = in.readShort();
+               v2 = in.readShort();
+
+               dataLen = len-8;
+               if (dataLen > sizeof(data)) 
+                       throw StreamException("ASF chunk too big");
+               in.read(data,dataLen);
+       }
+
+       void write(Stream &out)
+       {
+               out.writeShort(type);
+               out.writeShort(len);
+               out.writeLong(seq);
+               out.writeShort(v1);
+               out.writeShort(v2);
+               out.write(data,dataLen);
+       }
+
+       unsigned int seq,dataLen;
+       unsigned short type,len,v1,v2;
+       unsigned char data[8192];
+};
+
+
+#endif
+
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/atom.h b/c:/Git/PeerCast.root/PeerCast/core/common/atom.h
new file mode 100644 (file)
index 0000000..94d8e46
--- /dev/null
@@ -0,0 +1,208 @@
+// ------------------------------------------------
+// File : atom.h
+// Date: 1-mar-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _ATOM_H
+#define _ATOM_H
+
+#include "stream.h"
+
+#include "id.h"
+
+// ------------------------------------------------
+class AtomStream
+{
+public:
+       AtomStream(Stream &s) : io(s),numChildren(0),numData(0)
+       {}
+
+       void checkData(int d)
+       {
+               if (numData != d)
+                       throw StreamException("Bad atom data");
+       }
+
+       void writeParent(ID4 id,int nc)
+       {
+               io.writeID4(id);
+               io.writeInt(nc|0x80000000);
+       }
+
+       void writeInt(ID4 id,int d)
+       {
+               io.writeID4(id);
+               io.writeInt(4);
+               io.writeInt(d);
+       }
+       
+       void writeID4(ID4 id,ID4 d)
+       {
+               io.writeID4(id);
+               io.writeInt(4);
+               io.writeID4(d);
+       }
+
+       void writeShort(ID4 id,short d)
+       {
+               io.writeID4(id);
+               io.writeInt(2);
+               io.writeShort(d);
+       }
+
+       void writeChar(ID4 id,char d)
+       {
+               io.writeID4(id);
+               io.writeInt(1);
+               io.writeChar(d);
+       }
+
+       void writeBytes(ID4 id,const void *p,int l)
+       {
+               io.writeID4(id);
+               io.writeInt(l);
+               io.write(p,l);
+       }
+
+
+       int writeStream(ID4 id,Stream &in,int l)
+       {
+               io.writeID4(id);
+               io.writeInt(l);
+               in.writeTo(io,l);
+               return (sizeof(int)*2)+l;
+
+       }
+
+       void writeString(ID4 id,const char *p)
+       {
+               writeBytes(id,p,strlen(p)+1);
+       }
+
+       ID4     read(int &numc,int &dlen)
+       {
+               ID4 id = io.readID4();
+
+               unsigned int v = io.readInt();
+               if (v & 0x80000000)
+               {
+                       numc = v&0x7fffffff;
+                       dlen = 0;
+               }else
+               {
+                       numc = 0;
+                       dlen = v;
+               }
+
+               numChildren = numc;
+               numData = dlen;
+
+               return id;
+       }
+
+       void skip(int c, int d)
+       {
+               if (d)
+                       io.skip(d);
+
+               for(int i=0; i<c; i++)
+               {
+                       int numc,data;
+                       read(numc,data);
+                       skip(numc,data);
+               }
+
+       }
+
+       int             readInt() 
+       {
+               checkData(4);
+               return io.readInt();
+       }
+       int             readID4() 
+       {
+               checkData(4);
+               return io.readID4();
+       }
+
+       int             readShort() 
+       {
+               checkData(2);
+               return io.readShort();
+       }
+       int             readChar() 
+       {
+               checkData(1);
+               return io.readChar();
+       }
+       int             readBytes(void *p,int l) 
+       {
+               checkData(l);
+               return io.read(p,l);
+       }
+
+       void    readString(char *s,int max,int dlen)
+       {
+               checkData(dlen);
+               readBytes(s,max,dlen);
+               s[max-1] = 0;
+
+       }
+
+       void    readBytes(void *s,int max,int dlen)
+       {
+               checkData(dlen);
+               if (max > dlen)
+                       readBytes(s,dlen);
+               else
+               {
+                       readBytes(s,max);
+                       io.skip(dlen-max);
+               }
+       }
+
+       int             writeAtoms(ID4 id, Stream &in, int cnt, int data)
+       {
+               int total=0;
+
+               if (cnt)
+               {
+                       writeParent(id,cnt);
+                       total+=sizeof(int)*2;
+
+                       for(int i=0; i<cnt; i++)
+                       {
+                               AtomStream ain(in);
+                               int c,d;
+                               ID4 cid = ain.read(c,d);
+                               total += writeAtoms(cid,in,c,d);
+                       }
+               }else
+               {
+                       total += writeStream(id,in,data);
+               }
+
+               return total;
+       }
+
+       bool    eof() {return io.eof();}        
+
+
+       int     numChildren,numData;
+       Stream &io;
+};
+
+#endif
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/channel.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/channel.cpp
new file mode 100644 (file)
index 0000000..f80f0da
--- /dev/null
@@ -0,0 +1,4608 @@
+// ------------------------------------------------
+// File : channel.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             Channel streaming classes. These do the actual 
+//             streaming of media between clients. 
+//
+// (c) 2002 peercast.org
+// 
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include <string.h>
+#include <stdlib.h>
+#include "common.h"
+#include "socket.h"
+#include "channel.h"
+#include "gnutella.h"
+#include "servent.h"
+#include "servmgr.h"
+#include "sys.h"
+#include "xml.h"
+#include "http.h"
+#include "peercast.h"
+#include "atom.h"
+#include "pcp.h"
+
+#include "mp3.h"
+#include "ogg.h"
+#include "mms.h"
+#include "nsv.h"
+
+#include "icy.h"
+#include "url.h"
+
+#include "version2.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// -----------------------------------
+char *Channel::srcTypes[]=
+{
+       "NONE",
+       "PEERCAST",
+       "SHOUTCAST",
+       "ICECAST",
+       "URL"
+};
+// -----------------------------------
+char *Channel::statusMsgs[]=
+{
+       "NONE",
+       "WAIT",
+       "CONNECT",
+       "REQUEST",
+       "CLOSE",
+       "RECEIVE",
+       "BROADCAST",
+       "ABORT",
+       "SEARCH",
+       "NOHOSTS",
+       "IDLE",
+       "ERROR",
+       "NOTFOUND"
+};
+
+
+// for PCRaw start.
+bool isIndexTxt(ChanInfo *info)
+{
+       int len;
+
+       if(     info &&
+               info->contentType == ChanInfo::T_RAW &&
+               info->bitrate <= 32 &&
+               (len = strlen(info->name.cstr())) >= 9 &&
+               !memcmp(info->name.cstr(), "index", 5) &&
+               !memcmp(info->name.cstr()+len-4, ".txt", 4))
+       {
+               return true;
+       }
+       else
+       {
+               return false;
+       }
+}
+
+bool isIndexTxt(Channel *ch)
+{
+       if(ch && !ch->isBroadcasting() && isIndexTxt(&ch->info))
+               return true;
+       else
+               return false;
+}
+
+int numMaxRelaysIndexTxt(Channel *ch)
+{
+       return ((servMgr->maxRelaysIndexTxt < 1) ? 1 : servMgr->maxRelaysIndexTxt);
+}
+
+int canStreamIndexTxt(Channel *ch)
+{
+       int ret;
+
+       // \8e©\95ª\82ª\94z\90M\82µ\82Ä\82¢\82é\8fê\8d\87\82Í\8aÖ\8cW\82È\82¢
+       if(!ch || ch->isBroadcasting())
+               return -1;
+
+       ret = numMaxRelaysIndexTxt(ch) - ch->localRelays();
+       if(ret < 0)
+               ret = 0;
+
+       return ret;
+}
+// for PCRaw end.
+
+// -----------------------------------
+void readXMLString(String &str, XML::Node *n, const char *arg)
+{
+       char *p;
+       p = n->findAttr(arg);
+       if (p)
+       {
+               str.set(p,String::T_HTML);
+               str.convertTo(String::T_ASCII);
+       }
+}
+
+int channel_count=1;
+// -----------------------------------------------------------------------------
+// Initialise the channel to its default settings of unallocated and reset.
+// -----------------------------------------------------------------------------
+Channel::Channel()
+{
+       next = NULL;
+       reset();
+       channel_id = channel_count++;
+}
+// -----------------------------------------------------------------------------
+void Channel::endThread(bool flg)
+{
+       if (pushSock)
+       {
+               pushSock->close();
+               delete pushSock;
+               pushSock = NULL;
+       }
+
+       if (sock)
+       {
+               sock->close();
+               sock = NULL;
+       }
+
+       if (sourceData)
+       {
+               delete sourceData;
+               sourceData = NULL;
+       }
+
+       if (flg == true){
+               reset();
+
+               chanMgr->channellock.on();
+               chanMgr->deleteChannel(this);
+               chanMgr->channellock.off();
+
+               sys->endThread(&thread);
+       }
+}
+// -----------------------------------------------------------------------------
+void Channel::resetPlayTime()
+{
+       info.lastPlayStart = sys->getTime();
+}
+// -----------------------------------------------------------------------------
+void Channel::setStatus(STATUS s)
+{
+       if (s != status)
+       {
+               bool wasPlaying = isPlaying();
+
+               status = s;
+
+               if (isPlaying())
+               {
+                       info.status = ChanInfo::S_PLAY;
+                       resetPlayTime();
+               }else
+               {
+                       if (wasPlaying)
+                               info.lastPlayEnd = sys->getTime();
+                       info.status = ChanInfo::S_UNKNOWN;
+               }
+
+               if (isBroadcasting())
+               {
+                       ChanHitList *chl = chanMgr->findHitListByID(info.id);
+                       if (!chl)
+                               chanMgr->addHitList(info);
+               }
+
+               peercastApp->channelUpdate(&info);
+
+       }
+}
+       
+// -----------------------------------------------------------------------------
+// Reset channel and make it available 
+// -----------------------------------------------------------------------------
+void Channel::reset()
+{
+       sourceHost.init();
+       remoteID.clear();
+
+       streamIndex = 0;
+
+       lastIdleTime = 0;
+
+       info.init();
+
+       mount.clear();
+       bump = false;
+       stayConnected = false;
+
+       icyMetaInterval = 0;
+       streamPos = 0;
+       skipCount = 0; //JP-EX
+       lastSkipTime = 0;
+
+       insertMeta.init();
+
+       headPack.init();
+
+       sourceStream = NULL;
+
+       rawData.init();
+       rawData.accept = ChanPacket::T_HEAD|ChanPacket::T_DATA;
+
+       setStatus(S_NONE);
+       type = T_NONE;
+
+       readDelay = false;
+       sock = NULL;
+       pushSock = NULL;
+
+       sourceURL.clear();
+       sourceData = NULL;
+
+       lastTrackerUpdate = 0;
+       lastMetaUpdate = 0;
+
+       srcType = SRC_NONE;
+
+
+       startTime = 0;
+       syncTime = 0;
+
+       channel_id = 0;
+       finthread = NULL;
+
+       trackerHit.init();
+}
+
+// -----------------------------------
+void   Channel::newPacket(ChanPacket &pack)
+{
+       if (pack.type != ChanPacket::T_PCP)
+       {
+               rawData.writePacket(pack,true);
+       }
+}
+
+
+// -----------------------------------
+bool   Channel::checkIdle()
+{
+       return ( (info.getUptime() > chanMgr->prefetchTime) && (localListeners() == 0) && (!stayConnected) && (status != S_BROADCASTING));
+}
+
+// -----------------------------------
+bool   Channel::isFull()
+{
+       // for PCRaw (relay) start.
+       if(isIndexTxt(this))
+       {
+               int ret = canStreamIndexTxt(this);
+               
+               if(ret > 0)
+                       return false;
+               else if(ret == 0)
+                       return true;
+       }
+       // for PCRaw (relay) end.
+
+       return chanMgr->maxRelaysPerChannel ? localRelays() >= chanMgr->maxRelaysPerChannel : false;
+}
+// -----------------------------------
+int Channel::localRelays()
+{
+       return servMgr->numStreams(info.id,Servent::T_RELAY,true);
+}
+// -----------------------------------
+int Channel::localListeners()
+{
+       return servMgr->numStreams(info.id,Servent::T_DIRECT,true);
+}
+
+// -----------------------------------
+int Channel::totalRelays()
+{
+       int tot = 0;
+       ChanHitList *chl = chanMgr->findHitListByID(info.id);
+       if (chl)
+               tot += chl->numHits();
+       return tot;
+}
+// -----------------------------------
+int Channel::totalListeners()
+{
+       int tot = localListeners();
+       ChanHitList *chl = chanMgr->findHitListByID(info.id);
+       if (chl)
+               tot += chl->numListeners();
+       return tot;
+}
+
+
+
+
+// -----------------------------------
+void   Channel::startGet()
+{
+       srcType = SRC_PEERCAST;
+       type = T_RELAY;
+       info.srcProtocol = ChanInfo::SP_PCP;
+
+
+       sourceData = new PeercastSource();
+
+       startStream();
+}
+// -----------------------------------
+void   Channel::startURL(const char *u)
+{
+       sourceURL.set(u);
+
+       srcType = SRC_URL;
+       type = T_BROADCAST;
+       stayConnected = true;
+
+       resetPlayTime();
+
+       sourceData = new URLSource(u);
+
+       startStream();
+
+}
+// -----------------------------------
+void Channel::startStream()
+{
+       thread.data = this;
+       thread.func = stream;
+       if (!sys->startThread(&thread))
+               reset();
+}
+
+// -----------------------------------
+void Channel::sleepUntil(double time)
+{
+       double sleepTime = time - (sys->getDTime()-startTime);
+
+//     LOG("sleep %g",sleepTime);
+       if (sleepTime > 0)
+       {
+               if (sleepTime > 60) sleepTime = 60;
+
+               double sleepMS = sleepTime*1000;
+
+               sys->sleep((int)sleepMS);
+       }
+}
+
+
+// -----------------------------------
+void Channel::checkReadDelay(unsigned int len)
+{
+       if (readDelay)
+       {
+               unsigned int time = (len*1000)/((info.bitrate*1024)/8);
+               sys->sleep(time);
+       }
+
+
+}
+
+
+// -----------------------------------
+THREAD_PROC    Channel::stream(ThreadInfo *thread)
+{
+//     thread->lock();
+
+       Channel *ch = (Channel *)thread->data;
+
+       LOG_CHANNEL("Channel started");
+
+       while (thread->active && !peercastInst->isQuitting && !thread->finish)
+       {
+               ChanHitList *chl = chanMgr->findHitList(ch->info);
+               if (!chl)
+                       chanMgr->addHitList(ch->info);
+
+               ch->sourceData->stream(ch);
+
+               LOG_CHANNEL("Channel stopped");
+               ch->rawData.init();
+
+               if (!ch->stayConnected)
+               {
+                       thread->active = false;
+                       break;
+               }else
+               {
+                       if (!ch->info.lastPlayEnd)
+                               ch->info.lastPlayEnd = sys->getTime();
+
+                       unsigned int diff = (sys->getTime()-ch->info.lastPlayEnd) + 5;
+
+                       LOG_DEBUG("Channel sleeping for %d seconds",diff);
+                       for(unsigned int i=0; i<diff; i++)
+                       {
+                               if (!thread->active || peercastInst->isQuitting){
+                                       thread->active = false;
+                                       break;
+                               }
+                               sys->sleep(1000);       
+                       }
+               }
+       }
+
+       LOG_DEBUG("thread.active = %d, thread.finish = %d",
+               ch->thread.active, ch->thread.finish);
+
+       if (!thread->finish){
+               ch->endThread(false);
+
+               if (!ch->finthread){
+                       ch->finthread = new ThreadInfo();
+                       ch->finthread->func = waitFinish;
+                       ch->finthread->data = ch;
+                       sys->startThread(ch->finthread);
+               }
+       } else {
+               ch->endThread(true);
+       }
+       return 0;
+}      
+
+// -----------------------------------
+THREAD_PROC Channel::waitFinish(ThreadInfo *thread)
+{
+       Channel *ch = (Channel*)thread->data;
+       LOG_DEBUG("Wait channel finish");
+
+       while(!(ch->thread.finish) && !thread->finish){
+               sys->sleep(1000);
+       }
+
+       if (ch->thread.finish){
+               LOG_DEBUG("channel finish");
+               ch->endThread(true);
+       } else {
+               LOG_DEBUG("channel restart");
+       }
+
+       delete thread;
+       return 0;
+}
+
+// -----------------------------------
+bool Channel::acceptGIV(ClientSocket *givSock)
+{
+       if (!pushSock)
+       {
+               pushSock = givSock;
+               return true;
+       }else
+               return false;
+}
+// -----------------------------------
+void Channel::connectFetch()
+{
+       sock = sys->createSocket();
+       
+       if (!sock)
+               throw StreamException("Can`t create socket");
+
+       if (sourceHost.tracker || sourceHost.yp)
+       {
+               sock->setReadTimeout(30000);
+               sock->setWriteTimeout(30000);
+               LOG_CHANNEL("Channel using longer timeouts");
+       } else {
+               sock->setReadTimeout(5000);
+               sock->setWriteTimeout(5000);
+       }
+
+       sock->open(sourceHost.host);
+               
+       sock->connect();
+}
+
+// -----------------------------------
+int Channel::handshakeFetch()
+{
+       char idStr[64];
+       info.id.toStr(idStr);
+
+       char sidStr[64];
+       servMgr->sessionID.toStr(sidStr);
+
+       sock->writeLineF("GET /channel/%s HTTP/1.0",idStr);
+       sock->writeLineF("%s %d",PCX_HS_POS,streamPos);
+       sock->writeLineF("%s %d",PCX_HS_PCP,1);
+
+       sock->writeLine("");
+
+       HTTP http(*sock);
+
+       int r = http.readResponse();
+
+       LOG_CHANNEL("Got response: %d",r);
+
+       while (http.nextHeader())
+       {
+               char *arg = http.getArgStr();
+               if (!arg) 
+                       continue;
+
+               if (http.isHeader(PCX_HS_POS))
+                       streamPos = atoi(arg);
+               else
+                       Servent::readICYHeader(http, info, NULL);
+
+               LOG_CHANNEL("Channel fetch: %s",http.cmdLine);
+       }
+
+       if ((r != 200) && (r != 503))
+               return r;
+
+       if (!servMgr->keepDownstreams) {
+               if (rawData.getLatestPos() > streamPos)
+                       rawData.init();
+       }
+
+       AtomStream atom(*sock);
+
+       String agent;
+
+       Host rhost = sock->host;
+
+       if (info.srcProtocol == ChanInfo::SP_PCP)
+       {
+               // don`t need PCP_CONNECT here
+               Servent::handshakeOutgoingPCP(atom,rhost,remoteID,agent,sourceHost.yp|sourceHost.tracker);
+       }
+
+       if (r == 503) return 503;
+       return 0;
+
+}
+
+// -----------------------------------
+void PeercastSource::stream(Channel *ch)
+{
+       int numYPTries=0;
+       int numYPTries2=0;
+       bool next_yp = false;
+       bool tracker_check = (ch->trackerHit.host.ip != 0);
+       int connFailCnt = 0;
+
+       ch->lastStopTime = 0;
+       ch->bumped = false;
+
+       while (ch->thread.active)
+       {
+               ch->skipCount = 0; //JP-EX
+               ch->lastSkipTime = 0;
+               
+               ChanHitList *chl = NULL;
+
+               ch->sourceHost.init();
+
+               if (connFailCnt >= 3 && (ch->localListeners() == 0) && (!ch->stayConnected) && !ch->isBroadcasting()) {
+                       ch->lastIdleTime = sys->getTime();
+                       ch->setStatus(Channel::S_IDLE);
+                       ch->skipCount = 0;
+                       ch->lastSkipTime = 0;
+                       break;
+               }
+
+               if (!servMgr->keepDownstreams && !ch->bumped) {
+                       ch->trackerHit.lastContact = sys->getTime() - 30 + (rand() % 30);
+               }
+
+               ch->setStatus(Channel::S_SEARCHING);
+               LOG_CHANNEL("Channel searching for hit..");
+               do 
+               {
+       
+                       if (ch->pushSock)
+                       {
+                               ch->sock = ch->pushSock;
+                               ch->pushSock = NULL;
+                               ch->sourceHost.host = ch->sock->host;
+                               break;
+                       }
+
+                       chanMgr->hitlistlock.on();
+
+                       chl = chanMgr->findHitList(ch->info);
+                       if (chl)
+                       {
+                               ChanHitSearch chs;
+
+                               // find local hit 
+                               if (!ch->sourceHost.host.ip){
+                                       chs.init();
+                                       chs.matchHost = servMgr->serverHost;
+                                       chs.waitDelay = MIN_RELAY_RETRY;
+                                       chs.excludeID = servMgr->sessionID;
+                                       if (chl->pickSourceHits(chs)){
+                                               ch->sourceHost = chs.best[0];
+                                               LOG_DEBUG("use local hit");
+                                       }
+                               }
+                               
+                               // else find global hit
+                               if (!ch->sourceHost.host.ip)
+                               {
+                                       chs.init();
+                                       chs.waitDelay = MIN_RELAY_RETRY;
+                                       chs.excludeID = servMgr->sessionID;
+                                       if (chl->pickSourceHits(chs)){
+                                               ch->sourceHost = chs.best[0];
+                                               LOG_DEBUG("use global hit");
+                                       }
+                               }
+
+
+                               // else find local tracker
+                               if (!ch->sourceHost.host.ip)
+                               {
+                                       chs.init();
+                                       chs.matchHost = servMgr->serverHost;
+                                       chs.waitDelay = MIN_TRACKER_RETRY;
+                                       chs.excludeID = servMgr->sessionID;
+                                       chs.trackersOnly = true;
+                                       if (chl->pickSourceHits(chs)){
+                                               ch->sourceHost = chs.best[0];
+                                               LOG_DEBUG("use local tracker");
+                                       }
+                               }
+
+                               // find tracker
+                               unsigned int ctime = sys->getTime();
+                               if (!ch->sourceHost.host.ip && tracker_check && ch->trackerHit.host.ip){
+                                       if (ch->trackerHit.lastContact + 30 < ctime){
+                                               ch->sourceHost = ch->trackerHit;
+                                               ch->trackerHit.lastContact = ctime;
+                                               LOG_DEBUG("use saved tracker");
+                                       }
+                               }
+
+                               // else find global tracker
+                               if (!ch->sourceHost.host.ip)
+                               {
+                                       chs.init();
+                                       chs.waitDelay = MIN_TRACKER_RETRY;
+                                       chs.excludeID = servMgr->sessionID;
+                                       chs.trackersOnly = true;
+                                       if (chl->pickSourceHits(chs)){
+                                               ch->sourceHost = chs.best[0];
+                                               tracker_check = true;
+                                               ch->trackerHit = chs.best[0];
+                                               LOG_DEBUG("use global tracker");
+                                       }
+                               }
+                       }
+
+                       chanMgr->hitlistlock.off();
+
+                       if (servMgr->keepDownstreams && ch->lastStopTime && ch->lastStopTime < sys->getTime() - 7) {
+                               ch->lastStopTime = 0;
+                               LOG_DEBUG("------------ disconnect all downstreams");
+                               ChanPacket pack;
+                               MemoryStream mem(pack.data,sizeof(pack.data));
+                               AtomStream atom(mem);
+                               atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_OFFAIR);
+                               pack.len = mem.pos;
+                               pack.type = ChanPacket::T_PCP;
+                               GnuID noID;
+                               noID.clear();
+                               servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY);
+
+                               chanMgr->hitlistlock.on();
+                               ChanHitList *hl = chanMgr->findHitList(ch->info);
+                               if (hl){
+                                       hl->clearHits(false);
+                               }
+                               chanMgr->hitlistlock.off();
+                       }
+
+                       // no trackers found so contact YP
+                       if (!tracker_check && !ch->sourceHost.host.ip)
+                       {
+                               next_yp = false;
+                               if (servMgr->rootHost.isEmpty())
+                                       goto yp2;
+
+                               if (numYPTries >= 3)
+                                       goto yp2;
+
+                               if  ((!servMgr->rootHost2.isEmpty()) && (numYPTries > numYPTries2))
+                                       goto yp2;
+
+                               unsigned int ctime=sys->getTime();
+                               if ((ctime-chanMgr->lastYPConnect) > MIN_YP_RETRY)
+                               {
+                                       ch->sourceHost.host.fromStrName(servMgr->rootHost.cstr(),DEFAULT_PORT);
+                                       ch->sourceHost.yp = true;
+                                       chanMgr->lastYPConnect=ctime;
+                                       numYPTries++;
+                               }
+                               if (numYPTries < 3)
+                                       next_yp = true;
+                       }
+
+yp2:
+                       // no trackers found so contact YP2
+                       if (!tracker_check && !ch->sourceHost.host.ip)
+                       {
+//                             next_yp = false;
+                               if (servMgr->rootHost2.isEmpty())
+                                       goto yp0;
+
+                               if (numYPTries2 >= 3)
+                                       goto yp0;
+
+                               unsigned int ctime=sys->getTime();
+                               if ((ctime-chanMgr->lastYPConnect2) > MIN_YP_RETRY)
+                               {
+                                       ch->sourceHost.host.fromStrName(servMgr->rootHost2.cstr(),DEFAULT_PORT);
+                                       ch->sourceHost.yp = true;
+                                       chanMgr->lastYPConnect2=ctime;
+                                       numYPTries2++;
+                               }
+                               if (numYPTries2 < 3)
+                                       next_yp = true;
+                       }
+yp0:
+                       if (!tracker_check && !ch->sourceHost.host.ip && !next_yp) break;
+
+                       sys->sleepIdle();
+
+               }while((ch->sourceHost.host.ip==0) && (ch->thread.active));
+
+               if (!ch->sourceHost.host.ip)
+               {
+                       LOG_ERROR("Channel giving up");
+                       ch->setStatus(Channel::S_ERROR);                        
+                       break;
+               }
+
+               if (ch->sourceHost.yp)
+               {
+                       LOG_CHANNEL("Channel contacting YP, try %d",numYPTries);
+               }else
+               {
+                       LOG_CHANNEL("Channel found hit");
+                       numYPTries=0;
+                       numYPTries2=0;
+               }
+
+               if (ch->sourceHost.host.ip)
+               {
+                       bool isTrusted = ch->sourceHost.tracker | ch->sourceHost.yp;
+
+
+                       //if (ch->sourceHost.tracker)
+                       //      peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Contacting tracker, please wait...");
+                       
+                       char ipstr[64];
+                       ch->sourceHost.host.toStr(ipstr);
+
+                       char *type = "";
+                       if (ch->sourceHost.tracker)
+                               type = "(tracker)";
+                       else if (ch->sourceHost.yp)
+                               type = "(YP)";
+
+                       int error=-1;
+                       int got503 = 0;
+                       try
+                       {
+                               ch->setStatus(Channel::S_CONNECTING);
+                               ch->sourceHost.lastContact = sys->getTime();
+
+                               if (!ch->sock)
+                               {
+                                       LOG_CHANNEL("Channel connecting to %s %s",ipstr,type);
+                                       ch->connectFetch();
+                               }
+
+                               error = ch->handshakeFetch();
+                               if (error == 503) {
+                                       got503 = 1;
+                                       error = 0;
+                               }
+                               if (error)
+                                       throw StreamException("Handshake error");
+                               if (ch->sourceHost.tracker) connFailCnt = 0;
+
+                               if (servMgr->autoMaxRelaySetting) //JP-EX
+                               {       
+                                       double setMaxRelays = ch->info.bitrate?servMgr->maxBitrateOut/(ch->info.bitrate*1.3):0;
+                                       if ((unsigned int)setMaxRelays == 0)
+                                               servMgr->maxRelays = 1;
+                                       else if ((unsigned int)setMaxRelays > servMgr->autoMaxRelaySetting)
+                                               servMgr->maxRelays = servMgr->autoMaxRelaySetting;
+                                       else
+                                               servMgr->maxRelays = (unsigned int)setMaxRelays;
+                               }
+
+                               ch->sourceStream = ch->createSource();
+
+                               error = ch->readStream(*ch->sock,ch->sourceStream);
+                               if (error)
+                                       throw StreamException("Stream error");
+
+                               error = 0;              // no errors, closing normally.
+//                             ch->setStatus(Channel::S_CLOSING);                      
+                               ch->setStatus(Channel::S_IDLE);
+
+                               LOG_CHANNEL("Channel closed normally");
+                       }catch(StreamException &e)
+                       {
+                               ch->setStatus(Channel::S_ERROR);                        
+                               LOG_ERROR("Channel to %s %s : %s",ipstr,type,e.msg);
+                               if (!servMgr->allowConnectPCST) //JP-EX
+                               {
+                                       if (ch->info.srcProtocol == ChanInfo::SP_PEERCAST)
+                                               ch->thread.active = false;
+                               }
+                               //if (!ch->sourceHost.tracker || ((error != 503) && ch->sourceHost.tracker))
+                               if (!ch->sourceHost.tracker || (!got503 && ch->sourceHost.tracker))
+                                       chanMgr->deadHit(ch->sourceHost);
+                               if (ch->sourceHost.tracker && error == -1) {
+                                       LOG_ERROR("can't connect to tracker");
+                                       connFailCnt++;
+                               }
+                       }
+
+                       unsigned int ctime = sys->getTime();
+                       if (ch->rawData.lastWriteTime) {
+                               ch->lastStopTime = ch->rawData.lastWriteTime;
+                               if (isIndexTxt(ch) && ctime - ch->lastStopTime < 60)
+                                       ch->lastStopTime = ctime;
+                       }
+
+                       if (tracker_check && ch->sourceHost.tracker)
+                               ch->trackerHit.lastContact = ctime - 30 + (rand() % 30);
+
+                       // broadcast source host
+                       if (!error && ch->sourceHost.host.ip) { // if closed normally
+                               ChanPacket pack;
+                               MemoryStream mem(pack.data,sizeof(pack.data));
+                               AtomStream atom(mem);
+                               ch->sourceHost.writeAtoms(atom, ch->info.id);
+                               pack.len = mem.pos;
+                               pack.type = ChanPacket::T_PCP;
+                               GnuID noID;
+                               noID.clear();
+                               servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY);
+                               LOG_DEBUG("stream: broadcast sourceHost");
+                       }
+
+                       // broadcast quit to any connected downstream servents
+                       if (!servMgr->keepDownstreams || (ch->sourceHost.tracker && !got503) || !error) {
+                               ChanPacket pack;
+                               MemoryStream mem(pack.data,sizeof(pack.data));
+                               AtomStream atom(mem);
+                               atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_OFFAIR);
+                               pack.len = mem.pos;
+                               pack.type = ChanPacket::T_PCP;
+                               GnuID noID;
+                               noID.clear();
+                               servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY);
+                               LOG_DEBUG("------------ broadcast quit to all downstreams");
+
+                               chanMgr->hitlistlock.on();
+                               ChanHitList *hl = chanMgr->findHitList(ch->info);
+                               if (hl){
+                                       hl->clearHits(false);
+                               }
+                               chanMgr->hitlistlock.off();
+                       }
+
+
+                       if (ch->sourceStream)
+                       {
+                               try
+                               {
+                                       if (!error)
+                                       {
+                                               ch->sourceStream->updateStatus(ch);
+                                               ch->sourceStream->flush(*ch->sock);
+                                       }
+                               }catch(StreamException &)
+                               {}
+                               ChannelStream *cs = ch->sourceStream;
+                               ch->sourceStream = NULL;
+                               cs->kill();
+                               delete cs;
+                       }
+
+                       if (ch->sock)
+                       {
+                               ch->sock->close();
+                               delete ch->sock;
+                               ch->sock = NULL;
+                       }
+
+                       if (error == 404)
+                       {
+                               LOG_ERROR("Channel not found");
+                               //if (!next_yp){
+                               if ((ch->sourceHost.yp && !next_yp) || ch->sourceHost.tracker) {
+                                       chanMgr->hitlistlock.on();
+                                       ChanHitList *hl = chanMgr->findHitList(ch->info);
+                                       if (hl){
+                                               hl->clearHits(true);
+                                       }
+                                       chanMgr->hitlistlock.off();
+
+                                       if(!isIndexTxt(&ch->info))      // for PCRaw (popup)
+                                               peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Channel not found");
+                                       return;
+                               }
+                       }
+
+
+               }
+
+               ch->lastIdleTime = sys->getTime();
+               ch->setStatus(Channel::S_IDLE);
+               ch->skipCount = 0; //JP-EX
+               ch->lastSkipTime = 0;
+               while ((ch->checkIdle()) && (ch->thread.active))
+               {
+                       sys->sleepIdle();
+               }
+
+               sys->sleepIdle();
+       }
+
+}
+// -----------------------------------
+void   Channel::startICY(ClientSocket *cs, SRC_TYPE st)
+{
+       srcType = st;
+       type = T_BROADCAST;
+       cs->setReadTimeout(0);  // stay connected even when theres no data coming through
+       sock = cs;
+       info.srcProtocol = ChanInfo::SP_HTTP;
+
+       streamIndex = ++chanMgr->icyIndex;
+
+       sourceData = new ICYSource();
+       startStream();
+}
+
+// -----------------------------------
+static char *nextMetaPart(char *str,char delim)
+{
+       while (*str)
+       {
+               if (*str == delim)
+               {
+                       *str++ = 0;
+                       return str;
+               }
+               str++;
+       }
+       return NULL;
+}
+// -----------------------------------
+static void copyStr(char *to,char *from,int max)
+{
+       char c;
+       while ((c=*from++) && (--max))
+               if (c != '\'')
+                       *to++ = c;
+
+       *to = 0;
+}
+
+// -----------------------------------
+void Channel::processMp3Metadata(char *str)
+{
+       ChanInfo newInfo = info;
+       
+       char *cmd=str;
+       while (cmd)
+       {
+               char *arg = nextMetaPart(cmd,'=');
+               if (!arg)
+                       break;
+
+               char *next = nextMetaPart(arg,';');
+
+               if (strcmp(cmd,"StreamTitle")==0)
+               {
+                       newInfo.track.title.setUnquote(arg,String::T_ASCII);
+                       newInfo.track.title.convertTo(String::T_UNICODE);
+
+               }else if (strcmp(cmd,"StreamUrl")==0)
+               {
+                       newInfo.track.contact.setUnquote(arg,String::T_ASCII);
+                       newInfo.track.contact.convertTo(String::T_UNICODE);
+               }
+
+
+               cmd = next;
+       }
+
+       updateInfo(newInfo);
+}
+
+// -----------------------------------
+XML::Node *ChanHit::createXML()
+{
+       // IP
+       char ipStr[64];
+       host.toStr(ipStr);
+       
+       return new XML::Node("host ip=\"%s\" hops=\"%d\" listeners=\"%d\" relays=\"%d\" uptime=\"%d\" push=\"%d\" relay=\"%d\" direct=\"%d\" cin=\"%d\" stable=\"%d\" version=\"%d\" update=\"%d\" tracker=\"%d\"",
+               ipStr,
+               numHops,
+               numListeners,
+               numRelays,
+               upTime,
+               firewalled?1:0,
+               relay?1:0,
+               direct?1:0,
+               cin?1:0,
+               stable?1:0,
+               version,
+               sys->getTime()-time,
+               tracker
+               );
+
+}
+
+// -----------------------------------
+XML::Node *ChanHitList::createXML(bool addHits)
+{
+       XML::Node *hn = new XML::Node("hits hosts=\"%d\" listeners=\"%d\" relays=\"%d\" firewalled=\"%d\" closest=\"%d\" furthest=\"%d\" newest=\"%d\"",
+               numHits(),
+               numListeners(),
+               numRelays(),
+               numFirewalled(),
+               closestHit(),
+               furthestHit(),
+               sys->getTime()-newestHit()
+               );              
+
+       if (addHits)
+       {
+               ChanHit *h = hit;
+               while (h)
+               {
+                       if (h->host.ip)
+                               hn->add(h->createXML());
+                       h = h->next;
+               }
+       }
+
+       return hn;
+}
+
+// -----------------------------------
+XML::Node *Channel::createRelayXML(bool showStat)
+{
+       const char *ststr;
+       ststr = getStatusStr();
+       if (!showStat)
+               if ((status == S_RECEIVING) || (status == S_BROADCASTING))
+                       ststr = "OK";
+
+       ChanHitList *chl = chanMgr->findHitList(info);
+
+       return new XML::Node("relay listeners=\"%d\" relays=\"%d\" hosts=\"%d\" status=\"%s\"",
+               localListeners(),
+               localRelays(),
+               (chl!=NULL)?chl->numHits():0,
+               ststr
+               );      
+}
+
+// -----------------------------------
+void ChanMeta::fromXML(XML &xml)
+{
+       MemoryStream tout(data,MAX_DATALEN);
+       xml.write(tout);
+
+       len = tout.pos;
+}
+// -----------------------------------
+void ChanMeta::fromMem(void *p, int l)
+{
+       len = l;
+       memcpy(data,p,len);
+}
+// -----------------------------------
+void ChanMeta::addMem(void *p, int l)
+{
+       if ((len+l) <= MAX_DATALEN)
+       {
+               memcpy(data+len,p,l);
+               len += l;
+       }
+}
+// -----------------------------------
+void Channel::broadcastTrackerUpdate(GnuID &svID, bool force)
+{
+       unsigned int ctime = sys->getTime();
+
+       if (((ctime-lastTrackerUpdate) > 30) || (force))
+       {
+               ChanPacket pack;
+
+               MemoryStream mem(pack.data,sizeof(pack));
+
+               AtomStream atom(mem);
+                       
+               ChanHit hit;
+
+               ChanHitList *chl = chanMgr->findHitListByID(info.id);
+               if (!chl)
+                       throw StreamException("Broadcast channel has no hitlist");
+
+               int numListeners = totalListeners();
+               int numRelays = totalRelays();
+
+               unsigned int oldp = rawData.getOldestPos();
+               unsigned int newp = rawData.getLatestPos();
+
+               hit.initLocal(numListeners,numRelays,info.numSkips,info.getUptime(),isPlaying(), false, 0, this, oldp,newp);
+               hit.tracker = true;
+
+#ifndef VERSION_EX
+               atom.writeParent(PCP_BCST,8);
+#else
+               atom.writeParent(PCP_BCST,10);
+#endif
+                       atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_ROOT);
+                       atom.writeChar(PCP_BCST_HOPS,0);
+                       atom.writeChar(PCP_BCST_TTL,11);
+                       atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
+                       atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
+                       atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
+#ifdef VERSION_EX
+                       atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
+                       atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
+#endif
+                       atom.writeParent(PCP_CHAN,4);
+                               atom.writeBytes(PCP_CHAN_ID,info.id.id,16);
+                               atom.writeBytes(PCP_CHAN_BCID,chanMgr->broadcastID.id,16);
+                               info.writeInfoAtoms(atom);
+                               info.writeTrackAtoms(atom);
+                       hit.writeAtoms(atom,info.id);
+
+
+               pack.len = mem.pos;
+               pack.type = ChanPacket::T_PCP;
+
+               GnuID noID;
+               noID.clear();
+               int cnt = servMgr->broadcastPacket(pack,noID,servMgr->sessionID,svID,Servent::T_COUT);
+
+               if (cnt)
+               {
+                       LOG_DEBUG("Sent tracker update for %s to %d client(s)",info.name.cstr(),cnt);
+                       lastTrackerUpdate = ctime;
+               }
+       }
+}
+
+// -----------------------------------
+bool   Channel::sendPacketUp(ChanPacket &pack,GnuID &cid,GnuID &sid,GnuID &did)
+{
+       if ( isActive() 
+               && (!cid.isSet() || info.id.isSame(cid)) 
+               && (!sid.isSet() || !remoteID.isSame(sid))
+               && sourceStream 
+          )
+               return sourceStream->sendPacket(pack,did);
+
+       return false;
+}
+
+// -----------------------------------
+void Channel::updateInfo(ChanInfo &newInfo)
+{
+       if (info.update(newInfo))
+       {
+               if (isBroadcasting())
+               {
+                       unsigned int ctime = sys->getTime();
+                       if ((ctime-lastMetaUpdate) > 30)
+                       {
+                               lastMetaUpdate = ctime;
+
+                               ChanPacket pack;
+
+                               MemoryStream mem(pack.data,sizeof(pack));
+
+                               AtomStream atom(mem);
+
+#ifndef VERSION_EX
+                               atom.writeParent(PCP_BCST,8);
+#else
+                               atom.writeParent(PCP_BCST,10);
+#endif
+                                       atom.writeChar(PCP_BCST_HOPS,0);
+                                       atom.writeChar(PCP_BCST_TTL,7);
+                                       atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_RELAYS);
+                                       atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
+                                       atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
+                                       atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
+#ifdef VERSION_EX
+                                       atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
+                                       atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
+#endif
+                                       atom.writeBytes(PCP_BCST_CHANID,info.id.id,16);
+                                       atom.writeParent(PCP_CHAN,3);
+                                               atom.writeBytes(PCP_CHAN_ID,info.id.id,16);
+                                               info.writeInfoAtoms(atom);
+                                               info.writeTrackAtoms(atom);
+
+                               pack.len = mem.pos;
+                               pack.type = ChanPacket::T_PCP;
+                               GnuID noID;
+                               noID.clear();
+                               servMgr->broadcastPacket(pack,info.id,servMgr->sessionID,noID,Servent::T_RELAY);
+
+                               broadcastTrackerUpdate(noID);
+                       }
+               }
+
+               ChanHitList *chl = chanMgr->findHitList(info);
+               if (chl)
+                       chl->info = info;
+
+               peercastApp->channelUpdate(&info);
+
+       }
+
+}
+// -----------------------------------
+ChannelStream *Channel::createSource()
+{
+//     if (servMgr->relayBroadcast)
+//             chanMgr->broadcastRelays(NULL,chanMgr->minBroadcastTTL,chanMgr->maxBroadcastTTL);
+
+
+       ChannelStream *source=NULL;
+
+       if (info.srcProtocol == ChanInfo::SP_PEERCAST)
+       {
+               LOG_CHANNEL("Channel is Peercast");
+               if (servMgr->allowConnectPCST) //JP-EX
+                       source = new PeercastStream();
+               else
+                       throw StreamException("Channel is not allowed");
+       }
+       else if (info.srcProtocol == ChanInfo::SP_PCP)
+       {
+               LOG_CHANNEL("Channel is PCP");
+               PCPStream *pcp = new PCPStream(remoteID);
+               source = pcp;
+       }
+       else if (info.srcProtocol == ChanInfo::SP_MMS)
+       {
+               LOG_CHANNEL("Channel is MMS");
+               source = new MMSStream();
+       }else
+       {
+               switch(info.contentType)
+               {
+                       case ChanInfo::T_MP3:
+                               LOG_CHANNEL("Channel is MP3 - meta: %d",icyMetaInterval);
+                               source = new MP3Stream();
+                               break;
+                       case ChanInfo::T_NSV:
+                               LOG_CHANNEL("Channel is NSV");
+                               source = new NSVStream();
+                               break;
+                       case ChanInfo::T_WMA:
+                       case ChanInfo::T_WMV:
+                               throw StreamException("Channel is WMA/WMV - but not MMS");
+                               break;
+                       case ChanInfo::T_OGG:
+                       case ChanInfo::T_OGM:
+                               LOG_CHANNEL("Channel is OGG");
+                               source = new OGGStream();
+                               break;
+                       default:
+                               LOG_CHANNEL("Channel is Raw");
+                               source = new RawStream();
+                               break;
+               }
+       }
+
+       source->parent = this;
+
+       return source;
+}
+// ------------------------------------------
+void ChannelStream::updateStatus(Channel *ch)
+{
+       ChanPacket pack;
+       if (getStatus(ch,pack))
+       {
+               if (!ch->isBroadcasting())
+               {
+                       GnuID noID;
+                       noID.clear();
+                       int cnt = chanMgr->broadcastPacketUp(pack,ch->info.id,servMgr->sessionID,noID);
+                       LOG_CHANNEL("Sent channel status update to %d clients",cnt);
+               }
+       }
+}
+
+// ------------------------------------------
+bool ChannelStream::getStatus(Channel *ch,ChanPacket &pack)
+{
+       unsigned int ctime = sys->getTime();
+
+       ChanHitList *chl = chanMgr->findHitListByID(ch->info.id);
+
+       if (!chl)
+               return false;
+
+/*     int newLocalListeners = ch->localListeners();
+       int newLocalRelays = ch->localRelays();
+
+       if (
+               (
+               (numListeners != newLocalListeners) 
+               || (numRelays != newLocalRelays) 
+               || (ch->isPlaying() != isPlaying) 
+               || (servMgr->getFirewall() != fwState)
+               || (((ctime-lastUpdate)>chanMgr->hostUpdateInterval) && chanMgr->hostUpdateInterval)
+               )
+               && ((ctime-lastUpdate) > 10)
+          )
+       {
+
+               numListeners = newLocalListeners;
+               numRelays = newLocalRelays;
+               isPlaying = ch->isPlaying();
+               fwState = servMgr->getFirewall();
+               lastUpdate = ctime;
+
+               ChanHit hit;
+
+               hit.initLocal(ch->localListeners(),ch->localRelays(),ch->info.numSkips,ch->info.getUptime(),isPlaying, ch->isFull(), ch->info.bitrate, ch);
+               hit.tracker = ch->isBroadcasting();*/
+
+       int newLocalListeners = ch->localListeners();
+       int newLocalRelays = ch->localRelays();
+
+       if ((ch->isPlaying() == isPlaying)){
+               if ((ctime-lastUpdate) < 10){
+                       return false;
+               }
+
+               if ((ctime-lastCheckTime) < 10){
+                       return false;
+               }
+               lastCheckTime = ctime;
+       }
+
+       unsigned int oldp = ch->rawData.getOldestPos();
+       unsigned int newp = ch->rawData.getLatestPos();
+
+       ChanHit hit;
+
+//     LOG_DEBUG("isPlaying-------------------------------------- %d %d", ch->isPlaying(), isPlaying);
+
+       hit.initLocal(newLocalListeners,newLocalRelays,ch->info.numSkips,ch->info.getUptime(),ch->isPlaying(), ch->isFull(), ch->info.bitrate, ch, oldp, newp);
+       hit.tracker = ch->isBroadcasting();
+
+       if      (       (((ctime-lastUpdate)>chanMgr->hostUpdateInterval) && chanMgr->hostUpdateInterval)
+               ||      (newLocalListeners != numListeners)
+               ||      (newLocalRelays != numRelays)
+               ||      (ch->isPlaying() != isPlaying)
+               ||      (servMgr->getFirewall() != fwState)
+               ||      (ch->chDisp.relay != hit.relay)
+               ||      (ch->chDisp.relayfull != hit.relayfull)
+               ||      (ch->chDisp.chfull != hit.chfull)
+               ||      (ch->chDisp.ratefull != hit.ratefull)   
+       ){
+               numListeners = newLocalListeners;
+               numRelays = newLocalRelays;
+               isPlaying = ch->isPlaying();
+               fwState = servMgr->getFirewall();
+               lastUpdate = ctime;
+       
+               ch->chDisp = hit;
+
+               if ((numRelays) && ((servMgr->getFirewall() == ServMgr::FW_OFF) && (servMgr->autoRelayKeep!=0))) //JP-EX
+                       ch->stayConnected = true;
+
+               if ((!numRelays && !numListeners) && (servMgr->autoRelayKeep==2)) //JP-EX
+                       ch->stayConnected = false;
+
+               MemoryStream pmem(pack.data,sizeof(pack.data));
+               AtomStream atom(pmem);
+
+               GnuID noID;
+               noID.clear();
+
+#ifndef VERSION_EX
+                       atom.writeParent(PCP_BCST,8);
+#else
+                       atom.writeParent(PCP_BCST,10);
+#endif
+                       atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_TRACKERS);
+                       atom.writeChar(PCP_BCST_HOPS,0);
+                       atom.writeChar(PCP_BCST_TTL,11);
+                       atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
+                       atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
+                       atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
+#ifdef VERSION_EX
+                       atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
+                       atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
+#endif
+                       atom.writeBytes(PCP_BCST_CHANID,ch->info.id.id,16);
+                       hit.writeAtoms(atom,noID);
+
+               pack.len = pmem.pos;
+               pack.type = ChanPacket::T_PCP;
+               return true;
+       }else
+               return false;
+}
+// -----------------------------------
+bool   Channel::checkBump()
+{
+       if (!isBroadcasting() && (!sourceHost.tracker))
+               if (rawData.lastWriteTime && ((sys->getTime() - rawData.lastWriteTime) > 30))
+               {
+                       LOG_ERROR("Channel Auto bumped");
+                       bump = true;
+               }
+       
+       if (bump)
+       {
+               bump = false;
+               return true;
+       }else
+               return false;
+}
+
+// -----------------------------------
+int Channel::readStream(Stream &in,ChannelStream *source)
+{
+       //sys->sleep(300);
+
+       int error = 0;
+
+       info.numSkips = 0;
+
+       source->readHeader(in,this);
+
+       peercastApp->channelStart(&info);
+
+       rawData.lastWriteTime = 0;
+
+       bool wasBroadcasting=false;
+
+       unsigned int receiveStartTime = 0;
+
+       try
+       {
+               while (thread.active && !peercastInst->isQuitting)
+               {                       
+                       if (checkIdle())
+                       {
+                               LOG_DEBUG("Channel idle");
+                               break;
+                       }
+
+                       if (checkBump())
+                       {
+                               LOG_DEBUG("Channel bumped");
+                               error = -1;
+                               bumped = true;
+                               break;
+                       }
+
+                       if (in.eof())
+                       {
+                               LOG_DEBUG("Channel eof");
+                               break;
+                       }
+
+                       if (in.readReady())
+                       {
+                               error = source->readPacket(in,this);
+
+                               if (error)
+                                       break;
+
+                               //if (rawData.writePos > 0)
+                               if (rawData.lastWriteTime > 0)
+                               {
+                                       if (isBroadcasting())
+                                       {                                       
+                                               if ((sys->getTime()-lastTrackerUpdate) >= chanMgr->hostUpdateInterval)
+                                               {
+                                                       GnuID noID;
+                                                       noID.clear();
+                                                       broadcastTrackerUpdate(noID);
+                                               }
+                                               wasBroadcasting = true;
+
+                                       }else
+                                       {
+/*                                             if (status != Channel::S_RECEIVING){
+                                                       receiveStartTime = sys->getTime();
+                                               } else if (receiveStartTime && receiveStartTime + 10 > sys->getTime()){
+                                                       chanMgr->hitlistlock.on();
+                                                       ChanHitList *hl = chanMgr->findHitList(info);
+                                                       if (hl){
+                                                               hl->clearHits(true);
+                                                       }
+                                                       chanMgr->hitlistlock.off();
+                                                       receiveStartTime = 0;
+                                               }*/
+                                               setStatus(Channel::S_RECEIVING);
+                                               bumped = false;
+                                       }
+                                       source->updateStatus(this);
+                               }
+                       }
+
+                       source->flush(in);
+
+                       sys->sleepIdle();
+               }
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("readStream: %s",e.msg);
+               error = -1;
+       }
+
+       if (!servMgr->keepDownstreams) {
+               if (status == Channel::S_RECEIVING){
+                       chanMgr->hitlistlock.on();
+                       ChanHitList *hl = chanMgr->findHitList(info);
+                       if (hl){
+                               hl->clearHits(false);
+                       }
+                       chanMgr->hitlistlock.off();
+               }
+       }
+
+//     setStatus(S_CLOSING);
+       setStatus(S_IDLE);
+
+       if (wasBroadcasting)
+       {
+               GnuID noID;
+               noID.clear();
+               broadcastTrackerUpdate(noID,true);
+       }
+
+       peercastApp->channelStop(&info);
+
+       source->readEnd(in,this);
+
+       return error;
+}
+
+// -----------------------------------
+void PeercastStream::readHeader(Stream &in,Channel *ch)
+{
+       if (in.readTag() != 'PCST')
+               throw StreamException("Not PeerCast stream");
+
+}
+// -----------------------------------
+void PeercastStream::readEnd(Stream &,Channel *)
+{
+
+}
+// -----------------------------------
+int PeercastStream::readPacket(Stream &in,Channel *ch)
+{
+       ChanPacket pack;
+
+       {
+
+               pack.readPeercast(in);
+
+               MemoryStream mem(pack.data,pack.len);
+
+               switch(pack.type)
+               {
+                       case ChanPacket::T_HEAD:
+                               // update sync pos
+                               ch->headPack = pack;
+                               pack.pos = ch->streamPos;
+                               ch->newPacket(pack);
+                               ch->streamPos+=pack.len;
+                               break;
+                       case ChanPacket::T_DATA:
+                               pack.pos = ch->streamPos;
+                               ch->newPacket(pack);
+                               ch->streamPos+=pack.len;
+                               break;
+                       case ChanPacket::T_META:
+                               ch->insertMeta.fromMem(pack.data,pack.len);
+                               {
+                                       if (pack.len)
+                                       {
+                                               XML xml;
+                                               xml.read(mem);
+                                               XML::Node *n = xml.findNode("channel");                                 
+                                               if (n)
+                                               {
+                                                       ChanInfo newInfo = ch->info;
+                                                       newInfo.updateFromXML(n);
+                                                       ChanHitList *chl = chanMgr->findHitList(ch->info);
+                                                       if (chl)
+                                                               newInfo.updateFromXML(n);
+                                                       ch->updateInfo(newInfo);
+                                               }
+                                       }
+                               }
+                               break;
+#if 0
+                       case ChanPacket::T_SYNC:
+                               {
+                                       unsigned int s = mem.readLong();
+                                       if ((s-ch->syncPos) != 1)
+                                       {
+                                               LOG_CHANNEL("Ch.%d SKIP: %d to %d (%d)",ch->index,ch->syncPos,s,ch->info.numSkips);
+                                               if (ch->syncPos)
+                                               {
+                                                       ch->info.numSkips++;
+                                                       if (ch->info.numSkips>50)
+                                                               throw StreamException("Bumped - Too many skips");
+                                               }
+                                       }
+
+                                       ch->syncPos = s;
+                               }
+                               break;
+#endif
+
+               }
+
+       }
+       return 0;
+}
+
+// -----------------------------------
+void ChannelStream::readRaw(Stream &in, Channel *ch)
+{
+       ChanPacket pack;
+
+       const int readLen = 8192;
+
+       pack.init(ChanPacket::T_DATA,pack.data,readLen,ch->streamPos);
+       in.read(pack.data,pack.len);
+       ch->newPacket(pack);
+       ch->checkReadDelay(pack.len);
+
+       ch->streamPos+=pack.len;
+
+}
+// ------------------------------------------
+void RawStream::readHeader(Stream &,Channel *)
+{
+}
+
+// ------------------------------------------
+int RawStream::readPacket(Stream &in,Channel *ch)
+{
+       readRaw(in,ch);
+       return 0;
+}
+
+// ------------------------------------------
+void RawStream::readEnd(Stream &,Channel *)
+{
+}
+
+
+
+// -----------------------------------
+void ChanPacket::init(ChanPacketv &p)
+{
+       type = p.type;
+       len = p.len;
+       pos = p.pos;
+       sync = p.sync;
+       skip = p.skip;
+       memcpy(data, p.data, len);
+}
+// -----------------------------------
+void ChanPacket::init(TYPE t, const void *p, unsigned int l,unsigned int _pos)
+{
+       type = t;
+       if (l > MAX_DATALEN)
+               throw StreamException("Packet data too large");
+       len = l;
+       memcpy(data,p,len);
+       pos = _pos;
+       skip = false;
+}
+// -----------------------------------
+void ChanPacket::writeRaw(Stream &out)
+{
+       out.write(data,len);
+}
+// -----------------------------------
+void ChanPacket::writePeercast(Stream &out)
+{
+       unsigned int tp = 0;
+       switch (type)
+       {
+               case T_HEAD: tp = 'HEAD'; break;
+               case T_META: tp = 'META'; break;
+               case T_DATA: tp = 'DATA'; break;
+       }
+
+       if (type != T_UNKNOWN)
+       {
+               out.writeTag(tp);
+               out.writeShort(len);
+               out.writeShort(0);
+               out.write(data,len);
+       }
+}
+// -----------------------------------
+void ChanPacket::readPeercast(Stream &in)
+{
+       unsigned int tp = in.readTag();
+
+       switch (tp)
+       {
+               case 'HEAD':    type = T_HEAD; break;
+               case 'DATA':    type = T_DATA; break;
+               case 'META':    type = T_META; break;
+               default:                type = T_UNKNOWN;
+       }
+       len = in.readShort();
+       in.readShort();
+       if (len > MAX_DATALEN)
+               throw StreamException("Bad ChanPacket");
+       in.read(data,len);
+}
+// -----------------------------------
+int ChanPacketBuffer::copyFrom(ChanPacketBuffer &buf, unsigned int reqPos)
+{
+       lock.on();
+       buf.lock.on();
+
+       firstPos = 0;
+       lastPos = 0;
+       safePos = 0;
+       readPos = 0;
+
+       for(unsigned int i=buf.firstPos; i<=buf.lastPos; i++)
+       {
+               //ChanPacket *src = &buf.packets[i%MAX_PACKETS];
+               ChanPacketv *src = &buf.packets[i%MAX_PACKETS];
+               if (src->type & accept)
+               {
+                       if (src->pos >= reqPos)
+                       {
+                               lastPos = writePos;
+                               //packets[writePos++] = *src;
+                               packets[writePos++].init(*src);
+                       }
+               }
+
+       }
+
+
+       buf.lock.off();
+       lock.off();
+       return lastPos-firstPos;
+}
+
+// -----------------------------------
+bool ChanPacketBuffer::findPacket(unsigned int spos, ChanPacket &pack)
+{
+       if (writePos == 0)
+               return false;
+
+       lock.on();
+
+       unsigned int fpos = getStreamPos(firstPos);
+       if (spos < fpos)
+               spos = fpos;
+
+
+       for(unsigned int i=firstPos; i<=lastPos; i++)
+       {
+               //ChanPacket &p = packets[i%MAX_PACKETS];
+               ChanPacketv &p = packets[i%MAX_PACKETS];
+               if (p.pos >= spos)
+               {
+                       pack.init(p);
+                       lock.off();
+                       return true;
+               }
+       }
+
+       lock.off();
+       return false;
+}
+// -----------------------------------
+unsigned int   ChanPacketBuffer::getLatestPos()
+{
+       if (!writePos)
+               return 0;
+       else
+               return getStreamPos(lastPos);
+               
+}
+// -----------------------------------
+unsigned int   ChanPacketBuffer::getOldestPos()
+{
+       if (!writePos)
+               return 0;
+       else
+               return getStreamPos(firstPos);
+}
+
+// -----------------------------------
+unsigned int   ChanPacketBuffer::findOldestPos(unsigned int spos)
+{
+       unsigned int min = getStreamPos(safePos);
+       unsigned int max = getStreamPos(lastPos);
+
+       if (min > spos)
+               return min;
+
+       if (max < spos)
+               return max;
+
+       return spos;
+}
+
+// -----------------------------------
+unsigned int   ChanPacketBuffer::getStreamPos(unsigned int index)
+{
+       return packets[index%MAX_PACKETS].pos;
+}
+// -----------------------------------
+unsigned int   ChanPacketBuffer::getStreamPosEnd(unsigned int index)
+{
+       return packets[index%MAX_PACKETS].pos+packets[index%MAX_PACKETS].len;
+}
+// -----------------------------------
+bool ChanPacketBuffer::writePacket(ChanPacket &pack, bool updateReadPos)
+{
+       if (pack.len)
+       {
+               if (servMgr->keepDownstreams) {
+                       unsigned int lpos = getLatestPos();
+                       unsigned int diff = pack.pos - lpos;
+                       if (packets[lastPos%MAX_PACKETS].type == ChanPacket::T_HEAD) lpos = 0;
+                       if (lpos && (diff == 0 || diff > 0xfff00000)) {
+                               LOG_DEBUG("*   latest pos=%d, pack pos=%d", getLatestPos(), pack.pos);
+                               return false;
+                       }
+               }
+
+               if (willSkip()) // too far behind
+               {
+                       lastSkipTime = sys->getTime();
+                       return false;
+               }
+
+               lock.on();
+
+               pack.sync = writePos;
+               packets[writePos%MAX_PACKETS].init(pack);
+
+//             LOG_DEBUG("packet.len = %d",pack.len);
+
+
+               lastPos = writePos;
+               writePos++;
+
+               if (writePos >= MAX_PACKETS)
+                       firstPos = writePos-MAX_PACKETS;
+               else
+                       firstPos = 0;
+
+               if (writePos >= NUM_SAFEPACKETS)
+                       safePos = writePos - NUM_SAFEPACKETS;
+               else
+                       safePos = 0;
+
+               if (updateReadPos)
+                       readPos = writePos;
+
+               lastWriteTime = sys->getTime();
+
+               lock.off();
+               return true;
+       }
+
+       return false;
+}
+// -----------------------------------
+void   ChanPacketBuffer::readPacket(ChanPacket &pack)
+{
+
+       unsigned int tim = sys->getTime();
+
+       if (readPos < firstPos) 
+               throw StreamException("Read too far behind");
+
+       while (readPos >= writePos)
+       {
+               sys->sleepIdle();
+               if ((sys->getTime() - tim) > 30)
+                       throw TimeoutException();
+       }
+       lock.on();
+       pack.init(packets[readPos%MAX_PACKETS]);
+       readPos++;
+       lock.off();
+
+       sys->sleepIdle();
+
+}
+// -----------------------------------
+bool   ChanPacketBuffer::willSkip()
+{
+       return ((writePos-readPos) >= MAX_PACKETS);
+}
+
+// -----------------------------------
+void Channel::getStreamPath(char *str)
+{
+       char idStr[64];
+
+       getIDStr(idStr);
+
+       sprintf(str,"/stream/%s%s",idStr,info.getTypeExt(info.contentType));
+}
+
+
+
+// -----------------------------------
+void ChanMgr::startSearch(ChanInfo &info)
+{
+       searchInfo = info;
+       clearHitLists();
+       numFinds = 0;
+       lastHit = 0;
+//     lastSearch = 0;
+       searchActive = true;
+}
+// -----------------------------------
+void ChanMgr::quit()
+{
+       LOG_DEBUG("ChanMgr is quitting..");
+       closeAll();
+}
+// -----------------------------------
+int ChanMgr::numIdleChannels()
+{
+       int cnt=0;
+       Channel *ch = channel;
+       while (ch)
+       {
+               if (ch->isActive())
+                       if (ch->thread.active)
+                               if (ch->status == Channel::S_IDLE)
+                                       cnt++;
+               ch=ch->next;
+       }
+       return cnt;
+}
+// -----------------------------------
+void ChanMgr::closeOldestIdle()
+{
+       unsigned int idleTime = (unsigned int)-1;
+       Channel *ch = channel,*oldest=NULL;
+       while (ch)
+       {
+               if (ch->isActive())
+                       if (ch->thread.active)
+                               if (ch->status == Channel::S_IDLE)
+                                       if (ch->lastIdleTime < idleTime)
+                                       {
+                                               oldest = ch;
+                                               idleTime = ch->lastIdleTime;
+                                       }
+               ch=ch->next;
+       }
+
+       if (oldest)
+               oldest->thread.active = false;
+}
+
+// -----------------------------------
+void ChanMgr::closeAll()
+{
+       Channel *ch = channel;
+       while (ch)
+       {
+               if (ch->thread.active)
+                       ch->thread.shutdown();
+               ch=ch->next;
+       }
+}
+// -----------------------------------
+Channel *ChanMgr::findChannelByNameID(ChanInfo &info)
+{
+       Channel *ch = channel;
+       while (ch)
+       {
+               if (ch->isActive())
+                       if (ch->info.matchNameID(info))
+                               return ch;
+               ch=ch->next;
+       }
+       return NULL;
+}
+
+// -----------------------------------
+Channel *ChanMgr::findChannelByName(const char *n)
+{
+       Channel *ch = channel;
+       while (ch)
+       {
+               if (ch->isActive())
+                       if (stricmp(ch->info.name,n)==0)
+                               return ch;
+               ch=ch->next;
+       }
+
+       return NULL;
+}
+// -----------------------------------
+Channel *ChanMgr::findChannelByIndex(int index)
+{
+       int cnt=0;
+       Channel *ch = channel;
+       while (ch)
+       {
+               if (ch->isActive())
+               {
+                       if (cnt == index)
+                               return ch;
+                       cnt++;
+               }
+               ch=ch->next;
+       }
+       return NULL;
+}      
+// -----------------------------------
+Channel *ChanMgr::findChannelByMount(const char *str)
+{
+       Channel *ch = channel;
+       while (ch)
+       {
+               if (ch->isActive())
+                       if (strcmp(ch->mount,str)==0)
+                               return ch;
+               ch=ch->next;
+       }
+
+       return NULL;
+}      
+// -----------------------------------
+Channel *ChanMgr::findChannelByID(GnuID &id)
+{
+       Channel *ch = channel;
+       while (ch)
+       {
+               if (ch->isActive())
+                       if (ch->info.id.isSame(id))
+                               return ch;
+               ch=ch->next;
+       }
+       return NULL;
+}      
+// -----------------------------------
+Channel *ChanMgr::findChannelByChannelID(int id)
+{
+       int cnt=0;
+       Channel *ch = channel;
+       while (ch)
+       {
+               if (ch->isActive()){
+                       if (ch->channel_id == id){
+                               return ch;
+                       }
+               }
+               ch = ch->next;
+       }
+       return NULL;
+}
+// -----------------------------------
+int ChanMgr::findChannels(ChanInfo &info, Channel **chlist, int max)
+{
+       int cnt=0;
+       Channel *ch = channel;
+       while (ch)
+       {
+               if (ch->isActive())
+                       if (ch->info.match(info))
+                       {
+                               chlist[cnt++] = ch;
+                               if (cnt >= max)
+                                       break;
+                       }
+               ch=ch->next;
+       }
+       return cnt;
+}
+// -----------------------------------
+int ChanMgr::findChannelsByStatus(Channel **chlist, int max, Channel::STATUS status)
+{
+       int cnt=0;
+       Channel *ch = channel;
+       while (ch)
+       {
+               if (ch->isActive())
+                       if (ch->status == status)
+                       {
+                               chlist[cnt++] = ch;
+                               if (cnt >= max)
+                                       break;
+                       }
+               ch=ch->next;
+       }
+       return cnt;
+}
+// -----------------------------------
+Channel *ChanMgr::createRelay(ChanInfo &info, bool stayConnected)
+{
+       Channel *c = chanMgr->createChannel(info,NULL);
+       if (c)
+       {
+               c->stayConnected = stayConnected;
+               c->startGet();
+               return c;
+       }
+       return NULL;
+}
+// -----------------------------------
+Channel *ChanMgr::findAndRelay(ChanInfo &info)
+{
+       char idStr[64];
+       info.id.toStr(idStr);
+       LOG_CHANNEL("Searching for: %s (%s)",idStr,info.name.cstr());
+
+       if(!isIndexTxt(&info))  // for PCRaw (popup)
+               peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Finding channel...");
+
+
+       Channel *c = NULL;
+
+       WLockBlock wb(&(chanMgr->channellock));
+
+       wb.on();
+
+       c = findChannelByNameID(info);
+
+       if (!c)
+       {
+               c = chanMgr->createChannel(info,NULL);
+               if (c)
+               {
+                       c->setStatus(Channel::S_SEARCHING);                     
+                       c->startGet();
+               }
+       } else if (!(c->thread.active)){
+               c->thread.active = true;
+               c->thread.finish = false;
+               if (c->finthread){
+                       c->finthread->finish = true;
+                       c->finthread = NULL;
+               }
+               if (c->status != Channel::S_CONNECTING && c->status != Channel::S_SEARCHING){
+                       c->setStatus(Channel::S_SEARCHING);     
+                       c->startGet();
+               }
+       }
+
+       wb.off();
+
+       for(int i=0; i<600; i++)        // search for 1 minute.
+       {
+
+
+               wb.on();
+               c = findChannelByNameID(info);
+
+               if (!c)
+               {
+//                     peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Channel not found");
+                       return NULL;
+               }
+
+               
+               if (c->isPlaying() && (c->info.contentType!=ChanInfo::T_UNKNOWN))
+                       break;
+
+               wb.off();
+
+               sys->sleep(100);
+       }
+
+       return c;
+}
+// -----------------------------------
+ChanMgr::ChanMgr()
+{
+       channel = NULL;
+       
+       hitlist = NULL;
+
+       currFindAndPlayChannel.clear();
+
+       broadcastMsg.clear();
+       broadcastMsgInterval=10;
+
+       broadcastID.generate(PCP_BROADCAST_FLAGS);
+
+       deadHitAge = 600;
+
+       icyIndex = 0;
+       icyMetaInterval = 8192; 
+       maxRelaysPerChannel = 1;
+
+       searchInfo.init();
+
+       minBroadcastTTL = 1;
+       maxBroadcastTTL = 7;
+
+       pushTimeout = 60;       // 1 minute
+       pushTries = 5;          // 5 times
+       maxPushHops = 8;        // max 8 hops away
+       maxUptime = 0;          // 0 = none
+
+       prefetchTime = 10;      // n seconds
+
+       hostUpdateInterval = 120; // 2 minutes
+
+       bufferTime = 5;
+
+       autoQuery = 0;  
+       lastQuery = 0;
+
+       lastYPConnect = 0;
+       lastYPConnect2 = 0;
+
+}
+
+// -----------------------------------
+bool ChanMgr::writeVariable(Stream &out, const String &var, int index)
+{
+       char buf[1024];
+       if (var == "numHitLists")
+               sprintf(buf,"%d",numHitLists());
+       
+       else if (var == "numChannels")
+               sprintf(buf,"%d",numChannels());
+       else if (var == "djMessage")
+               strcpy(buf,broadcastMsg.cstr());
+       else if (var == "icyMetaInterval")
+               sprintf(buf,"%d",icyMetaInterval);
+       else if (var == "maxRelaysPerChannel")
+               sprintf(buf,"%d",maxRelaysPerChannel);
+       else if (var == "hostUpdateInterval")
+               sprintf(buf,"%d",hostUpdateInterval);
+       else if (var == "broadcastID")
+               broadcastID.toStr(buf);
+       else
+               return false;
+
+
+
+       out.writeString(buf);
+       return true;
+}
+
+// -----------------------------------
+bool Channel::writeVariable(Stream &out, const String &var, int index)
+{
+       char buf[1024];
+
+       buf[0]=0;
+
+       String utf8;
+
+       if (var == "name")
+       {
+               utf8 = info.name;
+               utf8.convertTo(String::T_UNICODESAFE);
+               strcpy(buf,utf8.cstr());
+
+       }else if (var == "bitrate")
+       {
+               sprintf(buf,"%d",info.bitrate);
+
+       }else if (var == "srcrate")
+       {
+               if (sourceData)
+               {
+                       unsigned int tot = sourceData->getSourceRate();
+                       sprintf(buf,"%.1f",BYTES_TO_KBPS(tot));
+               }else
+                       strcpy(buf,"0");
+
+       }else if (var == "genre")
+       {
+               utf8 = info.genre;
+               utf8.convertTo(String::T_UNICODESAFE);
+               strcpy(buf,utf8.cstr());
+       }else if (var == "desc")
+       {
+               utf8 = info.desc;
+               utf8.convertTo(String::T_UNICODESAFE);
+               strcpy(buf,utf8.cstr());
+       }else if (var == "comment")
+       {
+               utf8 = info.comment;
+               utf8.convertTo(String::T_UNICODESAFE);
+               strcpy(buf,utf8.cstr());
+       }else if (var == "uptime")
+       {
+               String uptime;
+               if (info.lastPlayStart)
+                       uptime.setFromStopwatch(sys->getTime()-info.lastPlayStart);
+               else
+                       uptime.set("-");
+               strcpy(buf,uptime.cstr());
+       }
+       else if (var == "type")
+               sprintf(buf,"%s",ChanInfo::getTypeStr(info.contentType));
+       else if (var == "ext")
+               sprintf(buf,"%s",ChanInfo::getTypeExt(info.contentType));
+       else if (var == "proto") {
+               switch(info.contentType) {
+               case ChanInfo::T_WMA:
+               case ChanInfo::T_WMV:
+                       sprintf(buf, "mms://");
+                       break;
+               default:
+                       sprintf(buf, "http://");
+               }
+       }
+       else if (var == "localRelays")
+               sprintf(buf,"%d",localRelays());
+       else if (var == "localListeners")
+               sprintf(buf,"%d",localListeners());
+
+       else if (var == "totalRelays")
+               sprintf(buf,"%d",totalRelays());
+       else if (var == "totalListeners")
+               sprintf(buf,"%d",totalListeners());
+
+       else if (var == "status")
+               sprintf(buf,"%s",getStatusStr());
+       else if (var == "keep")
+               sprintf(buf,"%s",stayConnected?"Yes":"No");
+       else if (var == "id")
+               info.id.toStr(buf);
+       else if (var.startsWith("track."))
+       {
+
+               if (var == "track.title")
+                       utf8 = info.track.title;
+               else if (var == "track.artist")
+                       utf8 = info.track.artist;
+               else if (var == "track.album")
+                       utf8 = info.track.album;
+               else if (var == "track.genre")
+                       utf8 = info.track.genre;
+               else if (var == "track.contactURL")
+                       utf8 = info.track.contact;
+
+               utf8.convertTo(String::T_UNICODESAFE);
+               strcpy(buf,utf8.cstr());
+
+       }else if (var == "contactURL")
+               sprintf(buf,"%s",info.url.cstr());
+       else if (var == "streamPos")
+               sprintf(buf,"%d",streamPos);
+       else if (var == "sourceType")
+               strcpy(buf,getSrcTypeStr());
+       else if (var == "sourceProtocol")
+               strcpy(buf,ChanInfo::getProtocolStr(info.srcProtocol));
+       else if (var == "sourceURL")
+       {
+               if (sourceURL.isEmpty())
+                       sourceHost.host.toStr(buf);
+               else
+                       strcpy(buf,sourceURL.cstr());
+       }
+       else if (var == "headPos")
+               sprintf(buf,"%d",headPack.pos);
+       else if (var == "headLen")
+               sprintf(buf,"%d",headPack.len);
+       else if (var == "numHits")
+       {
+               ChanHitList *chl = chanMgr->findHitListByID(info.id);
+               int numHits = 0;
+               if (chl){
+//                     numHits = chl->numHits();
+                       ChanHit *hit;
+                       hit = chl->hit;
+                       while(hit){
+                               numHits++;
+                               hit = hit->next;
+                       }
+               }
+               sprintf(buf,"%d",numHits);
+       } else if (var == "isBroadcast")
+               strcpy(buf, (type == T_BROADCAST) ? "1":"0");
+       else
+               return false;
+
+       out.writeString(buf);
+       return true;
+}
+
+// -----------------------------------
+void ChanMgr::broadcastTrackerUpdate(GnuID &svID, bool force)
+{
+       Channel *c = channel;
+       while(c)
+       {
+               if ( c->isActive() && c->isBroadcasting() )
+                       c->broadcastTrackerUpdate(svID,force);
+               c=c->next;
+       }
+}
+
+
+// -----------------------------------
+int ChanMgr::broadcastPacketUp(ChanPacket &pack,GnuID &chanID, GnuID &srcID, GnuID &destID)
+{
+       int cnt=0;
+
+       Channel *c = channel;
+       while(c)
+       {
+               if (c->sendPacketUp(pack,chanID,srcID,destID))
+                       cnt++;
+               c=c->next;
+       }
+
+       return cnt;
+}
+
+// -----------------------------------
+void ChanMgr::broadcastRelays(Servent *serv, int minTTL, int maxTTL)
+{
+       //if ((servMgr->getFirewall() == ServMgr::FW_OFF) || servMgr->serverHost.localIP())
+       {
+
+               Host sh = servMgr->serverHost;
+               bool push = (servMgr->getFirewall()!=ServMgr::FW_OFF);
+               bool busy = (servMgr->pubInFull() && servMgr->outFull()) || servMgr->relaysFull();
+               bool stable = servMgr->totalStreams>0;
+
+
+               GnuPacket hit;
+
+               int numChans=0;
+
+               Channel *c = channel;
+               while(c)
+               {
+                       if (c->isPlaying())
+                       {
+
+                               bool tracker = c->isBroadcasting();
+
+                               int ttl = (c->info.getUptime() / servMgr->relayBroadcast);      // 1 hop per N seconds
+
+                               if (ttl < minTTL)
+                                       ttl = minTTL;
+
+                               if (ttl > maxTTL)
+                                       ttl = maxTTL;
+
+                               if (hit.initHit(sh,c,NULL,push,busy,stable,tracker,ttl))
+                               {
+                                       int numOut=0;
+                                       numChans++;
+                                       if (serv)
+                                       {
+                                               serv->outputPacket(hit,false);
+                                               numOut++;
+                                       }
+
+                                       LOG_NETWORK("Sent channel to %d servents, TTL %d",numOut,ttl);          
+
+                               }
+                       }
+                       c=c->next;
+               }
+               //if (numChans)
+               //      LOG_NETWORK("Sent %d channels to %d servents",numChans,numOut);         
+       }
+}
+// -----------------------------------
+void ChanMgr::setUpdateInterval(unsigned int v)
+{
+       hostUpdateInterval = v;
+}
+
+
+// -----------------------------------
+// message check
+#if 0
+                               ChanPacket pack;
+                               MemoryStream mem(pack.data,sizeof(pack.data));
+                               AtomStream atom(mem);
+                               atom.writeParent(PCP_BCST,3);
+                                       atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_ALL);
+                                       atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
+                                       atom.writeParent(PCP_MESG,1);
+                                               atom.writeString(PCP_MESG_DATA,msg.cstr());
+
+                               mem.len = mem.pos;
+                               mem.rewind();
+                               pack.len = mem.len;
+
+                               GnuID noID;
+                               noID.clear();
+
+                               BroadcastState bcs;
+                               PCPStream::readAtom(atom,bcs);
+                               //int cnt = servMgr->broadcastPacketUp(pack,noID,servMgr->sessionID);
+                               //int cnt = servMgr->broadcastPacketDown(pack,noID,servMgr->sessionID);
+                               //int cnt = chanMgr->broadcastPacketUp(pack,noID,servMgr->sessionID);
+                               //LOG_DEBUG("Sent message to %d clients",cnt);
+#endif
+// -----------------------------------
+void ChanMgr::setBroadcastMsg(String &msg)
+{
+       if (!msg.isSame(broadcastMsg))
+       {
+               broadcastMsg = msg;
+
+               Channel *c = channel;
+               while(c)
+               {
+                       if (c->isActive() && c->isBroadcasting())
+                       {
+                               ChanInfo newInfo = c->info;
+                               newInfo.comment = broadcastMsg;
+                               c->updateInfo(newInfo);
+                       }
+                       c=c->next;
+               }
+
+       }
+}
+
+
+// -----------------------------------
+void ChanMgr::clearHitLists()
+{
+
+//     LOG_DEBUG("clearHitLists HITLISTLOCK ON-------------");
+       chanMgr->hitlistlock.on();
+       while (hitlist)
+       {
+               peercastApp->delChannel(&hitlist->info);
+       
+               ChanHitList *next = hitlist->next;
+
+               delete hitlist;
+
+               hitlist = next;
+       }
+//     LOG_DEBUG("clearHitLists HITLISTLOCK OFF-------------");
+       chanMgr->hitlistlock.off();
+}
+// -----------------------------------
+Channel *ChanMgr::deleteChannel(Channel *delchan)
+{
+       lock.on();
+
+       Channel *ch = channel,*prev=NULL,*next=NULL;
+
+       while (ch)
+       {
+               if (ch == delchan)
+               {
+                       Channel *next = ch->next;
+                       if (prev)
+                               prev->next = next;
+                       else
+                               channel = next;
+
+                       if (delchan->sourceStream){
+                               delchan->sourceStream->parent = NULL;
+                       }
+
+                       delete delchan;
+
+                       break;
+               }
+               prev = ch;
+               ch=ch->next;
+       }
+
+
+       lock.off();
+       return next;
+}
+
+// -----------------------------------
+Channel *ChanMgr::createChannel(ChanInfo &info, const char *mount)
+{
+       lock.on();
+
+       Channel *nc=NULL;
+
+       nc = new Channel();
+
+       nc->next = channel;
+       channel = nc;
+
+
+       nc->info = info;
+       nc->info.lastPlayStart = 0;
+       nc->info.lastPlayEnd = 0;
+       nc->info.status = ChanInfo::S_UNKNOWN;
+       if (mount)
+               nc->mount.set(mount);
+       nc->setStatus(Channel::S_WAIT);
+       nc->type = Channel::T_ALLOCATED;
+       nc->info.createdTime = sys->getTime();
+
+       LOG_CHANNEL("New channel created");
+
+       lock.off();
+       return nc;
+}
+// -----------------------------------
+int ChanMgr::pickHits(ChanHitSearch &chs)
+{
+       ChanHitList *chl = hitlist;
+       while(chl)
+       {
+               if (chl->isUsed())
+                       if (chl->pickHits(chs))
+                       {
+                               chl->info.id;
+                               return 1;
+                       }
+               chl = chl->next;
+       }
+       return 0;
+}
+
+// -----------------------------------
+ChanHitList *ChanMgr::findHitList(ChanInfo &info)
+{
+       ChanHitList *chl = hitlist;
+       while(chl)
+       {
+               if (chl->isUsed())
+                       if (chl->info.matchNameID(info))
+                               return chl;
+
+               chl = chl->next;
+       }
+       return NULL;
+}
+// -----------------------------------
+ChanHitList *ChanMgr::findHitListByID(GnuID &id)
+{
+       ChanHitList *chl = hitlist;
+       while(chl)
+       {
+               if (chl->isUsed())
+                       if (chl->info.id.isSame(id))
+                               return chl;
+               chl = chl->next;
+       }
+       return NULL;
+}
+// -----------------------------------
+int ChanMgr::numHitLists()
+{
+       int num=0;
+       ChanHitList *chl = hitlist;
+       while(chl)
+       {
+               if (chl->isUsed())
+                       num++;
+               chl = chl->next;
+       }
+       return num;
+}
+// -----------------------------------
+ChanHitList *ChanMgr::addHitList(ChanInfo &info)
+{      
+       ChanHitList *chl = new ChanHitList();   
+
+
+       chl->next = hitlist;
+       hitlist = chl;
+
+       chl->used = true;
+       chl->info = info;
+       chl->info.createdTime = sys->getTime();
+       peercastApp->addChannel(&chl->info);
+
+
+       return chl;
+}
+// -----------------------------------
+void ChanMgr::clearDeadHits(bool clearTrackers)
+{
+       unsigned int interval;
+       
+       if (servMgr->isRoot)
+               interval = 1200;                // mainly for old 0.119 clients
+       else
+               interval = hostUpdateInterval+120;
+
+       chanMgr->hitlistlock.on();
+       ChanHitList *chl = hitlist,*prev = NULL;
+       while (chl)
+       {
+               if (chl->isUsed())
+               {
+                       if (chl->clearDeadHits(interval,clearTrackers) == 0)
+                       {
+                               if (!isBroadcasting(chl->info.id))
+                               {
+                                       if (!chanMgr->findChannelByID(chl->info.id))
+                                       {
+                                               peercastApp->delChannel(&chl->info);
+
+                                               ChanHitList *next = chl->next;
+                                               if (prev)
+                                                       prev->next = next;
+                                               else
+                                                       hitlist = next;
+
+                                               delete chl;
+                                               chl = next;
+                                               continue;
+                                       }
+                               }
+                       }
+               }
+               prev = chl;
+               chl = chl->next;
+       }
+       chanMgr->hitlistlock.off();
+}
+// -----------------------------------
+bool   ChanMgr::isBroadcasting(GnuID &id)
+{
+       Channel *ch = findChannelByID(id);
+       if (ch)
+               return ch->isBroadcasting();
+
+       return false;
+}
+// -----------------------------------
+bool   ChanMgr::isBroadcasting()
+{
+       Channel *ch = channel;
+       while (ch)
+       {
+               if (ch->isActive())
+                       if (ch->isBroadcasting())
+                               return true;
+
+               ch = ch->next;
+       }
+       return false;
+}
+
+// -----------------------------------
+int ChanMgr::numChannels()
+{
+       int tot = 0;
+       Channel *ch = channel;
+       while (ch)
+       {
+               if (ch->isActive())
+                       tot++;
+               ch = ch->next;
+       }
+       return tot;
+}
+
+// -----------------------------------
+void ChanMgr::deadHit(ChanHit &hit)
+{
+       ChanHitList *chl = findHitListByID(hit.chanID);
+       if (chl)
+               chl->deadHit(hit);
+}
+// -----------------------------------
+void ChanMgr::delHit(ChanHit &hit)
+{
+       ChanHitList *chl = findHitListByID(hit.chanID);
+       if (chl)
+               chl->delHit(hit);
+}
+
+// -----------------------------------
+void ChanMgr::addHit(Host &h,GnuID &id,bool tracker)
+{
+       ChanHit hit;
+       hit.init();
+       hit.host = h; 
+       hit.rhost[0] = h;
+       hit.rhost[1].init();
+       hit.tracker = tracker;
+       hit.recv = true;
+       hit.chanID = id;
+       addHit(hit);
+}
+// -----------------------------------
+ChanHit *ChanMgr::addHit(ChanHit &h)
+{
+       if (searchActive)
+               lastHit = sys->getTime();
+
+       ChanHitList *hl=NULL;
+
+       hl = findHitListByID(h.chanID);
+
+       if (!hl)
+       {
+               ChanInfo info;
+               info.id = h.chanID;
+               hl = addHitList(info);
+       }
+
+       if (hl)
+       {
+               return hl->addHit(h);
+       }else
+               return NULL;
+}
+
+// -----------------------------------
+class ChanFindInfo : public ThreadInfo
+{
+public:
+       ChanInfo        info;
+       bool    keep;
+};
+// -----------------------------------
+THREAD_PROC findAndPlayChannelProc(ThreadInfo *th)
+{
+       ChanFindInfo *cfi = (ChanFindInfo *)th;
+
+       ChanInfo info;
+       info = cfi->info;
+
+
+       Channel *ch = chanMgr->findChannelByNameID(info);
+
+       chanMgr->currFindAndPlayChannel = info.id;
+
+       if (!ch)
+               ch = chanMgr->findAndRelay(info);
+
+       if (ch)
+       {
+               // check that a different channel hasn`t be selected already.
+               if (chanMgr->currFindAndPlayChannel.isSame(ch->info.id))
+                       chanMgr->playChannel(ch->info);
+
+               if (cfi->keep)
+                       ch->stayConnected = cfi->keep;
+       }
+
+       delete cfi;
+       return 0;
+}
+// -----------------------------------
+void ChanMgr::findAndPlayChannel(ChanInfo &info, bool keep)
+{
+       ChanFindInfo *cfi = new ChanFindInfo;
+       cfi->info = info;
+       cfi->keep = keep;
+       cfi->func = findAndPlayChannelProc;
+
+
+       sys->startThread(cfi);
+}
+// -----------------------------------
+void ChanMgr::playChannel(ChanInfo &info)
+{
+
+       char str[128],fname[256],idStr[128];
+
+       sprintf(str,"http://localhost:%d",servMgr->serverHost.port);
+       info.id.toStr(idStr);
+
+       PlayList::TYPE type;
+
+
+       if ((info.contentType == ChanInfo::T_WMA) || (info.contentType == ChanInfo::T_WMV))
+       {
+               type = PlayList::T_ASX;
+               // WMP seems to have a bug where it doesn`t re-read asx files if they have the same name
+               // so we prepend the channel id to make it unique - NOTE: should be deleted afterwards.
+               if (servMgr->getModulePath) //JP-EX
+               {
+                       peercastApp->getDirectory();
+                       sprintf(fname,"%s/%s.asx",servMgr->modulePath,idStr);   
+               }else
+                       sprintf(fname,"%s/%s.asx",peercastApp->getPath(),idStr);
+       }else if (info.contentType == ChanInfo::T_OGM)
+       {
+               type = PlayList::T_RAM;
+               if (servMgr->getModulePath) //JP-EX
+               {
+                       peercastApp->getDirectory();
+                       sprintf(fname,"%s/play.ram",servMgr->modulePath);
+               }else
+                       sprintf(fname,"%s/play.ram",peercastApp->getPath());
+
+       }else
+       {
+               type = PlayList::T_SCPLS;
+               if (servMgr->getModulePath) //JP-EX
+               {
+                       peercastApp->getDirectory();
+                       sprintf(fname,"%s/play.pls",servMgr->modulePath);
+               }else
+                       sprintf(fname,"%s/play.pls",peercastApp->getPath());
+       }
+
+
+       PlayList *pls = new PlayList(type,1);
+       pls->addChannel(str,info);
+
+
+       LOG_DEBUG("Writing %s",fname);
+       FileStream file;
+       file.openWriteReplace(fname);
+       pls->write(file);
+       file.close();
+
+
+       LOG_DEBUG("Executing: %s",fname);
+       sys->executeFile(fname);
+       delete pls;
+
+}
+
+// -----------------------------------
+ChanHitList::ChanHitList()
+{
+       info.init();
+       lastHitTime = 0;
+       used = false;
+       hit = NULL;
+}
+// -----------------------------------
+ChanHitList::~ChanHitList()
+{
+       chanMgr->hitlistlock.on();
+       while (hit)
+               hit = deleteHit(hit);
+       chanMgr->hitlistlock.off();
+}
+// -----------------------------------
+void ChanHit::pickNearestIP(Host &h)
+{
+       for(int i=0; i<2; i++)
+       {
+               if (h.classType() == rhost[i].classType())
+               {
+                       host = rhost[i];
+                       break;
+               }
+       }
+}
+
+// -----------------------------------
+void ChanHit::init()
+{
+       host.init();
+
+       rhost[0].init();
+       rhost[1].init();
+
+       next = NULL;
+
+       numListeners = 0;
+       numRelays = 0;
+
+       dead = tracker = firewalled = stable = yp = false;
+       recv = cin = direct = relay = true;
+       relayfull = chfull = ratefull = false;
+       direct = 0;
+       numHops = 0;
+       time = upTime = 0;
+       lastContact = 0;
+
+       version = 0;
+       version_vp = 0;
+
+       version_ex_prefix[0] = ' ';
+       version_ex_prefix[1] = ' ';
+       version_ex_number = 0;
+
+       status = 0;
+
+       sessionID.clear();
+       chanID.clear();
+
+
+       oldestPos = newestPos = 0;
+       uphost.init();
+       uphostHops = 0;
+}
+
+// -----------------------------------
+void ChanHit::initLocal(int numl,int numr,int,int uptm,bool connected,bool isFull,unsigned int bitrate, Channel* ch, unsigned int oldp,unsigned int newp)
+{
+       init();
+       firewalled = (servMgr->getFirewall() != ServMgr::FW_OFF);
+       numListeners = numl;
+       numRelays = numr;
+       upTime = uptm;
+       stable = servMgr->totalStreams>0;
+       sessionID = servMgr->sessionID;
+       recv = connected;
+
+       direct = !servMgr->directFull();
+//     relay = !servMgr->relaysFull();
+       cin = !servMgr->controlInFull();
+
+       relayfull = servMgr->relaysFull();
+       chfull = isFull;
+
+       Channel *c = chanMgr->channel;
+       int noRelay = 0;
+       unsigned int needRate = 0;
+       unsigned int allRate = 0;
+       while(c){
+               if (c->isPlaying()){
+                       allRate += c->info.bitrate * c->localRelays();
+                       if ((c != ch) && (c->localRelays() == 0)){
+                               if(!isIndexTxt(c))      // for PCRaw (relay)
+                                       noRelay++;
+                               needRate+=c->info.bitrate;
+                       }
+               }
+               c = c->next;
+       }
+       int diff = servMgr->maxRelays - servMgr->numStreams(Servent::T_RELAY,false);
+       if (ch->localRelays()){
+               if (noRelay > diff){
+                       noRelay = diff;
+               }
+       } else {
+               noRelay = 0;
+               needRate = 0;
+       }
+
+       // for PCRaw (relay) start.
+       bool force_off = false;
+
+       if(isIndexTxt(ch))
+               force_off = true;
+       // for PCRaw (relay) end.
+
+//     ratefull = servMgr->bitrateFull(needRate+bitrate);
+       ratefull = (servMgr->maxBitrateOut < allRate + needRate + ch->info.bitrate);
+
+       //relay =       (!relayfull) && (!chfull) && (!ratefull) && ((servMgr->numStreams(Servent::T_RELAY,false) + noRelay) < servMgr->maxRelays);
+       relay = (!relayfull || force_off) && (!chfull) && (!ratefull)
+               && (((servMgr->numStreams(Servent::T_RELAY,false) + noRelay) < servMgr->maxRelays) || force_off);       // for PCRaw (relay) (force_off)
+
+/*     if (relayfull){
+               LOG_DEBUG("Reject by relay full");
+       }
+       if (chfull){
+               LOG_DEBUG("Reject by channel full");
+       }
+       if (ratefull){
+               LOG_DEBUG("Reject by rate: Max=%d Now=%d Need=%d ch=%d", servMgr->maxBitrateOut, allRate, needRate, ch->info.bitrate);
+       }*/
+
+       host = servMgr->serverHost;
+
+       version = PCP_CLIENT_VERSION;
+       version_vp = PCP_CLIENT_VERSION_VP;
+#ifdef VERSION_EX
+       strncpy(version_ex_prefix, PCP_CLIENT_VERSION_EX_PREFIX,2);
+       version_ex_number = PCP_CLIENT_VERSION_EX_NUMBER;
+#else
+       version_ex_prefix[0] = ' ';
+       version_ex_prefix[1] = ' ';
+       version_ex_number = 0;
+#endif
+
+       status = ch->status;
+
+       rhost[0] = Host(host.ip,host.port);
+       rhost[1] = Host(ClientSocket::getIP(NULL),host.port);
+
+       if (firewalled)
+               rhost[0].port = 0;
+
+       oldestPos = oldp;
+       newestPos = newp;
+
+       uphost.ip = ch->sourceHost.host.ip;
+       uphost.port = ch->sourceHost.host.port;
+       uphostHops = 1;
+}
+
+// -----------------------------------
+void ChanHit::writeAtoms(AtomStream &atom,GnuID &chanID)
+{
+       bool addChan=chanID.isSet();
+       bool uphostdata=(uphost.ip != 0);
+
+       int fl1 = 0; 
+       if (recv) fl1 |= PCP_HOST_FLAGS1_RECV;
+       if (relay) fl1 |= PCP_HOST_FLAGS1_RELAY;
+       if (direct) fl1 |= PCP_HOST_FLAGS1_DIRECT;
+       if (cin) fl1 |= PCP_HOST_FLAGS1_CIN;
+       if (tracker) fl1 |= PCP_HOST_FLAGS1_TRACKER;
+       if (firewalled) fl1 |= PCP_HOST_FLAGS1_PUSH;
+
+       atom.writeParent(PCP_HOST,13  + (addChan?1:0) + (uphostdata?3:0) + (version_ex_number?2:0));
+
+               if (addChan)
+                       atom.writeBytes(PCP_HOST_CHANID,chanID.id,16);
+               atom.writeBytes(PCP_HOST_ID,sessionID.id,16);
+               atom.writeInt(PCP_HOST_IP,rhost[0].ip);
+               atom.writeShort(PCP_HOST_PORT,rhost[0].port);
+               atom.writeInt(PCP_HOST_IP,rhost[1].ip);
+               atom.writeShort(PCP_HOST_PORT,rhost[1].port);
+               atom.writeInt(PCP_HOST_NUML,numListeners);
+               atom.writeInt(PCP_HOST_NUMR,numRelays);
+               atom.writeInt(PCP_HOST_UPTIME,upTime);
+               atom.writeInt(PCP_HOST_VERSION,version);
+               atom.writeInt(PCP_HOST_VERSION_VP,version_vp);
+               if (version_ex_number){
+                       atom.writeBytes(PCP_HOST_VERSION_EX_PREFIX,version_ex_prefix,2);
+                       atom.writeShort(PCP_HOST_VERSION_EX_NUMBER,version_ex_number);
+               }
+               atom.writeChar(PCP_HOST_FLAGS1,fl1);
+               atom.writeInt(PCP_HOST_OLDPOS,oldestPos);
+               atom.writeInt(PCP_HOST_NEWPOS,newestPos);
+               if (uphostdata){
+                       atom.writeInt(PCP_HOST_UPHOST_IP,uphost.ip);
+                       atom.writeInt(PCP_HOST_UPHOST_PORT,uphost.port);
+                       atom.writeInt(PCP_HOST_UPHOST_HOPS,uphostHops);
+               }
+}
+// -----------------------------------
+bool   ChanHit::writeVariable(Stream &out, const String &var)
+{
+       char buf[1024];
+
+       if (var == "rhost0")
+       {
+               if (servMgr->enableGetName) //JP-EX s
+               {
+                       char buf2[256];
+                       if (firewalled) 
+                       {
+                               if (numRelays==0) 
+                                       strcpy(buf,"<font color=red>");
+                               else 
+                                       strcpy(buf,"<font color=orange>");
+                       }
+                       else {
+                               if (!relay){
+                                       if (numRelays==0){
+                                               strcpy(buf,"<font color=purple>");
+                                       } else {
+                                               strcpy(buf,"<font color=blue>");
+                                       }
+                               } else {
+                                       strcpy(buf,"<font color=green>");
+                               }
+                       }
+
+                       rhost[0].toStr(buf2);
+                       strcat(buf,buf2);
+
+                       char h_name[128];
+                       if (ClientSocket::getHostname(h_name,rhost[0].ip))
+                       {
+                               strcat(buf,"[");
+                               strcat(buf,h_name);
+                               strcat(buf,"]");
+                       }
+                       strcat(buf,"</font>");
+               } //JP-EX e
+               else
+                       rhost[0].toStr(buf);
+       }
+       else if (var == "rhost1")
+               rhost[1].toStr(buf);
+       else if (var == "numHops")
+               sprintf(buf,"%d",numHops);
+       else if (var == "numListeners")
+               sprintf(buf,"%d",numListeners);
+       else if (var == "numRelays")
+               sprintf(buf,"%d",numRelays);
+       else if (var == "uptime")
+       {
+               String timeStr;
+               timeStr.setFromStopwatch(upTime);
+               strcpy(buf,timeStr.cstr());
+       }else if (var == "update")
+       {
+               String timeStr;
+               if (timeStr)
+                       timeStr.setFromStopwatch(sys->getTime()-time);
+               else
+                       timeStr.set("-");
+               strcpy(buf,timeStr.cstr());
+       }else if (var == "isFirewalled"){
+               sprintf(buf,"%d",firewalled?1:0);
+       }else if (var == "version"){
+               sprintf(buf,"%d",version);
+       }else if (var == "agent"){
+               if (version){
+                       if (version_ex_number){
+                               sprintf(buf, "v0.%d(%c%c%04d)", version, version_ex_prefix[0], version_ex_prefix[1], version_ex_number);
+                       } else if (version_vp){
+                               sprintf(buf,"v0.%d(VP%04d)", version, version_vp);
+                       } else {
+                               sprintf(buf,"v0.%d", version);
+                       }
+               } else {
+                       strcpy(buf, "0");
+               }
+       }
+       else if (var == "check")
+       {
+               char buf2[256];
+               strcpy(buf, "<a href=\"#\" onclick=\"checkip('");
+               rhost[0].IPtoStr(buf2);
+               strcat(buf, buf2);
+               strcat(buf, "')\">_</a>");
+       }
+       else if (var == "uphost")               // tree
+               uphost.toStr(buf);
+       else if (var == "uphostHops")   // tree
+               sprintf(buf,"%d",uphostHops);
+       else if (var == "canRelay")             // tree
+               sprintf(buf, "%d",relay);
+       else
+               return false;
+
+       out.writeString(buf);
+       return true;
+}
+
+// -----------------------------------
+int ChanHitList::getTotalListeners()
+{
+       int cnt=0;
+       ChanHit *h = hit;
+       while (h)
+       {
+               if (h->host.ip)
+                       cnt+=h->numListeners;
+               h=h->next;
+       }
+       return cnt;
+}
+// -----------------------------------
+int ChanHitList::getTotalRelays()
+{
+       int cnt=0;
+       ChanHit *h = hit;
+       while (h)
+       {
+               if (h->host.ip)
+                       cnt+=h->numRelays;
+               h=h->next;
+       }
+       return cnt;
+}
+// -----------------------------------
+int ChanHitList::getTotalFirewalled()
+{
+       int cnt=0;
+       ChanHit *h = hit;
+       while (h)
+       {
+               if (h->host.ip)
+                       if (h->firewalled)
+                               cnt++;
+               h=h->next;
+       }
+       return cnt;
+}
+
+// -----------------------------------
+int ChanHitList::contactTrackers(bool connected, int numl, int nums, int uptm)
+{
+       return 0;
+}
+
+void ChanHitList::clearHits(bool flg)
+{
+       ChanHit *c = hit, *prev = NULL;
+
+       while(c){
+               if (flg || (c->numHops != 0)){
+                       ChanHit *next = c->next;
+                       if (prev)
+                               prev->next = next;
+                       else
+                               hit = next;
+
+                       delete c;
+                       c = next;
+               } else {
+                       prev = c;
+                       c = c->next;
+               }
+       }
+}
+
+// -----------------------------------
+ChanHit *ChanHitList::deleteHit(ChanHit *ch)
+{
+       ChanHit *c = hit,*prev=NULL;
+       while (c)
+       {
+               if (c == ch)
+               {
+                       ChanHit *next = c->next;
+                       if (prev)
+                               prev->next = next;
+                       else
+                               hit = next;
+
+                       delete c;
+
+                       return next;
+               }
+               prev=c;
+               c=c->next;
+       }
+
+       return NULL;
+}
+// -----------------------------------
+ChanHit *ChanHitList::addHit(ChanHit &h)
+{
+       char ip0str[64],ip1str[64];
+       h.rhost[0].toStr(ip0str);
+       h.rhost[1].toStr(ip1str);
+       char uphostStr[64];
+       h.uphost.toStr(uphostStr);
+       if (h.uphost.ip){
+               LOG_DEBUG("Add hit: F%dT%dR%d %s/%s <- %s(%d)",h.firewalled,h.tracker,h.relay,ip0str,ip1str,uphostStr, h.uphostHops);
+       } else {
+               LOG_DEBUG("Add hit: F%dT%dR%d %s/%s",h.firewalled,h.tracker,h.relay,ip0str,ip1str);
+       }
+
+       // dont add our own hits
+       if (servMgr->sessionID.isSame(h.sessionID))
+               return NULL;
+
+
+       lastHitTime = sys->getTime();
+       h.time = lastHitTime;
+
+       ChanHit *ch = hit;
+       while (ch)
+       {
+               if ((ch->rhost[0].ip == h.rhost[0].ip) && (ch->rhost[0].port == h.rhost[0].port))
+                       if (((ch->rhost[1].ip == h.rhost[1].ip) && (ch->rhost[1].port == h.rhost[1].port)) || (!ch->rhost[1].isValid()))
+                       {
+                               if (!ch->dead)
+                               {
+                                       if (ch->numHops > 0 && h.numHops == 0)
+                                               // downstream hit recieved as RelayHost
+                                               return ch;
+                                       ChanHit *next = ch->next;
+                                       *ch = h;
+                                       ch->next = next;
+                                       return ch;
+                               }
+                       }
+               ch=ch->next;
+       }
+
+       // clear hits with same session ID (IP may have changed)
+       if (h.sessionID.isSet())
+       {
+               ChanHit *ch = hit;
+               while (ch)
+               {
+                       if (ch->host.ip)
+                               if (ch->sessionID.isSame(h.sessionID))
+                               {
+                                       ch = deleteHit(ch);
+                                       continue;                                               
+                               }
+                       ch=ch->next;
+               }
+       }
+
+
+       // else add new hit
+       {
+               ChanHit *ch = new ChanHit();
+               *ch = h;
+               ch->chanID = info.id;
+               ch->next = hit;
+               hit = ch;
+               return ch;
+       }
+
+       return NULL;
+}
+
+
+// -----------------------------------
+int    ChanHitList::clearDeadHits(unsigned int timeout, bool clearTrackers)
+{
+       int cnt=0;
+       unsigned int ctime = sys->getTime();
+
+//     LOG_DEBUG("clearDeadHits HITLISTLOCK ON-------------");
+       chanMgr->hitlistlock.on();
+       ChanHit *ch = hit;
+       while (ch)
+       {
+               if (ch->host.ip)
+               {
+                       if (ch->dead || ((ctime-ch->time) > timeout) && (clearTrackers || (!clearTrackers & !ch->tracker)))
+                       {
+//                             ch = deleteHit(ch);
+
+                               if (ch->firewalled){
+//                                     LOG_DEBUG("kickKeepTime = %d, %d", servMgr->kickKeepTime, ctime-ch->time);
+                                       if ( (servMgr->kickKeepTime == 0) || ((ctime-ch->time) > servMgr->kickKeepTime) ){
+                                               ch = deleteHit(ch);
+                                       } else {
+                                               ch->numHops = 0;
+                                               ch->numListeners = 0;
+                                               ch = ch->next;
+                                       }
+                               } else {
+                                       ch = deleteHit(ch);
+                               }
+
+                               continue;
+                       }else
+                               cnt++;
+               }
+               ch = ch->next;
+       }
+//     LOG_DEBUG("clearDeadHits HITLISTLOCK OFF-------------");
+       chanMgr->hitlistlock.off();
+       return cnt;
+}
+
+
+// -----------------------------------
+void   ChanHitList::deadHit(ChanHit &h)
+{
+       char ip0str[64],ip1str[64];
+       h.rhost[0].toStr(ip0str);
+       h.rhost[1].toStr(ip1str);
+       LOG_DEBUG("Dead hit: %s/%s",ip0str,ip1str);
+
+       ChanHit *ch = hit;
+       while (ch)
+       {
+               if (ch->host.ip)
+                       if (ch->rhost[0].isSame(h.rhost[0]) && ch->rhost[1].isSame(h.rhost[1]))
+                       {
+                               ch->dead = true;
+                       }
+               ch = ch->next;
+       }
+}
+// -----------------------------------
+void   ChanHitList::delHit(ChanHit &h)
+{
+       char ip0str[64],ip1str[64];
+       h.rhost[0].toStr(ip0str);
+       h.rhost[1].toStr(ip1str);
+       LOG_DEBUG("Del hit: %s/%s",ip0str,ip1str);
+
+       ChanHit *ch = hit;
+       while (ch)
+       {
+               if (ch->host.ip)
+                       if (ch->rhost[0].isSame(h.rhost[0]) && ch->rhost[1].isSame(h.rhost[1]))
+                       {
+                               ch=deleteHit(ch);
+                               continue;
+                       }
+               ch = ch->next;
+       }
+}
+// -----------------------------------
+int    ChanHitList::numHits()
+{
+       int cnt=0;
+       ChanHit *ch = hit;
+       while (ch)
+       {
+               if (ch->host.ip && !ch->dead && ch->numHops)
+                       cnt++;
+               ch = ch->next;
+       }
+
+       return cnt;
+}
+// -----------------------------------
+int    ChanHitList::numListeners()
+{
+       int cnt=0;
+       ChanHit *ch = hit;
+       while (ch)
+       {
+               if (ch->host.ip && !ch->dead && ch->numHops)
+                       cnt += ch->numListeners;
+               ch=ch->next;
+       }
+
+       return cnt;
+}
+// -----------------------------------
+int    ChanHitList::numRelays()
+{
+       int cnt=0;
+       ChanHit *ch = hit;
+       while (ch)
+       {
+               if (ch->host.ip && !ch->dead)
+                       cnt += ch->numRelays;
+               ch=ch->next;
+       }
+
+       return cnt;
+}
+
+// -----------------------------------
+int    ChanHitList::numTrackers()
+{
+       int cnt=0;
+       ChanHit *ch = hit;
+       while (ch)
+       {
+               if ((ch->host.ip && !ch->dead) && (ch->tracker))
+                       cnt++;
+               ch=ch->next;
+       }
+       return cnt;
+}
+// -----------------------------------
+int    ChanHitList::numFirewalled()
+{
+       int cnt=0;
+       ChanHit *ch = hit;
+       while (ch)
+       {
+               if (ch->host.ip && !ch->dead)
+                       cnt += ch->firewalled?1:0;
+               ch=ch->next;
+       }
+       return cnt;
+}
+// -----------------------------------
+int    ChanHitList::closestHit()
+{
+       unsigned int hop=10000;
+       ChanHit *ch = hit;
+       while (ch)
+       {
+               if (ch->host.ip && !ch->dead)
+                       if (ch->numHops < hop)
+                               hop = ch->numHops;
+               ch=ch->next;
+       }
+
+       return hop;
+}
+// -----------------------------------
+int    ChanHitList::furthestHit()
+{
+       unsigned int hop=0;
+       ChanHit *ch = hit;
+       while (ch)
+       {
+               if (ch->host.ip && !ch->dead)
+                       if (ch->numHops > hop)
+                               hop = ch->numHops;
+               ch=ch->next;
+       }
+
+       return hop;
+}
+// -----------------------------------
+unsigned int   ChanHitList::newestHit()
+{
+       unsigned int time=0;
+       ChanHit *ch = hit;
+       while (ch)
+       {
+               if (ch->host.ip && !ch->dead)
+                       if (ch->time > time)
+                               time = ch->time;
+               ch=ch->next;
+       }
+
+       return time;
+}
+// -----------------------------------
+int ChanHitList::pickHits(ChanHitSearch &chs)
+{
+       ChanHit best,*bestP=NULL;
+       best.init();
+       best.numHops = 255;
+       best.time = 0;
+
+       unsigned int ctime = sys->getTime();
+
+       ChanHit *c = hit;
+       while (c)
+       {
+               if (c->host.ip && !c->dead)
+               {
+                       if (!chs.excludeID.isSame(c->sessionID))
+                       if ((chs.waitDelay==0) || ((ctime-c->lastContact) >= chs.waitDelay))
+                       if ((c->numHops<=best.numHops)) // (c->time>=best.time))
+                       if (c->relay || (!c->relay && chs.useBusyRelays))
+                       if (c->cin || (!c->cin && chs.useBusyControls))
+                       {
+
+                               if (chs.trackersOnly && c->tracker)
+                               {
+                                       if (chs.matchHost.ip)
+                                       {
+                                               if ((c->rhost[0].ip == chs.matchHost.ip) && c->rhost[1].isValid())
+                                               {
+                                                       bestP = c;
+                                                       best = *c;
+                                                       best.host = best.rhost[1];      // use lan ip
+                                               }
+                                       }else if (c->firewalled == chs.useFirewalled)
+                                       {
+                                               bestP = c;
+                                               best = *c;
+                                               best.host = best.rhost[0];                      // use wan ip
+                                       }
+                               }else if (!chs.trackersOnly && !c->tracker)
+                               {
+                                       if (chs.matchHost.ip)
+                                       {
+                                               if ((c->rhost[0].ip == chs.matchHost.ip) && c->rhost[1].isValid())
+                                               {
+                                                       bestP = c;
+                                                       best = *c;
+                                                       best.host = best.rhost[1];      // use lan ip
+                                               }
+                                       }else if (c->firewalled == chs.useFirewalled && (!bestP || !bestP->relay))
+                                       {
+                                               bestP = c;
+                                               best = *c;
+                                               best.host = best.rhost[0];                      // use wan ip
+                                       }
+                               }
+                       }
+               }
+               c=c->next;
+       }
+
+       if (bestP)
+       {
+               if (chs.numResults < ChanHitSearch::MAX_RESULTS)
+               {
+                       if (chs.waitDelay)
+                               bestP->lastContact = ctime;
+                       chs.best[chs.numResults++] = best;
+                       return 1;
+               }
+
+       }
+
+       return 0;
+}
+
+
+// -----------------------------------
+int ChanHitList::pickSourceHits(ChanHitSearch &chs)
+{
+       if (pickHits(chs) && chs.best[0].numHops == 0) return 1;
+       return 0;
+}
+
+
+// -----------------------------------
+const char *ChanInfo::getTypeStr(TYPE t)
+{
+       switch (t)
+       {
+               case T_RAW: return "RAW";
+
+               case T_MP3: return "MP3";
+               case T_OGG: return "OGG";
+               case T_OGM: return "OGM";
+               case T_WMA: return "WMA";
+
+               case T_MOV: return "MOV";
+               case T_MPG: return "MPG";
+               case T_NSV: return "NSV";
+               case T_WMV: return "WMV";
+
+               case T_PLS: return "PLS";
+               case T_ASX: return "ASX";
+
+               default: return "UNKNOWN";
+       }
+}
+// -----------------------------------
+const char *ChanInfo::getProtocolStr(PROTOCOL t)
+{
+       switch (t)
+       {
+               case SP_PEERCAST: return "PEERCAST";
+               case SP_HTTP: return "HTTP";
+               case SP_FILE: return "FILE";
+               case SP_MMS: return "MMS";
+               case SP_PCP: return "PCP";
+               default: return "UNKNOWN";
+       }
+}
+// -----------------------------------
+ChanInfo::PROTOCOL ChanInfo::getProtocolFromStr(const char *str)
+{
+       if (stricmp(str,"PEERCAST")==0)
+               return SP_PEERCAST;
+       else if (stricmp(str,"HTTP")==0)
+               return SP_HTTP;
+       else if (stricmp(str,"FILE")==0)
+               return SP_FILE;
+       else if (stricmp(str,"MMS")==0)
+               return SP_MMS;
+       else if (stricmp(str,"PCP")==0)
+               return SP_PCP;
+       else 
+               return SP_UNKNOWN;
+}
+
+// -----------------------------------
+const char *ChanInfo::getTypeExt(TYPE t)
+{
+       switch(t)
+       {
+               case ChanInfo::T_OGM:
+               case ChanInfo::T_OGG:
+                       return ".ogg";
+               case ChanInfo::T_MP3:
+                       return ".mp3";
+               case ChanInfo::T_MOV:
+                       return ".mov";
+               case ChanInfo::T_NSV:
+                       return ".nsv";
+               case ChanInfo::T_WMV:
+                       return ".wmv";
+               case ChanInfo::T_WMA:
+                       return ".wma";
+               default:
+                       return "";
+       }
+}
+// -----------------------------------
+ChanInfo::TYPE ChanInfo::getTypeFromStr(const char *str)
+{
+       if (stricmp(str,"MP3")==0)
+               return T_MP3;
+       else if (stricmp(str,"OGG")==0)
+               return T_OGG;
+       else if (stricmp(str,"OGM")==0)
+               return T_OGM;
+       else if (stricmp(str,"RAW")==0)
+               return T_RAW;
+       else if (stricmp(str,"NSV")==0)
+               return T_NSV;
+       else if (stricmp(str,"WMA")==0)
+               return T_WMA;
+       else if (stricmp(str,"WMV")==0)
+               return T_WMV;
+       else if (stricmp(str,"PLS")==0)
+               return T_PLS;
+       else if (stricmp(str,"M3U")==0)
+               return T_PLS;
+       else if (stricmp(str,"ASX")==0)
+               return T_ASX;
+       else 
+               return T_UNKNOWN;
+}
+// -----------------------------------
+bool   ChanInfo::matchNameID(ChanInfo &inf)
+{
+       if (inf.id.isSet())
+               if (id.isSame(inf.id))
+                       return true;
+
+       if (!inf.name.isEmpty())
+               if (name.contains(inf.name))
+                       return true;
+
+       return false;
+}
+// -----------------------------------
+bool   ChanInfo::match(ChanInfo &inf)
+{
+       bool matchAny=true;
+
+       if (inf.status != S_UNKNOWN)
+       {
+               if (status != inf.status)
+                       return false;
+       }
+
+       if (inf.bitrate != 0)
+       {
+               if (bitrate == inf.bitrate)
+                       return true;
+               matchAny = false;
+       }
+
+       if (inf.id.isSet())
+       {
+               if (id.isSame(inf.id))
+                       return true;
+               matchAny = false;
+       }
+
+       if (inf.contentType != T_UNKNOWN)
+       {
+               if (contentType == inf.contentType)
+                       return true;
+               matchAny = false;
+       }
+
+       if (!inf.name.isEmpty())
+       {
+               if (name.contains(inf.name))
+                       return true;
+               matchAny = false;
+       }
+
+       if (!inf.genre.isEmpty())
+       {
+               if (genre.contains(inf.genre))
+                       return true;
+               matchAny = false;
+       }
+
+       return matchAny;
+}
+// -----------------------------------
+bool TrackInfo::update(TrackInfo &inf)
+{
+       bool changed = false;
+
+       if (!contact.isSame(inf.contact))
+       {
+               contact = inf.contact;
+               changed = true;
+       }
+
+       if (!title.isSame(inf.title))
+       {
+               title = inf.title;
+               changed = true;
+       }
+
+       if (!artist.isSame(inf.artist))
+       {
+               artist = inf.artist;
+               changed = true;
+       }
+
+       if (!album.isSame(inf.album))
+       {
+               album = inf.album;
+               changed = true;
+       }
+
+       if (!genre.isSame(inf.genre))
+       {
+               genre = inf.genre;
+               changed = true;
+       }
+
+
+       return changed;
+}
+
+
+// -----------------------------------
+bool ChanInfo::update(ChanInfo &info)
+{
+       bool changed = false;
+
+
+
+       // check valid id
+       if (!info.id.isSet())
+               return false;
+
+       // only update from chaninfo that has full name etc..
+       if (info.name.isEmpty())
+               return false;
+
+       // check valid broadcaster key
+       if (bcID.isSet())
+       {
+               if (!bcID.isSame(info.bcID))
+               {
+                       LOG_ERROR("ChanInfo BC key not valid");
+                       return false;
+               }
+       }else
+       {
+               bcID = info.bcID;
+       }
+
+
+
+       if (bitrate != info.bitrate)
+       {
+               bitrate = info.bitrate;
+               changed = true;
+       }
+
+       if (contentType != info.contentType)
+       {
+               contentType = info.contentType;
+               changed = true;
+       }
+
+       if (!desc.isSame(info.desc)) //JP-EX
+       {
+               desc = info.desc;
+               changed = true;
+       }
+
+       if (!name.isSame(info.name))
+       {
+               name = info.name;
+               changed = true;
+       }
+
+       if (!comment.isSame(info.comment))
+       {
+               comment = info.comment;
+               changed = true;
+       }
+
+       if (!genre.isSame(info.genre))
+       {
+               genre = info.genre;
+               changed = true;
+       }
+       
+       if (!url.isSame(info.url))
+       {
+               url = info.url;
+               changed = true;
+       }
+
+       if (track.update(info.track))
+               changed = true;
+
+
+       return changed;
+}
+// -----------------------------------
+void ChanInfo::initNameID(const char *n)
+{
+       init();
+       id.fromStr(n);
+       if (!id.isSet())
+               name.set(n);
+}
+
+// -----------------------------------
+void ChanInfo::init()
+{
+       status = S_UNKNOWN;
+       name.clear();
+       bitrate = 0;
+       contentType = T_UNKNOWN;
+       srcProtocol = SP_UNKNOWN;
+       id.clear();
+       url.clear();
+       genre.clear();
+       comment.clear();
+       track.clear();
+       lastPlayStart = 0;
+       lastPlayEnd = 0;
+       numSkips = 0;
+       bcID.clear();
+       createdTime = 0;
+}
+// -----------------------------------
+void ChanInfo::readTrackXML(XML::Node *n)
+{
+       track.clear();
+       readXMLString(track.title,n,"title");
+       readXMLString(track.contact,n,"contact");
+       readXMLString(track.artist,n,"artist");
+       readXMLString(track.album,n,"album");
+       readXMLString(track.genre,n,"genre");
+}
+// -----------------------------------
+unsigned int ChanInfo::getUptime()
+{
+       // calculate uptime and cap if requested by settings.
+       unsigned int upt;
+       upt = lastPlayStart?(sys->getTime()-lastPlayStart):0;
+       if (chanMgr->maxUptime)
+               if (upt > chanMgr->maxUptime)
+                       upt = chanMgr->maxUptime;
+       return upt;
+}
+// -----------------------------------
+unsigned int ChanInfo::getAge()
+{
+       return sys->getTime()-createdTime;
+}
+
+// ------------------------------------------
+void ChanInfo::readTrackAtoms(AtomStream &atom,int numc)
+{
+       for(int i=0; i<numc; i++)
+       {
+               int c,d;
+               ID4 id = atom.read(c,d);
+               if (id == PCP_CHAN_TRACK_TITLE)
+               {
+                       atom.readString(track.title.data,sizeof(track.title.data),d);
+               }else if (id == PCP_CHAN_TRACK_CREATOR)
+               {
+                       atom.readString(track.artist.data,sizeof(track.artist.data),d);
+               }else if (id == PCP_CHAN_TRACK_URL)
+               {
+                       atom.readString(track.contact.data,sizeof(track.contact.data),d);
+               }else if (id == PCP_CHAN_TRACK_ALBUM)
+               {
+                       atom.readString(track.album.data,sizeof(track.album.data),d);
+               }else
+                       atom.skip(c,d);
+       }
+}
+// ------------------------------------------
+void ChanInfo::readInfoAtoms(AtomStream &atom,int numc)
+{
+       for(int i=0; i<numc; i++)
+       {
+               int c,d;
+               ID4 id = atom.read(c,d);
+               if (id == PCP_CHAN_INFO_NAME)
+               {
+                       atom.readString(name.data,sizeof(name.data),d);
+               }else if (id == PCP_CHAN_INFO_BITRATE)
+               {
+                       bitrate = atom.readInt();
+               }else if (id == PCP_CHAN_INFO_GENRE)
+               {
+                       atom.readString(genre.data,sizeof(genre.data),d);
+               }else if (id == PCP_CHAN_INFO_URL)
+               {
+                       atom.readString(url.data,sizeof(url.data),d);
+               }else if (id == PCP_CHAN_INFO_DESC)
+               {
+                       atom.readString(desc.data,sizeof(desc.data),d);
+               }else if (id == PCP_CHAN_INFO_COMMENT)
+               {
+                       atom.readString(comment.data,sizeof(comment.data),d);
+               }else if (id == PCP_CHAN_INFO_TYPE)
+               {
+                       char type[16];
+                       atom.readString(type,sizeof(type),d);
+                       contentType = ChanInfo::getTypeFromStr(type);
+               }else
+                       atom.skip(c,d);
+       }       
+}
+
+// -----------------------------------
+void ChanInfo::writeInfoAtoms(AtomStream &atom)
+{
+       atom.writeParent(PCP_CHAN_INFO,7);
+               atom.writeString(PCP_CHAN_INFO_NAME,name.cstr());
+               atom.writeInt(PCP_CHAN_INFO_BITRATE,bitrate);
+               atom.writeString(PCP_CHAN_INFO_GENRE,genre.cstr());
+               atom.writeString(PCP_CHAN_INFO_URL,url.cstr());
+               atom.writeString(PCP_CHAN_INFO_DESC,desc.cstr());
+               atom.writeString(PCP_CHAN_INFO_COMMENT,comment.cstr());
+               atom.writeString(PCP_CHAN_INFO_TYPE,getTypeStr(contentType));           
+
+}
+// -----------------------------------
+void ChanInfo::writeTrackAtoms(AtomStream &atom)
+{
+       atom.writeParent(PCP_CHAN_TRACK,4);
+               atom.writeString(PCP_CHAN_TRACK_TITLE,track.title.cstr());
+               atom.writeString(PCP_CHAN_TRACK_CREATOR,track.artist.cstr());
+               atom.writeString(PCP_CHAN_TRACK_URL,track.contact.cstr());
+               atom.writeString(PCP_CHAN_TRACK_ALBUM,track.album.cstr());
+}
+
+
+// -----------------------------------
+XML::Node *ChanInfo::createChannelXML()
+{
+       char idStr[64];
+
+       String nameUNI = name;
+       nameUNI.convertTo(String::T_UNICODESAFE);
+
+       String urlUNI = url;
+       urlUNI.convertTo(String::T_UNICODESAFE);
+
+       String genreUNI = genre;
+       genreUNI.convertTo(String::T_UNICODESAFE);
+
+       String descUNI = desc;
+       descUNI.convertTo(String::T_UNICODESAFE);
+
+       String commentUNI;
+       commentUNI = comment;
+       commentUNI.convertTo(String::T_UNICODESAFE);
+
+
+       id.toStr(idStr);
+
+
+       return new XML::Node("channel name=\"%s\" id=\"%s\" bitrate=\"%d\" type=\"%s\" genre=\"%s\" desc=\"%s\" url=\"%s\" uptime=\"%d\" comment=\"%s\" skips=\"%d\" age=\"%d\" bcflags=\"%d\"",
+               nameUNI.cstr(),
+               idStr,
+               bitrate,
+               getTypeStr(contentType),
+               genreUNI.cstr(),
+               descUNI.cstr(),
+               urlUNI.cstr(),
+               getUptime(),
+               commentUNI.cstr(),
+               numSkips,
+               getAge(),
+               bcID.getFlags()
+               );      
+}
+
+// -----------------------------------
+XML::Node *ChanInfo::createQueryXML()
+{
+       char buf[512];
+       char idStr[64];
+
+
+       String nameHTML = name;
+       nameHTML.convertTo(String::T_HTML);
+       String genreHTML = genre;
+       genreHTML.convertTo(String::T_HTML);
+
+       buf[0]=0;
+       if (!nameHTML.isEmpty())
+       {
+               strcat(buf," name=\"");
+               strcat(buf,nameHTML.cstr());
+               strcat(buf,"\"");
+       }
+
+       if (!genreHTML.isEmpty())
+       {
+               strcat(buf," genre=\"");
+               strcat(buf,genreHTML.cstr());
+               strcat(buf,"\"");
+       }
+
+       if (id.isSet())
+       {
+               id.toStr(idStr);
+               strcat(buf," id=\"");
+               strcat(buf,idStr);
+               strcat(buf,"\"");
+       }
+               
+
+       return new XML::Node("channel %s",buf);
+}
+
+// -----------------------------------
+XML::Node *ChanInfo::createRelayChannelXML()
+{
+       char idStr[64];
+
+       id.toStr(idStr);
+
+
+       return new XML::Node("channel id=\"%s\" uptime=\"%d\" skips=\"%d\" age=\"%d\"",
+               idStr,
+               getUptime(),
+               numSkips,
+               getAge()
+               );      
+}// -----------------------------------
+XML::Node *ChanInfo::createTrackXML()
+{
+       String titleUNI = track.title;
+       titleUNI.convertTo(String::T_UNICODESAFE);
+
+       String artistUNI = track.artist;
+       artistUNI.convertTo(String::T_UNICODESAFE);
+
+       String albumUNI = track.album;
+       albumUNI.convertTo(String::T_UNICODESAFE);
+
+       String genreUNI = track.genre;
+       genreUNI.convertTo(String::T_UNICODESAFE);
+
+       String contactUNI = track.contact;
+       contactUNI.convertTo(String::T_UNICODESAFE);
+       
+
+
+       return new XML::Node("track title=\"%s\" artist=\"%s\" album=\"%s\" genre=\"%s\" contact=\"%s\"",
+               titleUNI.cstr(),
+               artistUNI.cstr(),
+               albumUNI.cstr(),
+               genreUNI.cstr(),
+               contactUNI.cstr()
+               );
+}
+
+// -----------------------------------
+void ChanInfo::init(XML::Node *n)
+{
+       init();
+
+       updateFromXML(n);
+}
+// -----------------------------------
+void ChanInfo::updateFromXML(XML::Node *n)
+{
+       String typeStr,idStr;
+
+       readXMLString(name,n,"name");
+       readXMLString(genre,n,"genre");
+       readXMLString(url,n,"url");
+       readXMLString(desc,n,"desc");
+
+
+       int br = n->findAttrInt("bitrate");
+       if (br)
+               bitrate = br;
+
+       readXMLString(typeStr,n,"type");
+       if (!typeStr.isEmpty())
+               contentType = getTypeFromStr(typeStr.cstr());
+
+
+       readXMLString(idStr,n,"id");
+       if (!idStr.isEmpty())
+               id.fromStr(idStr.cstr());
+
+       readXMLString(comment,n,"comment");
+
+       XML::Node *tn = n->findNode("track");
+       if (tn)
+               readTrackXML(tn);
+
+}
+
+// -----------------------------------
+void ChanInfo::init(const char *n, GnuID &cid, TYPE tp, int br)
+{
+       init();
+
+       name.set(n);
+       bitrate = br;
+       contentType = tp;
+       id = cid;
+}
+
+// -----------------------------------
+void ChanInfo::init(const char *fn)
+{
+       init();
+
+       if (fn)
+               name.set(fn);
+}
+// -----------------------------------
+void PlayList::readASX(Stream &in)
+{
+       LOG_DEBUG("Reading ASX");
+       XML xml;
+
+       try
+       {
+               xml.read(in);
+       }catch(StreamException &) {} // TODO: eof is NOT handled properly in sockets - always get error at end
+
+       if (xml.root)
+       {
+               XML::Node *n = xml.root->child;
+               while (n)
+               {
+                       if (stricmp("entry",n->getName())==0)
+                       {
+                               XML::Node *rf = n->findNode("ref");
+                               if (rf)
+                               {
+                                       char *hr = rf->findAttr("href");
+                                       if (hr)
+                                       {
+                                               addURL(hr,"");
+                                               //LOG("asx url %s",hr);
+                                       }
+
+                               }
+                       }
+                       n=n->sibling;
+               }
+       }
+}
+// -----------------------------------
+void PlayList::readSCPLS(Stream &in)
+{
+       char tmp[256];
+       while (in.readLine(tmp,sizeof(tmp)))
+       {
+               if (strnicmp(tmp,"file",4)==0)
+               {
+                       char *p = strstr(tmp,"=");
+                       if (p)
+                               addURL(p+1,"");
+               }
+       }
+}
+// -----------------------------------
+void PlayList::readPLS(Stream &in)
+{
+       char tmp[256];
+       while (in.readLine(tmp,sizeof(tmp)))
+       {
+               if (tmp[0] != '#')
+                       addURL(tmp,"");
+       }
+}
+// -----------------------------------
+void PlayList::writeSCPLS(Stream &out)
+{
+       out.writeLine("[playlist]");
+       out.writeLine("");
+       out.writeLineF("NumberOfEntries=%d",numURLs);
+
+       for(int i=0; i<numURLs; i++)
+       {
+               out.writeLineF("File%d=%s",i+1,urls[i].cstr());
+               out.writeLineF("Title%d=%s",i+1,titles[i].cstr());
+               out.writeLineF("Length%d=-1",i+1);
+       }
+       out.writeLine("Version=2");
+}
+// -----------------------------------
+void PlayList::writePLS(Stream &out)
+{
+       for(int i=0; i<numURLs; i++)
+               out.writeLineF("%s",urls[i].cstr());
+}
+// -----------------------------------
+void PlayList::writeRAM(Stream &out)
+{
+       for(int i=0; i<numURLs; i++)
+               out.writeLineF("%s",urls[i].cstr());
+}
+
+// -----------------------------------
+void PlayList::writeASX(Stream &out)
+{
+       out.writeLine("<ASX Version=\"3.0\">");
+       for(int i=0; i<numURLs; i++)
+       {
+               out.writeLine("<ENTRY>");
+               out.writeLineF("<REF href = \"%s\" />",urls[i].cstr());
+               out.writeLine("</ENTRY>");
+       }
+       out.writeLine("</ASX>");
+}
+
+
+// -----------------------------------
+void PlayList::addChannel(const char *path, ChanInfo &info)
+{
+       String url;
+
+       char idStr[64];
+
+       info.id.toStr(idStr);
+       char *nid = info.id.isSet()?idStr:info.name.cstr();
+
+       sprintf(url.cstr(),"%s/stream/%s%s",path,nid,ChanInfo::getTypeExt(info.contentType));
+       addURL(url.cstr(),info.name);
+}
+
+// -----------------------------------
+void ChanHitSearch::init()
+{
+       matchHost.init();
+       waitDelay = 0;
+       useFirewalled = false;
+       trackersOnly = false;
+       useBusyRelays = true;
+       useBusyControls = true;
+       excludeID.clear();
+       numResults = 0;
+
+       //seed = sys->getTime();
+       //srand(seed);
+}
+
+int ChanHitSearch::getRelayHost(Host host1, Host host2, GnuID exID, ChanHitList *chl)
+{
+       int cnt = 0;
+       int loop = 1;
+       int index = 0;
+       int prob;
+       int rnd;
+       static int base = 0x400;
+       ChanHit tmpHit[MAX_RESULTS];
+       static WLock seqLock;
+       static unsigned int riSequence = 0;
+
+       //srand(seed);
+       //seed += 11;
+
+       unsigned int seq;
+       seqLock.on();
+       seq = riSequence++;
+       riSequence &= 0xffffff;
+       seqLock.off();
+
+       ChanHit *hit = chl->hit;
+
+       while(hit){
+               if (hit->host.ip && !hit->dead){
+                       if (
+                               (!exID.isSame(hit->sessionID))
+//                     &&      (hit->relay)
+                       &&      (!hit->tracker)
+                       &&      (!hit->firewalled)
+                       &&      (hit->numHops != 0)
+                       ){
+                               if (    (hit->rhost[0].ip == host1.ip)
+                                       &&      hit->rhost[1].isValid()
+                                       &&      (host2.ip != hit->rhost[1].ip)
+                               ){
+                                       best[0] = *hit;
+                                       best[0].host = hit->rhost[1];
+                                       index++;
+                               }
+                               if ((hit->rhost[0].ip == host2.ip) && hit->rhost[1].isValid()){
+                                       best[0] = *hit;
+                                       best[0].host = hit->rhost[1];
+                                       index++;
+                               }
+
+                               loop = (index / MAX_RESULTS) + 1;
+                               //prob = (float)1 / (float)loop;
+                               prob = base / loop;
+                               //rnd = (float)rand() / (float)RAND_MAX;
+                               rnd = rand() % base;
+                               if (hit->numHops == 1){
+                                       if (tmpHit[index % MAX_RESULTS].numHops == 1){
+                                               if (rnd < prob){
+                                                       tmpHit[index % MAX_RESULTS] = *hit;
+                                                       tmpHit[index % MAX_RESULTS].host = hit->rhost[0];
+                                                       index++;
+                                               }
+                                       } else {
+                                               tmpHit[index % MAX_RESULTS] = *hit;
+                                               tmpHit[index % MAX_RESULTS].host = hit->rhost[0];
+                                               index++;
+                                       }
+                               } else {
+                                       if ((tmpHit[index % MAX_RESULTS].numHops != 1) && (rnd < prob)){
+                                               tmpHit[index % MAX_RESULTS] = *hit;
+                                               tmpHit[index % MAX_RESULTS].host = hit->rhost[0];
+                                               index++;
+                                       }
+                               }
+
+//                             char tmp[50];
+//                             hit->host.toStr(tmp);
+//                             LOG_DEBUG("TEST %s: %f %f", tmp, rnd, prob);
+                       }
+               }
+               hit = hit->next;
+       }
+       
+       if (index > MAX_RESULTS){
+               cnt = MAX_RESULTS;
+       } else {
+               cnt = index;
+       }
+
+/*     int use[MAX_RESULTS];
+       memset(use, 0, sizeof(use));
+       int i;
+       for (i = 0; i < cnt; i++){
+               use[i] = -1;
+       }
+       int r;
+       for (i = 0; i < cnt; i++){
+               do {
+                       r = rand();
+//                     LOG_DEBUG("%d",r);
+                       r = r % cnt;
+                       if (use[r] == -1){
+                               use[r] = i;
+                               break;
+                       }
+               } while(1);
+       }
+       for (i = 0; i < cnt; i++){
+//             LOG_DEBUG("%d", use[i]);
+               best[use[i]] = tmpHit[i];
+       }*/
+
+       int use[MAX_RESULTS];
+       int i;
+       for (i = 0; i < cnt; i++) {
+               use[i] = (i + seq) % cnt;
+       }
+
+       for (i = 0; i < cnt; i++){
+//             LOG_DEBUG("%d", use[i]);
+               best[use[i]] = tmpHit[i];
+       }
+//     for (i = 0; i < cnt; i++){
+//             char tmp[50];
+//             best[i].host.toStr(tmp);
+//             LOG_DEBUG("Relay info: Hops = %d, %s", best[i].numHops, tmp);
+//     }
+
+       return cnt;
+}
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/channel.h b/c:/Git/PeerCast.root/PeerCast/core/common/channel.h
new file mode 100644 (file)
index 0000000..d1d00fb
--- /dev/null
@@ -0,0 +1,731 @@
+// ------------------------------------------------
+// File : channel.h
+// Date: 4-apr-2002
+// Author: giles
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _CHANNEL_H
+#define _CHANNEL_H
+
+#include "sys.h"
+#include "stream.h"
+#include "gnutella.h"
+#include "xml.h"
+#include "asf.h"
+#include "cstream.h"
+
+class AtomStream;
+class ChanHitSearch;
+
+// --------------------------------------------------
+struct MP3Header
+{
+       int lay;
+       int version;
+       int error_protection;
+       int bitrate_index;
+       int sampling_frequency;
+       int padding;
+       int extension;
+       int mode;
+       int mode_ext;
+       int copyright;
+       int original;
+       int emphasis;
+       int stereo;
+};
+
+// ----------------------------------
+class TrackInfo
+{
+public:
+       void    clear()
+       {
+               contact.clear();
+               title.clear();
+               artist.clear();
+               album.clear();
+               genre.clear();
+       }
+
+       void    convertTo(String::TYPE t)
+       {
+               contact.convertTo(t);
+               title.convertTo(t);
+               artist.convertTo(t);
+               album.convertTo(t);
+               genre.convertTo(t);
+       }
+
+       bool    update(TrackInfo &);
+
+       ::String        contact,title,artist,album,genre;
+};
+
+
+
+// ----------------------------------
+class ChanInfo
+{
+public:
+       enum TYPE
+       {
+               T_UNKNOWN,
+
+               T_RAW,
+               T_MP3,
+               T_OGG,
+               T_OGM,
+               T_MOV,
+               T_MPG,
+               T_NSV,
+
+               T_WMA,
+               T_WMV,
+
+               T_PLS,
+               T_ASX
+       };
+
+
+       enum PROTOCOL
+       {
+               SP_UNKNOWN,
+               SP_PEERCAST,
+               SP_HTTP,
+               SP_FILE,
+               SP_MMS,
+               SP_PCP
+       };
+
+
+       enum STATUS
+       {
+               S_UNKNOWN,
+               S_PLAY
+       };
+
+       ChanInfo() {init();}
+
+       void    init();
+       void    init(const char *);
+       void    init(const char *, GnuID &, TYPE, int);
+       void    init(XML::Node *);
+       void    initNameID(const char *);
+
+       void    updateFromXML(XML::Node *);
+
+       void    readTrackXML(XML::Node *);
+       void    readServentXML(XML::Node *);
+       bool    update(ChanInfo &);
+       XML::Node *createQueryXML();
+       XML::Node *createChannelXML();
+       XML::Node *createRelayChannelXML();
+       XML::Node *createTrackXML();
+       bool    match(XML::Node *);
+       bool    match(ChanInfo &);
+       bool    matchNameID(ChanInfo &);
+
+       void    writeInfoAtoms(AtomStream &atom);
+       void    writeTrackAtoms(AtomStream &atom);
+
+       void    readInfoAtoms(AtomStream &,int);
+       void    readTrackAtoms(AtomStream &,int);
+
+       unsigned int getUptime();
+       unsigned int getAge();
+       bool    isActive() {return id.isSet();}
+       bool    isPrivate() {return bcID.getFlags() & 1;}
+       static  const   char *getTypeStr(TYPE);
+       static  const   char *getProtocolStr(PROTOCOL);
+       static  const   char *getTypeExt(TYPE);
+       static  TYPE            getTypeFromStr(const char *str);
+       static  PROTOCOL        getProtocolFromStr(const char *str);
+
+       ::String        name;
+       GnuID   id,bcID;
+       int             bitrate;
+       TYPE    contentType;
+       PROTOCOL        srcProtocol;
+       unsigned int lastPlayStart,lastPlayEnd;
+       unsigned int numSkips;
+       unsigned int createdTime;
+
+       STATUS  status;
+
+       TrackInfo       track;
+       ::String        desc,genre,url,comment;
+
+};
+
+
+// ----------------------------------
+class ChanHit
+{
+public:
+       void    init();
+       void    initLocal(int numl,int numr,int nums,int uptm,bool,bool,unsigned int,Channel*,unsigned int,unsigned int);
+       XML::Node *createXML();
+
+       void    writeAtoms(AtomStream &,GnuID &);
+       bool    writeVariable(Stream &, const String &);
+
+       void    pickNearestIP(Host &);
+
+       Host                            host;
+       Host                            rhost[2];
+       unsigned int            numListeners,numRelays,numHops;
+       unsigned int            time,upTime,lastContact;
+       unsigned int            hitID;
+       GnuID                           sessionID,chanID;
+       unsigned int            version;
+       unsigned int            version_vp;
+
+       bool    firewalled:1,stable:1,tracker:1,recv:1,yp:1,dead:1,direct:1,relay:1,cin:1;
+       bool    relayfull:1,chfull:1,ratefull:1;
+
+       ChanHit *next;
+
+       int status;
+       int servent_id;
+
+       unsigned int            oldestPos,newestPos;
+       Host uphost;
+       unsigned int            uphostHops;
+
+       char                            version_ex_prefix[2];
+       unsigned int            version_ex_number;
+};
+// ----------------------------------
+class ChanHitList
+{
+public:
+       ChanHitList();
+       ~ChanHitList();
+
+       int             contactTrackers(bool,int,int,int);
+
+       ChanHit *addHit(ChanHit &);
+       void    delHit(ChanHit &);
+       void    deadHit(ChanHit &);
+       void    clearHits(bool);
+       int             numHits();
+       int             numListeners();
+       int             numRelays();
+       int             numFirewalled();
+       int             numTrackers();
+       int             closestHit();
+       int             furthestHit();
+       unsigned int            newestHit();
+
+       int                     pickHits(ChanHitSearch &);
+       int                     pickSourceHits(ChanHitSearch &);
+
+       bool    isUsed() {return used;}
+       int             clearDeadHits(unsigned int,bool);
+       XML::Node *createXML(bool addHits = true);
+
+       ChanHit *deleteHit(ChanHit *);
+
+       int             getTotalListeners();
+       int             getTotalRelays();
+       int             getTotalFirewalled();
+
+       bool    used;
+       ChanInfo        info;
+       ChanHit *hit;
+       unsigned int lastHitTime;
+       ChanHitList *next;
+
+
+};
+// ----------------------------------
+class ChanHitSearch
+{
+public:
+       enum
+       {
+               MAX_RESULTS = 8
+       };
+
+       ChanHitSearch() { init(); }
+       void init();
+
+       ChanHit best[MAX_RESULTS];
+       Host    matchHost;
+       unsigned int waitDelay;
+       bool    useFirewalled;
+       bool    trackersOnly;
+       bool    useBusyRelays,useBusyControls;
+       GnuID   excludeID;
+       int             numResults;
+       unsigned int seed;
+
+       int getRelayHost(Host host1, Host host2, GnuID exID, ChanHitList *chl);
+};
+
+// ----------------------------------
+class ChanMeta
+{
+public:
+       enum {
+               MAX_DATALEN = 65536
+       };
+
+       void    init()
+       {
+               len = 0;
+               cnt = 0;
+               startPos = 0;
+       }
+
+       void    fromXML(XML &);
+       void    fromMem(void *,int);
+       void    addMem(void *,int);
+
+       unsigned int len,cnt,startPos;
+       char    data[MAX_DATALEN];
+};
+
+
+
+// ------------------------------------------
+class RawStream : public ChannelStream
+{
+public:
+       virtual void readHeader(Stream &,Channel *);
+       virtual int readPacket(Stream &,Channel *);
+       virtual void readEnd(Stream &,Channel *);
+
+};
+
+// ------------------------------------------
+class PeercastStream : public ChannelStream
+{
+public:
+       virtual void readHeader(Stream &,Channel *);
+       virtual int  readPacket(Stream &,Channel *);
+       virtual void readEnd(Stream &,Channel *);
+};
+
+// ------------------------------------------
+class ChannelSource
+{
+public:
+       virtual ~ChannelSource() {}
+       virtual void stream(Channel *) = 0;
+
+       virtual int getSourceRate() {return 0;}
+
+};
+// ------------------------------------------
+class PeercastSource : public ChannelSource
+{
+public:
+
+
+       virtual void stream(Channel *);
+
+};
+
+
+// ----------------------------------
+class Channel
+{
+public:
+       
+       enum STATUS
+       {
+               S_NONE,
+               S_WAIT,
+               S_CONNECTING,
+               S_REQUESTING,
+               S_CLOSING,
+               S_RECEIVING,
+               S_BROADCASTING,
+               S_ABORT,
+               S_SEARCHING,
+               S_NOHOSTS,
+               S_IDLE,
+               S_ERROR,
+               S_NOTFOUND
+       };
+
+       enum TYPE
+       {
+               T_NONE,
+               T_ALLOCATED,
+               T_BROADCAST,
+               T_RELAY
+       };
+
+       enum SRC_TYPE
+       {
+               SRC_NONE,
+               SRC_PEERCAST,
+               SRC_SHOUTCAST,
+               SRC_ICECAST,
+               SRC_URL
+       };
+
+
+       Channel();
+       void    reset();
+       void    endThread(bool flg);
+
+       void    startMP3File(char *);
+       void    startGet();
+       void    startICY(ClientSocket *,SRC_TYPE);
+       void    startURL(const char *);
+
+
+       ChannelStream   *createSource();
+
+       void    resetPlayTime();
+
+       bool    notFound()
+       {
+               return (status == S_NOTFOUND);
+       }
+
+       bool    isPlaying()
+       {
+               return (status == S_RECEIVING) || (status == S_BROADCASTING);
+       }
+
+       bool    isReceiving()
+       {
+               return (status == S_RECEIVING);
+       }
+
+       bool    isBroadcasting()
+       {
+               return (status == S_BROADCASTING);
+       }
+
+       bool    isFull();
+
+       bool    checkBump();
+
+       bool    checkIdle();
+       void    sleepUntil(double);
+
+       bool    isActive()
+       {
+               return type != T_NONE;
+       }
+
+
+       void    connectFetch();
+       int             handshakeFetch();
+
+       bool    isIdle() {return isActive() && (status==S_IDLE);}
+
+       static THREAD_PROC      stream(ThreadInfo *);
+
+       static THREAD_PROC  waitFinish(ThreadInfo *);
+
+       void    setStatus(STATUS s);
+       const char  *getSrcTypeStr() {return srcTypes[srcType];}
+       const char      *getStatusStr() {return statusMsgs[status];}
+       const char      *getName() {return info.name.cstr();}
+       GnuID   getID() {return info.id;}
+       int             getBitrate() {return info.bitrate; }
+       void    getIDStr(char *s) {info.id.toStr(s);}
+       void    getStreamPath(char *);
+
+       void    broadcastTrackerUpdate(GnuID &,bool = false);
+       bool    sendPacketUp(ChanPacket &,GnuID &,GnuID &,GnuID &);
+
+       bool    writeVariable(Stream &, const String &,int);
+
+       bool    acceptGIV(ClientSocket *);
+
+       void    updateInfo(ChanInfo &);
+
+       int             readStream(Stream &,ChannelStream *);
+       
+       void    checkReadDelay(unsigned int);
+
+       void    processMp3Metadata(char *);
+
+       void    readHeader();
+
+       void    startStream();
+
+       XML::Node *createRelayXML(bool);
+
+       void    newPacket(ChanPacket &);
+
+       int             localListeners();
+       int             localRelays();
+
+       int             totalListeners();
+       int             totalRelays();
+
+       ::String mount;
+       ChanMeta        insertMeta;
+       ChanPacket      headPack;
+
+       ChanPacketBuffer        rawData;
+
+       ChannelStream *sourceStream;
+       unsigned int streamIndex;
+       
+
+       ChanInfo        info;
+       ChanHit         sourceHost;
+
+       GnuID           remoteID;
+
+
+       ::String  sourceURL;
+
+       bool    bump,stayConnected;
+       int             icyMetaInterval;
+       unsigned int streamPos;
+       unsigned int skipCount; //JP-EX
+       bool    readDelay;
+
+       TYPE    type;
+       ChannelSource *sourceData;
+
+       SRC_TYPE        srcType;
+
+       MP3Header mp3Head;
+       ThreadInfo      thread;
+       ThreadInfo  *finthread;
+
+       unsigned int lastIdleTime;
+       int             status;
+       static  char *statusMsgs[],*srcTypes[];
+
+       ClientSocket    *sock;
+       ClientSocket    *pushSock;
+
+       unsigned int lastTrackerUpdate;
+       unsigned int lastMetaUpdate;
+
+       double  startTime,syncTime;
+
+       WEvent  syncEvent;
+
+       Channel *next;
+
+       int channel_id;
+       ChanHit chDisp;
+       ChanHit trackerHit;
+       bool bumped;
+       unsigned int lastSkipTime;
+       unsigned int lastStopTime;
+};
+
+// ----------------------------------
+class ChanMgr
+{
+public:
+       enum {
+               MAX_IDLE_CHANNELS = 8,          // max. number of channels that can be left idle
+               MAX_METAINT = 8192                      // must be at least smaller than ChanPacket data len (ie. about half)
+               
+       };
+
+
+       ChanMgr();
+
+       Channel *deleteChannel(Channel *);
+
+       Channel *createChannel(ChanInfo &,const char *);
+       Channel *findChannelByName(const char *);
+       Channel *findChannelByIndex(int);
+       Channel *findChannelByMount(const char *);
+       Channel *findChannelByID(GnuID &);
+       Channel *findChannelByNameID(ChanInfo &);
+       Channel *findPushChannel(int);
+       Channel *findChannelByChannelID(int id);
+
+       void    broadcastTrackerSettings();
+       void    setUpdateInterval(unsigned int v);
+       void    broadcastRelays(Servent *,int,int);
+
+       int             broadcastPacketUp(ChanPacket &,GnuID &,GnuID &,GnuID &);
+       void    broadcastTrackerUpdate(GnuID &,bool = false);
+
+       bool    writeVariable(Stream &, const String &,int);
+
+       int             findChannels(ChanInfo &,Channel **,int);
+       int             findChannelsByStatus(Channel **,int,Channel::STATUS);
+       
+       int             numIdleChannels();
+       int             numChannels();
+
+       void    closeOldestIdle();
+       void    closeAll();
+       void    quit();
+
+       void    addHit(Host &,GnuID &,bool);
+       ChanHit *addHit(ChanHit &);
+       void    delHit(ChanHit &);
+       void    deadHit(ChanHit &);
+       void    setFirewalled(Host &);
+
+       ChanHitList *findHitList(ChanInfo &);
+       ChanHitList *findHitListByID(GnuID &);
+       ChanHitList     *addHitList(ChanInfo &);
+
+       void            clearHitLists();
+       void            clearDeadHits(bool);
+       int                     numHitLists();
+
+       void            setBroadcastMsg(::String &);
+
+       Channel         *createRelay(ChanInfo &,bool);
+       Channel         *findAndRelay(ChanInfo &);
+       void            startSearch(ChanInfo &);
+
+       void            playChannel(ChanInfo &);
+       void            findAndPlayChannel(ChanInfo &,bool);
+
+       bool            isBroadcasting(GnuID &);
+       bool            isBroadcasting();
+
+       int                     pickHits(ChanHitSearch &);
+
+
+
+       Channel         *channel;
+       ChanHitList     *hitlist;
+
+       GnuID   broadcastID;
+
+       ChanInfo        searchInfo;
+
+       int             numFinds;
+       ::String        broadcastMsg;
+       unsigned int            broadcastMsgInterval;
+       unsigned int lastHit,lastQuery;
+       unsigned int maxUptime;
+       bool    searchActive;
+       unsigned int            deadHitAge;
+       int             icyMetaInterval;
+       int             maxRelaysPerChannel;
+       WLock   lock;
+       int             minBroadcastTTL,maxBroadcastTTL;
+       int             pushTimeout,pushTries,maxPushHops;
+       unsigned int            autoQuery;
+       unsigned int    prefetchTime;
+       unsigned int    lastYPConnect;
+       unsigned int    lastYPConnect2;
+       unsigned int    icyIndex;
+
+       unsigned int    hostUpdateInterval;
+       unsigned int bufferTime;
+
+       GnuID   currFindAndPlayChannel;
+
+       WLock channellock;
+       WLock hitlistlock;
+};
+// ----------------------------------
+class PlayList
+{
+public:
+
+       enum TYPE
+       {
+               T_NONE,
+               T_SCPLS,
+               T_PLS,
+               T_ASX,
+               T_RAM,
+       };
+
+       PlayList(TYPE t, int max)
+       {
+               maxURLs = max;
+               numURLs = 0;
+               type = t;
+               urls = new ::String[max];
+               titles = new ::String[max];
+       }
+
+       ~PlayList()
+       {
+               delete [] urls;
+               delete [] titles;
+       }
+
+       void    addURL(const char *url, const char *tit)
+       {
+               if (numURLs < maxURLs)
+               {
+                       urls[numURLs].set(url);
+                       titles[numURLs].set(tit);
+                       numURLs++;
+               }
+       }
+       void    addChannels(const char *,Channel **,int);
+       void    addChannel(const char *,ChanInfo &);
+
+       void    writeSCPLS(Stream &);
+       void    writePLS(Stream &);
+       void    writeASX(Stream &);
+       void    writeRAM(Stream &);
+
+       void    readSCPLS(Stream &);
+       void    readPLS(Stream &);
+       void    readASX(Stream &);
+
+       void    read(Stream &s)
+       {
+               try
+               {
+                       switch (type)
+                       {
+                               case T_SCPLS: readSCPLS(s); break;
+                               case T_PLS: readPLS(s); break;
+                               case T_ASX: readASX(s); break;
+                       }
+               }catch(StreamException &) {}    // keep pls regardless of errors (eof isn`t handled properly in sockets)
+       }
+
+       void    write(Stream &s)
+       {
+               switch (type)
+               {
+                       case T_SCPLS: writeSCPLS(s); break;
+                       case T_PLS: writePLS(s); break;
+                       case T_ASX: writeASX(s); break;
+                       case T_RAM: writeRAM(s); break;
+               }
+       }
+
+       TYPE    type;
+       int             numURLs,maxURLs;
+       ::String        *urls,*titles;
+};
+
+// ----------------------------------
+
+extern ChanMgr *chanMgr;
+
+// for PCRaw start.
+bool isIndexTxt(ChanInfo *info);
+bool isIndexTxt(Channel *ch);
+int numMaxRelaysIndexTxt(Channel *ch);
+int canStreamIndexTxt(Channel *ch);
+// for PCRaw end
+
+#endif
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/common.h b/c:/Git/PeerCast.root/PeerCast/core/common/common.h
new file mode 100644 (file)
index 0000000..99a1c9b
--- /dev/null
@@ -0,0 +1,293 @@
+// ------------------------------------------------
+// File : common.h
+// Date: 4-apr-2002
+// Author: giles
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _COMMON_H
+#define _COMMON_H
+
+#pragma warning (disable: 4996)
+
+#include <stdio.h>
+#include <string.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+// ----------------------------------
+class GeneralException
+{
+public:
+    GeneralException(const char *m, int e = 0) 
+       {
+               strcpy(msg,m);
+               err=e;
+       }
+    char msg[128];
+       int err;
+};
+
+// -------------------------------------
+class StreamException : public GeneralException
+{
+public:
+       StreamException(const char *m) : GeneralException(m) {}
+       StreamException(const char *m,int e) : GeneralException(m,e) {}
+};
+
+// ----------------------------------
+class SockException : public StreamException
+{
+public:
+    SockException(const char *m="Socket") : StreamException(m) {}
+    SockException(const char *m, int e) : StreamException(m,e) {}
+};
+// ----------------------------------
+class EOFException : public StreamException
+{
+public:
+    EOFException(const char *m="EOF") : StreamException(m) {}
+    EOFException(const char *m, int e) : StreamException(m,e) {}
+};
+
+// ----------------------------------
+class CryptException : public StreamException
+{
+public:
+    CryptException(const char *m="Crypt") : StreamException(m) {}
+    CryptException(const char *m, int e) : StreamException(m,e) {}
+};
+
+
+// ----------------------------------
+class TimeoutException : public StreamException
+{
+public:
+    TimeoutException(const char *m="Timeout") : StreamException(m) {}
+};
+// --------------------------------
+class GnuID
+{
+public:
+       bool    isSame(GnuID &gid)
+       {
+               for(int i=0; i<16; i++)
+                       if (gid.id[i] != id[i])
+                               return false;
+               return true;
+       }
+
+
+       bool    isSet()
+       {
+               for(int i=0; i<16; i++)
+                       if (id[i] != 0)
+                               return true;
+               return false;
+       }
+
+       void    clear()
+       {
+               for(int i=0; i<16; i++)
+                       id[i] = 0;
+               storeTime = 0;
+       }
+
+
+       void    generate(unsigned char = 0);
+       void    encode(class Host *, const char *,const char *,unsigned char);
+
+       void    toStr(char *);
+       void    fromStr(const char *);
+
+       unsigned char   getFlags();
+
+       unsigned char id[16];
+       unsigned int storeTime;
+};
+// --------------------------------
+class GnuIDList 
+{
+public:
+       GnuIDList(int);
+       ~GnuIDList();
+       void    clear();
+       void    add(GnuID &);
+       bool    contains(GnuID &);
+       int             numUsed();
+       unsigned int getOldest();
+
+       GnuID   *ids;
+       int             maxID;
+};
+
+
+// ----------------------------------
+class Host
+{
+    inline unsigned int ip3()
+    {
+        return (ip>>24);
+    }
+    inline unsigned int ip2()
+    {
+        return (ip>>16)&0xff;
+    }
+    inline unsigned int ip1()
+    {
+        return (ip>>8)&0xff;
+    }
+    inline unsigned int ip0()
+    {
+        return ip&0xff;
+    }
+
+public:
+       Host(){init();}
+       Host(unsigned int i, unsigned short p)
+       {
+               ip = i;
+               port = p;
+               value = 0;
+       }
+
+       void    init()
+       {
+               ip = 0;
+               port = 0;
+               value = 0;
+       }
+
+
+       bool    isMemberOf(Host &);
+
+       bool    isSame(Host &h)
+       {
+               return (h.ip == ip) && (h.port == port);
+       }
+
+       bool classType() {return globalIP();}
+
+       bool    globalIP()
+       {
+               // local host
+               if ((ip3() == 127) && (ip2() == 0) && (ip1() == 0) && (ip0() == 1))
+                       return false;
+
+               // class A
+               if (ip3() == 10)
+                       return false;
+
+               // class B
+               if ((ip3() == 172) && (ip2() >= 16) && (ip2() <= 31))
+                       return false;
+
+               // class C
+               if ((ip3() == 192) && (ip2() == 168))
+                       return false;
+
+               return true;
+       }
+       bool    localIP()
+       {
+               return !globalIP();
+       }
+
+       bool    loopbackIP()
+       {
+//             return ((ipByte[3] == 127) && (ipByte[2] == 0) && (ipByte[1] == 0) && (ipByte[0] == 1));
+               return ((ip3() == 127) && (ip2() == 0) && (ip1() == 0) && (ip0() == 1));
+       }
+
+       bool    isValid()
+       {
+               return (ip != 0);
+       }
+
+
+       bool    isSameType(Host &h)
+       {
+                       return ( (globalIP() && h.globalIP()) ||
+                                (!globalIP() && !h.globalIP()) ); 
+       }
+
+       void    IPtoStr(char *str)
+       {
+               sprintf(str,"%d.%d.%d.%d",(ip>>24)&0xff,(ip>>16)&0xff,(ip>>8)&0xff,(ip)&0xff);
+       }
+
+       void    toStr(char *str)
+       {
+               sprintf(str,"%d.%d.%d.%d:%d",(ip>>24)&0xff,(ip>>16)&0xff,(ip>>8)&0xff,(ip)&0xff,port);
+       }
+
+       void    fromStrIP(const char *,int);
+       void    fromStrName(const char *,int);
+
+       bool    isLocalhost();
+
+
+       union
+       {
+               unsigned int ip;
+//             unsigned char ipByte[4];
+       };
+
+    unsigned short port;
+       unsigned int value;
+};
+// ----------------------------------
+#define SWAP2(v) ( ((v&0xff)<<8) | ((v&0xff00)>>8) )
+#define SWAP3(v) (((v&0xff)<<16) | ((v&0xff00)) | ((v&0xff0000)>>16) )
+#define SWAP4(v) (((v&0xff)<<24) | ((v&0xff00)<<8) | ((v&0xff0000)>>8) | ((v&0xff000000)>>24))
+#define TOUPPER(c) ((((c) >= 'a') && ((c) <= 'z')) ? (c)+'A'-'a' : (c))
+#define TONIBBLE(c) ((((c) >= 'A')&&((c) <= 'F')) ? (((c)-'A')+10) : ((c)-'0'))
+#define BYTES_TO_KBPS(n) (float)(((((float)n)*8.0f)/1024.0f))
+
+// ----------------------------------
+inline bool isWhiteSpace(char c)
+{
+       return (c == ' ') || (c == '\r') || (c == '\n') || (c == '\t');
+}
+
+// ----------------------------------
+inline int strToID(char *str)
+{
+       union {
+       int i;
+        char s[8];
+    };
+    strncpy(s,str,4);
+    return i;
+}
+
+// -----------------------------------
+char *getCGIarg(const char *str, const char *arg);
+bool cmpCGIarg(char *str, char *arg, char *value);
+bool hasCGIarg(char *str, char *arg);
+
+// ----------------------------------
+extern void LOG(const char *fmt,...);
+
+extern void LOG_ERROR(const char *fmt,...);
+extern void LOG_DEBUG(const char *fmt,...);
+extern void LOG_NETWORK(const char *fmt,...);
+extern void LOG_CHANNEL(const char *fmt,...);
+
+
+#endif
+
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/cstream.h b/c:/Git/PeerCast.root/PeerCast/core/common/cstream.h
new file mode 100644 (file)
index 0000000..f1a228b
--- /dev/null
@@ -0,0 +1,241 @@
+// ------------------------------------------------
+// File : cstream.h
+// Date: 12-mar-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _CSTREAM_H
+#define _CSTREAM_H
+
+// ----------------------------------
+
+class Channel;
+class ChanPacket;
+class ChanPacketv;
+class Stream;
+
+
+// ----------------------------------
+class ChanPacket
+{
+public:
+       enum 
+       {
+               MAX_DATALEN = 16384
+       };
+
+       enum TYPE
+       {
+               T_UNKNOWN       = 0,
+               T_HEAD          = 1,
+               T_DATA          = 2,
+               T_META          = 4,
+               T_PCP           = 16,
+               T_ALL           = 0xff
+       };
+
+       ChanPacket() 
+       {
+               init();
+       }
+
+       void    init()
+       {
+               type = T_UNKNOWN;
+               len = 0;
+               pos = 0;
+               sync = 0;
+               skip = false;
+       }
+       void    init(ChanPacketv &p);
+       void    init(TYPE t, const void *, unsigned int , unsigned int );
+
+       void    writeRaw(Stream &);
+       void    writePeercast(Stream &);
+       void    readPeercast(Stream &);
+
+
+       unsigned int sync;
+       unsigned int pos;
+       TYPE type;
+       unsigned int len;
+       char data[MAX_DATALEN];
+       bool skip;
+
+};
+// ----------------------------------
+class ChanPacketv
+{
+public:
+       enum {BSIZE = 0x100};
+       ChanPacketv() 
+       {
+               init();
+       }
+       ~ChanPacketv()
+       {
+               free();
+       }
+
+       void free()
+       {
+               if (data) {
+                       delete [] data;
+                       data = NULL;
+                       datasize = 0;
+               }
+       }
+       void reset()
+       {
+               free();
+               init();
+       }
+       void    init()
+       {
+               type = ChanPacket::T_UNKNOWN;
+               len = 0;
+               pos = 0;
+               sync = 0;
+               skip = false;
+               data = NULL;
+               datasize = 0;
+       }
+       void init(ChanPacket &p)
+       {
+               if (data && (datasize < p.len || datasize > p.len + BSIZE * 4)) {
+                       free();
+                       data = NULL;
+                       datasize = 0;
+               }
+               type = p.type;
+               len = p.len;
+               pos = p.pos;
+               sync = p.sync;
+               skip = p.skip;
+               if (!data) {
+                       datasize = (len & ~(BSIZE - 1)) + BSIZE;
+                       data = new char[datasize];
+               }
+               memcpy(data, p.data, len);
+       }
+       void init(ChanPacketv &p)
+       {
+               ChanPacket tp;
+               tp.init(p);
+               init(tp);
+       }
+
+       void    writeRaw(Stream &);
+       void    writePeercast(Stream &);
+       void    readPeercast(Stream &);
+
+       unsigned int sync;
+       unsigned int pos;
+       ChanPacket::TYPE type;
+       unsigned int len;
+       char *data;
+       unsigned int datasize;
+       bool skip;
+
+};
+// ----------------------------------
+class ChanPacketBuffer 
+{
+public:
+       enum {
+               MAX_PACKETS = 64,
+               NUM_SAFEPACKETS = 60 
+       };
+
+       void    init()
+       {
+               lock.on();
+               lastPos = firstPos = safePos = 0;
+               readPos = writePos = 0;
+               accept = 0;
+               lastWriteTime = 0;
+               for (int i = 0; i < MAX_PACKETS; i++) packets[i].reset();
+               lock.off();
+
+               lastSkipTime = 0;
+       }
+
+       int copyFrom(ChanPacketBuffer &,unsigned in);
+
+       bool    writePacket(ChanPacket &,bool = false);
+       void    readPacket(ChanPacket &);
+
+       bool    willSkip();
+
+       int             numPending() {return writePos-readPos;}
+
+       unsigned int    getLatestPos();
+       unsigned int    getOldestPos();
+       unsigned int    findOldestPos(unsigned int);
+       bool    findPacket(unsigned int,ChanPacket &);
+       unsigned int    getStreamPos(unsigned int);
+       unsigned int    getStreamPosEnd(unsigned int);
+       unsigned int    getLastSync();
+
+       //ChanPacket    packets[MAX_PACKETS];
+       ChanPacketv     packets[MAX_PACKETS];
+       volatile unsigned int lastPos,firstPos,safePos;
+       volatile unsigned int readPos,writePos;
+       unsigned int accept;
+       unsigned int lastWriteTime;
+       WLock lock;
+
+       unsigned int lastSkipTime;
+};
+
+// ----------------------------------
+class ChannelStream
+{
+public:
+       ChannelStream()
+       :numListeners(0)
+       ,numRelays(0) 
+       ,isPlaying(false)
+       ,fwState(0)
+       ,lastUpdate(0)
+       ,lastCheckTime(0)
+       ,parent(NULL)
+       {}
+       virtual ~ChannelStream() {}
+
+       void updateStatus(Channel *);
+       bool getStatus(Channel *,ChanPacket &);
+
+       virtual void kill() {}
+       virtual bool sendPacket(ChanPacket &,GnuID &) {return false;}
+       virtual void flush(Stream &) {}
+       virtual void readHeader(Stream &,Channel *)=0;
+       virtual int  readPacket(Stream &,Channel *)=0;
+       virtual void readEnd(Stream &,Channel *)=0;
+
+       void    readRaw(Stream &,Channel *);
+
+       int             numRelays;
+       int             numListeners;
+       bool    isPlaying;
+       int     fwState;
+       unsigned int lastUpdate;
+       unsigned int lastCheckTime;
+
+       Channel *parent;
+};
+
+#endif 
+
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/gnutella.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/gnutella.cpp
new file mode 100644 (file)
index 0000000..bff67fd
--- /dev/null
@@ -0,0 +1,751 @@
+// ------------------------------------------------
+// File : gnutella.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             GnuPacket is a Gnutella protocol packet.
+//             GnuStream is a Stream that reads/writes GnuPackets
+//
+//
+// (c) 2002 peercast.org
+// 
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "gnutella.h"
+#include "stream.h"
+#include "common.h"
+#include "servent.h"
+#include "servmgr.h"
+#include "stats.h"
+#include <stdlib.h>
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ---------------------------
+const char *GNU_FUNC_STR(int func)
+{
+       switch (func)
+       {
+               case GNU_FUNC_PING: return "PING"; break;
+               case GNU_FUNC_PONG: return "PONG"; break;
+               case GNU_FUNC_QUERY: return "QUERY"; break;
+               case GNU_FUNC_HIT: return "HIT"; break;
+               case GNU_FUNC_PUSH: return "PUSH"; break;
+               default: return "UNKNOWN"; break;
+       }
+}
+
+// ---------------------------
+const char *GnuStream::getRouteStr(R_TYPE r)
+{
+       switch(r)
+       {
+               case R_PROCESS: return "PROCESS"; break;
+               case R_DEAD: return "DEAD"; break;
+               case R_DISCARD: return "DISCARD"; break;
+               case R_ACCEPTED: return "ACCEPTED"; break;
+               case R_BROADCAST: return "BROADCAST"; break;
+               case R_ROUTE: return "ROUTE"; break;
+               case R_DUPLICATE: return "DUPLICATE"; break;
+               case R_BADVERSION: return "BADVERSION"; break;
+               case R_DROP: return "DROP"; break;
+               default: return "UNKNOWN"; break;
+       }
+}
+// ---------------------------
+void GnuPacket::makeChecksumID()
+{
+       for(unsigned int i=0; i<len; i++)
+               id.id[i%16] += data[i]; 
+}
+
+// ---------------------------
+void GnuPacket::initPing(int t)
+{
+       func = GNU_FUNC_PING;
+       ttl = t;
+       hops = 0;
+       len = 0;
+
+       id.generate();
+}
+// ---------------------------
+void GnuPacket::initPong(Host &h, bool ownPong, GnuPacket &ping)
+{
+       func = GNU_FUNC_PONG;
+       ttl = ping.hops;
+       hops = 0;
+       len = 14;
+       id = ping.id;
+
+       MemoryStream pk(data,len);
+
+       pk.writeShort(h.port);          // port
+       pk.writeLong(SWAP4(h.ip));      // ip
+       if (ownPong)
+       {
+               pk.writeLong(chanMgr->numChannels());   // cnt
+               pk.writeLong(servMgr->totalOutput(false));      // total
+       }else{
+               pk.writeLong(0);                                // cnt
+               pk.writeLong(0);                                // total
+       }
+
+
+}
+// ---------------------------
+void GnuPacket::initPush(ChanHit &ch, Host &sh)
+{
+#if 0
+       func = GNU_FUNC_PUSH;
+       ttl = ch.numHops;
+       hops = 0;
+       len = 26;
+       id.generate();
+
+       MemoryStream data(data,len);
+
+       // ID of Hit packet
+       data.write(ch.packetID.id,16);
+
+       // index of channel
+       data.writeLong(ch.index);
+
+       data.writeLong(SWAP4(sh.ip));   // ip
+       data.writeShort(sh.port);               // port
+#endif
+}
+
+
+// ---------------------------
+bool GnuPacket::initHit(Host &h, Channel *ch, GnuPacket *query, bool push, bool busy, bool stable, bool tracker, int maxttl)
+{
+       if (!ch)
+               return false;
+
+       func = GNU_FUNC_HIT;
+       hops = 0;
+       id.generate();
+
+       ttl = maxttl;
+
+
+       MemoryStream mem(data,MAX_DATA);
+
+       mem.writeChar(1);                       // num hits
+       mem.writeShort(h.port);         // port
+       mem.writeLong(SWAP4(h.ip));     // ip
+
+       if (query)
+               mem.writeLong(0);                       // speed - route
+       else
+               mem.writeLong(1);                       // broadcast
+
+       
+       //mem.writeLong(ch->index);                             // index
+       mem.writeLong(0);                               // index
+       mem.writeShort(ch->getBitrate());       // bitrate
+       mem.writeShort(ch->localListeners());           // num listeners
+
+       mem.writeChar(0);       // no name
+
+       XML xml;
+       XML::Node *cn = ch->info.createChannelXML();
+       cn->add(ch->info.createTrackXML());
+       xml.setRoot(cn);
+       xml.writeCompact(mem);
+
+       mem.writeChar(0);                                                       // extra null 
+
+
+       // QHD
+       mem.writeLong('PCST');                          // vendor ID            
+       mem.writeChar(2);                                       // public sector length 
+
+       int f1 = 0, f2 = 0;
+
+       f1 = 1 | 4 | 8 | 32 | 64;       // use push | busy | stable | broadcast | tracker 
+
+       if (push) f2 |= 1;                      
+       if (busy) f2 |= 4;
+       if (stable) f2 |= 8;
+       if (!query) f2 |= 32;
+       if (tracker) f2 |= 64;
+       
+       mem.writeChar(f1);
+       mem.writeChar(f2);
+
+       {
+               // write private sector
+               char pbuf[256];
+               MemoryStream pmem(pbuf,sizeof(pbuf));
+               XML xml;
+               XML::Node *pn = servMgr->createServentXML();
+               xml.setRoot(pn);
+               xml.writeCompact(pmem);
+               pmem.writeChar(0);                      // add null terminator
+               if (pmem.pos <= 255)
+               {
+                       mem.writeChar(pmem.pos);
+                       mem.write(pmem.buf,pmem.pos);
+               }else
+                       mem.writeChar(0);
+       }
+
+
+       // queryID/not used
+       if (query)
+               mem.write(query->id.id,16);                                     
+       else
+               mem.write(id.id,16);                                    
+
+       len = mem.pos;
+
+       LOG_NETWORK("Created Hit packet: %d bytes",len);
+
+       if (len >= MAX_DATA)
+               return false;
+
+//     servMgr->addReplyID(id);
+       return true;
+}
+
+
+// ---------------------------
+void GnuPacket::initFind(const char *str, XML *xml, int maxTTL)
+{
+
+       func = GNU_FUNC_QUERY;
+       ttl = maxTTL;
+       hops = 0;
+       id.generate();
+
+       MemoryStream mem(data,MAX_DATA);
+
+       mem.writeShort(0);              // min speed
+
+       if (str)
+       {
+               int slen = strlen(str);
+               mem.write((void *)str,slen+1);  // string
+       }else
+               mem.writeChar(0);               // null string
+
+       
+       if (xml)
+               xml->writeCompact(mem);
+
+       len = mem.pos;
+}
+
+// ---------------------------
+void GnuStream::ping(int ttl)
+{
+       GnuPacket ping;
+       ping.initPing(ttl);
+//     servMgr->addReplyID(ping.id);
+       sendPacket(ping);
+       LOG_NETWORK("ping out %02x%02x%02x%02x",ping.id.id[0],ping.id.id[1],ping.id.id[2],ping.id.id[3]);
+}
+
+// ---------------------------
+void GnuStream::sendPacket(GnuPacket &p)
+{
+       try 
+       {
+               lock.on();
+               packetsOut++;
+               stats.add(Stats::NUMPACKETSOUT);
+
+               switch(p.func)
+               {
+                       case GNU_FUNC_PING: stats.add(Stats::NUMPINGOUT); break;
+                       case GNU_FUNC_PONG: stats.add(Stats::NUMPONGOUT); break;
+                       case GNU_FUNC_QUERY: stats.add(Stats::NUMQUERYOUT); break;
+                       case GNU_FUNC_HIT: stats.add(Stats::NUMHITOUT); break;
+                       case GNU_FUNC_PUSH: stats.add(Stats::NUMPUSHOUT); break;
+                       default: stats.add(Stats::NUMOTHEROUT); break;
+               }
+
+
+               write(p.id.id,16);
+               writeChar(p.func);      // ping func
+               writeChar(p.ttl);       // ttl
+               writeChar(p.hops);      // hops
+               writeLong(p.len);       // len
+
+               if (p.len)
+                       write(p.data,p.len);
+
+               stats.add(Stats::PACKETDATAOUT,23+p.len);
+
+               lock.off();
+       }catch(StreamException &e)
+       {               
+               lock.off();
+               throw e;
+       }
+}
+// ---------------------------
+bool GnuStream::readPacket(GnuPacket &p)
+{
+       try 
+       {
+               lock.on();
+               packetsIn++;
+               stats.add(Stats::NUMPACKETSIN);
+
+               read(p.id.id,16);
+               p.func = readChar();
+               p.ttl = readChar();
+               p.hops = readChar();
+               p.len = readLong();
+
+
+               if ((p.hops >= 1) && (p.hops <= 10))
+                       stats.add((Stats::STAT)((int)Stats::NUMHOPS1+p.hops-1));
+
+               stats.add(Stats::PACKETDATAIN,23+p.len);
+
+               switch(p.func)
+               {
+                       case GNU_FUNC_PING: stats.add(Stats::NUMPINGIN); break;
+                       case GNU_FUNC_PONG: stats.add(Stats::NUMPONGIN); break;
+                       case GNU_FUNC_QUERY: stats.add(Stats::NUMQUERYIN); break;
+                       case GNU_FUNC_HIT: stats.add(Stats::NUMHITIN); break;
+                       case GNU_FUNC_PUSH: stats.add(Stats::NUMPUSHIN); break;
+                       default: stats.add(Stats::NUMOTHERIN); break;
+               }
+
+
+               if (p.len)
+               {
+                       if (p.len > GnuPacket::MAX_DATA)
+                       {
+                               while (p.len--)
+                                       readChar();
+                               lock.off();
+                               return false;
+                       }
+                       read(p.data,p.len);
+               }
+
+               lock.off();
+               return true;
+       }catch(StreamException &e)
+       {               
+               lock.off();
+               throw e;
+       }
+}
+
+// ---------------------------
+GnuStream::R_TYPE GnuStream::processPacket(GnuPacket &in, Servent *serv, GnuID &routeID)
+{
+
+       R_TYPE ret = R_DISCARD;
+
+       MemoryStream data(in.data,in.len);
+
+       Host remoteHost = serv->getHost();
+
+       in.ttl--;
+       in.hops++;
+
+       routeID = in.id;
+
+
+
+       switch(in.func)
+       {
+               case GNU_FUNC_PING: // ping
+                       {
+                               LOG_NETWORK("ping: from %d.%d.%d.%d : %02x%02x%02x%02x",
+                                                       remoteHost.ip>>24&0xff,remoteHost.ip>>16&0xff,remoteHost.ip>>8&0xff,remoteHost.ip&0xff,
+                                                       in.id.id[0],in.id.id[1],in.id.id[2],in.id.id[3]
+                                       );
+                               Host sh = servMgr->serverHost;
+                               if (sh.isValid())
+                               {
+                                       if ((servMgr->getFirewall() != ServMgr::FW_ON) && (!servMgr->pubInFull()))
+                                       {
+                                               GnuPacket pong;
+                                               pong.initPong(sh,true,in);
+                                               if (serv->outputPacket(pong,true))
+                                                       LOG_NETWORK("pong out");
+                                       }
+                                       ret = R_BROADCAST;                      
+                               }
+                       }
+                       break;
+               case GNU_FUNC_PONG: // pong
+                       {
+                               {
+                                       int ip,port,cnt,total;
+                                       port = data.readShort();
+                                       ip = data.readLong();
+                                       cnt = data.readLong();
+                                       total = data.readLong();
+
+                                       ip = SWAP4(ip);
+
+
+                                       Host h;
+                                       h.ip = ip;
+                                       h.port = port;
+
+                                       char sIP[64],rIP[64];
+                                       h.toStr(sIP);
+                                       remoteHost.toStr(rIP);
+                                       
+                                       LOG_NETWORK("pong: %s via %s : %02x%02x%02x%02x",sIP,ip,rIP,in.id.id[0],in.id.id[1],in.id.id[2],in.id.id[3]);
+
+
+                                       ret = R_DISCARD;
+
+                                       if (h.isValid())
+                                       {
+
+                                               #if 0
+                                               // accept if this pong is a reply from one of our own pings, otherwise route back
+                                               if (servMgr->isReplyID(in.id))
+                                               {
+                                                       servMgr->addHost(h,ServHost::T_SERVENT,sys->getTime());
+                                                       ret = R_ACCEPTED;
+                                               }else
+                                                       ret = R_ROUTE;
+                                               #endif
+                                       }
+
+                               }
+                       }
+                       break;
+               case GNU_FUNC_QUERY: // query
+                       ret = R_BROADCAST;
+
+                       {
+                               Host sh = servMgr->serverHost;
+                               if (!sh.isValid())
+                                       sh.ip = 127<<24|1;
+
+                               char words[256];
+                               short spd = data.readShort();
+                               data.readString(words,sizeof(words));
+                               words[sizeof(words)-1] = 0;
+
+                               MemoryStream xm(&data.buf[data.pos],data.len-data.pos);
+                               xm.buf[xm.len] = 0;
+
+                               Channel *hits[16];
+                               int numHits=0;
+
+                               if (strncmp(xm.buf,"<?xml",5)==0)
+                               {
+                                       XML xml;
+                                       xml.read(xm);
+                                       XML::Node *cn = xml.findNode("channel");
+                                       if (cn)
+                                       {
+                                               ChanInfo info;
+                                               info.init(cn);
+                                               info.status = ChanInfo::S_PLAY;
+                                               numHits = chanMgr->findChannels(info,hits,16);
+                                       }
+                                       LOG_NETWORK("query XML: %s : found %d",xm.buf,numHits);
+                               }else{
+                                       ChanInfo info;
+                                       info.name.set(words);
+                                       info.genre.set(words);
+                                       info.id.fromStr(words);
+                                       info.status = ChanInfo::S_PLAY;
+                                       numHits = chanMgr->findChannels(info,hits,16);
+                                       LOG_NETWORK("query STR: %s : found %d",words,numHits);
+                               }
+
+                       
+
+                               for(int i=0; i<numHits; i++)
+                               {
+                                       bool push = (servMgr->getFirewall()!=ServMgr::FW_OFF);
+                                       bool busy = (servMgr->pubInFull() && servMgr->outFull()) || servMgr->relaysFull();
+                                       bool stable = servMgr->totalStreams>0;
+                                       bool tracker =  hits[i]->isBroadcasting();
+
+                                       GnuPacket hit;
+                                       if (hit.initHit(sh,hits[i],&in,push,busy,stable,tracker,in.hops))
+                                               serv->outputPacket(hit,true);
+                               }
+                       }
+                       break;
+               case GNU_FUNC_PUSH:     // push
+                       {
+
+                               GnuID pid;
+                               data.read(pid.id,16);
+                               
+                               //LOG("push serv= %02x%02x%02x%02x",servMgr->id[0],servMgr->id[1],servMgr->id[2],servMgr->id[3]);
+                               //LOG("pack = %02x%02x%02x%02x",id[0],id[1],id[2],id[3]);
+
+
+                               int index = data.readLong();
+                               int ip = data.readLong();
+                               int port = data.readShort();
+
+                       
+                               ip = SWAP4(ip);
+
+                               Host h(ip,port);
+                               char hostName[64];
+                               h.toStr(hostName);
+
+#if 0
+                               if (servMgr->isReplyID(pid))
+                               {
+#if 0
+                                       Channel *c = chanMgr->findChannelByIndex(index);
+
+                                       if (!c)
+                                       {
+                                               LOG_NETWORK("push 0x%x to %s: Not found",index,hostName);
+                                       }else
+                                       {
+                                               if (!c->isFull() && !servMgr->streamFull())
+                                               {
+                                                       LOG_NETWORK("push: 0x%x to %s: OK",index,hostName);
+
+                                                       Servent *s = servMgr->allocServent();
+                                                       if (s)
+                                                               s->initGIV(h,c->info.id);
+                                               }else
+                                                       LOG_NETWORK("push: 0x%x to %s: FULL",index,hostName);
+                                       }
+#endif
+                                       ret = R_ACCEPTED;
+                               }else{
+                                       LOG_NETWORK("push: 0x%x to %s: ROUTE",index,hostName);
+                                       routeID = pid;
+                                       ret = R_ROUTE;
+                               }
+#endif         
+                       }
+                       break;
+               case GNU_FUNC_HIT: // hit
+                       {
+                               ret = R_DISCARD;
+
+                               ChanHit hit;
+                               if (readHit(data,hit,in.hops,in.id))
+                               {
+
+                                       char flstr[64];
+                                       flstr[0]=0;
+                                       if (hit.firewalled) strcat(flstr,"Push,");
+                                       if (hit.tracker) strcat(flstr,"Tracker,");
+                                       
+#if 0
+                                       if ((spd == 0) && (!isBroadcastHit))
+                                       {
+                                               if (servMgr->isReplyID(queryID))
+                                               {
+                                                       ret = R_ACCEPTED;
+                                                       LOG_NETWORK("self-hit: %s 0x%02x %s %d chan",hostName,f2,flstr,num);
+                                               }else
+                                               {
+                                                       routeID = queryID;
+                                                       ret = R_ROUTE;
+                                                       LOG_NETWORK("route-hit: %s 0x%02x %s %d chan",hostName,f2,flstr,num);
+                                               }
+                                       }else
+                                       {
+                                               ret = R_BROADCAST;
+                                               LOG_NETWORK("broadcast-hit: %s 0x%02x %s %d chan",hostName,f2,flstr,num);
+                                       }
+#else
+                                       ret = R_BROADCAST;
+                                       LOG_NETWORK("broadcast-hit: %s",flstr);
+#endif
+                               }
+                       }
+                       break;
+               default:
+                       LOG_NETWORK("packet: %d",in.func);
+                       break;
+       }
+
+       
+       if ((in.ttl > 10) || (in.hops > 10) || (in.ttl==0))
+               if ((ret == R_BROADCAST) || (ret == R_ROUTE))
+                       ret = R_DEAD;
+
+       return ret;
+}
+
+// ---------------------------
+bool GnuStream::readHit(Stream &data, ChanHit &ch,int hops,GnuID &id)
+{
+       int i;
+       int num = data.readChar();      // hits
+       int port = data.readShort();            // port
+       int ip = data.readLong();               // ip
+       ip = SWAP4(ip);
+       int spd = data.readLong();              // speed/broadcast
+
+       Host h(ip,port);
+       char hostName[64];
+
+       h.IPtoStr(hostName);
+
+       bool dataValid=true;
+
+       ChanHit *hits[100];
+       int numHits=0;
+
+       for(i=0; i<num; i++)
+       {
+               int index,bitrate,listeners;
+
+
+               index = data.readLong();                // index
+               bitrate = data.readShort();             // bitrate
+               listeners = data.readShort();   // listeners
+
+               // read name .. not used.
+               char fname[256];
+               data.readString(fname,sizeof(fname));
+               fname[sizeof(fname)-1] = 0;
+
+               ch.init();
+               ch.firewalled = false;          // default to NO as we dont get the info until the next section.
+               ch.host = h;
+               ch.numListeners = listeners;
+               ch.numHops = hops;
+               ch.rhost[0] = ch.host;
+
+               ChanInfo info;
+
+
+               {
+                       char xmlData[4000];
+                       int xlen = data.readString(xmlData,sizeof(xmlData));
+
+                       if ((strncmp(xmlData,"<?xml",5)==0) && (xlen < GnuPacket::MAX_DATA))
+                       {
+                               //LOG_NETWORK("Hit XML: %s",xmlData);
+
+                               MemoryStream xm(xmlData,xlen);
+                               XML xml;
+                               xml.read(xm);
+                               XML::Node *n = xml.findNode("channel");
+                               if (n)
+                               {
+                                       info.init(n);
+                                       char idStr[64];
+                                       info.id.toStr(idStr);
+                                       LOG_NETWORK("got hit %s %s",idStr,info.name.cstr());
+
+                                       ch.upTime = n->findAttrInt("uptime");
+
+                               }else
+                                       LOG_NETWORK("Missing Channel node");
+                       }else
+                       {
+                               LOG_NETWORK("Missing XML data");
+                               //LOG_NETWORK("%s",xmlData);
+                               dataValid = false;
+                       }
+               }
+
+               if (info.id.isSet())
+               {
+                       if (!chanMgr->findHitList(info))
+                               chanMgr->addHitList(info);
+
+                       ch.recv = true;
+                       ch.chanID = info.id;
+                       ChanHit *chp = chanMgr->addHit(ch);             
+
+                       if ((chp) && (numHits<100))
+                               hits[numHits++] = chp;
+               }
+
+       }
+
+
+       int vendor = data.readLong();   // vendor ID
+
+       int pubLen = data.readChar();   // public sec length - should be 2
+
+       int f1 = data.readChar() & 0xff; // flags 1
+       int f2 = data.readChar() & 0xff; // flags 2
+
+       pubLen -= 2;
+       while (pubLen-->0)
+               data.readChar();
+
+
+       char agentStr[16];
+       agentStr[0]=0;
+       int maxPreviewTime=0;
+
+       // read private sector with peercast servant specific info
+       int privLen = data.readChar();  
+
+       if (privLen)
+       {
+               char privData[256];
+               data.read(privData,privLen);
+               if (strncmp(privData,"<?xml",5)==0)
+               {
+                       MemoryStream xm(privData,privLen);
+                       XML xml;
+                       xml.read(xm);
+                       XML::Node *sn = xml.findNode("servent");
+                       if (sn)
+                       {
+                               char *ag = sn->findAttr("agent");
+                               if (ag)
+                               {
+                                       strncpy(agentStr,ag,16);
+                                       agentStr[15]=0;
+                               }
+                               maxPreviewTime = sn->findAttrInt("preview");
+                       }
+
+               }
+       }
+
+
+       // not used anymore
+       GnuID queryID;
+       data.read(queryID.id,16);
+
+       bool isBroadcastHit=false;
+       if (f1 & 32)
+               isBroadcastHit = (f2 & 32)!=0;
+
+       for(i=0; i<numHits; i++)
+       {
+               if (f1 & 1)
+                       hits[i]->firewalled = (f2 & 1)!=0;
+
+               if (f1 & 64)
+                       hits[i]->tracker = (f2 & 64)!=0;
+
+       }
+
+       return dataValid;
+}
+
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/gnutella.h b/c:/Git/PeerCast.root/PeerCast/core/common/gnutella.h
new file mode 100644 (file)
index 0000000..d31c580
--- /dev/null
@@ -0,0 +1,295 @@
+// ------------------------------------------------
+// File : gnutella.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _GNUTELLA_H
+#define _GNUTELLA_H
+
+// --------------------------------
+#include "stream.h"
+#include "sys.h"
+
+
+
+#define GNUTELLA_SETUP 0
+
+
+// --------------------------------
+static const int GNU_FUNC_PING = 0;
+static const int GNU_FUNC_PONG = 1;
+static const int GNU_FUNC_QUERY = 128;
+static const int GNU_FUNC_HIT  = 129;
+static const int GNU_FUNC_PUSH = 64;
+
+extern const char *GNU_FUNC_STR(int);
+
+// --------------------------------
+static const char *GNU_PEERCONN                = "PEERCAST CONNECT/0.1";
+static const char *GNU_CONNECT                 = "GNUTELLA CONNECT/0.6";
+static const char *GNU_OK                      = "GNUTELLA/0.6 200 OK";
+static const char *PCX_PCP_CONNECT     = "pcp";
+
+static const char *PCX_HS_OS           = "x-peercast-os:";
+static const char *PCX_HS_DL           = "x-peercast-download:"; 
+static const char *PCX_HS_ID           = "x-peercast-id:"; 
+static const char *PCX_HS_CHANNELID    = "x-peercast-channelid:"; 
+static const char *PCX_HS_NETWORKID    = "x-peercast-networkid:"; 
+static const char *PCX_HS_MSG          = "x-peercast-msg:"; 
+static const char *PCX_HS_SUBNET       = "x-peercast-subnet:"; 
+static const char *PCX_HS_FULLHIT      = "x-peercast-fullhit:"; 
+static const char *PCX_HS_MINBCTTL     = "x-peercast-minbcttl:"; 
+static const char *PCX_HS_MAXBCTTL     = "x-peercast-maxbcttl:"; 
+static const char *PCX_HS_RELAYBC      = "x-peercast-relaybc:"; 
+static const char *PCX_HS_PRIORITY     = "x-peercast-priority:"; 
+static const char *PCX_HS_FLOWCTL      = "x-peercast-flowctl:"; 
+static const char *PCX_HS_PCP          = "x-peercast-pcp:"; 
+static const char *PCX_HS_PINGME       = "x-peercast-pingme:"; 
+static const char *PCX_HS_PORT         = "x-peercast-port:"; 
+static const char *PCX_HS_REMOTEIP     = "x-peercast-remoteip:"; 
+static const char *PCX_HS_POS          = "x-peercast-pos:"; 
+static const char *PCX_HS_SESSIONID    = "x-peercast-sessionid:"; 
+
+// official version number sent to relay to check for updates 
+static const char *PCX_OS_WIN32        = "Win32";
+static const char *PCX_OS_LINUX        = "Linux";
+static const char *PCX_OS_MACOSX       = "Apple-OSX";
+static const char *PCX_OS_WINAMP2      = "Win32-WinAmp2";
+static const char *PCX_OS_ACTIVEX      = "Win32-ActiveX";
+
+static const char *PCX_DL_URL          = "http://www.peercast.org/download.php"; 
+
+// version number sent to other clients
+static const char *PCX_OLDAGENT        = "PeerCast/0.119E";
+
+
+
+
+
+// version number used inside packets GUIDs
+static const int PEERCAST_PACKETID     = 0x0000119E;
+
+static const char *MIN_ROOTVER         = "0.119E";
+
+static const char *MIN_CONNECTVER      = "0.119D";
+static const int MIN_PACKETVER     = 0x0000119D;
+
+static const char *ICY_OK      = "ICY 200 OK";
+
+// --------------------------------
+
+static const int DEFAULT_PORT  = 7144;
+
+// --------------------------------
+
+class Servent;
+class Channel;
+class ChanHit;
+
+
+// --------------------------------
+class GnuPacket
+{
+public:
+
+
+       // --------------------------------
+       class Hash
+       {
+       public:
+
+               bool    isSame(Hash &h)
+               {
+                       return (idChecksum == h.idChecksum) && (dataChecksum == h.dataChecksum);
+               }
+
+               bool    isSameID(Hash &h)
+               {
+                       return (idChecksum == h.idChecksum);
+               }
+
+               unsigned int idChecksum;
+               unsigned int dataChecksum;
+
+       };
+       // --------------------------------
+
+       enum {
+               MAX_DATA = 2000
+       };
+
+       void    initPing(int);
+       void    initPong(Host &, bool, GnuPacket &);
+       void    initFind(const char *, class XML *,int);
+       bool    initHit(Host &, Channel *, GnuPacket *,bool,bool,bool,bool,int);
+       void    initPush(ChanHit &, Host &);
+
+
+       void makeChecksumID();
+
+       unsigned char func;
+       unsigned char ttl;
+       unsigned char hops;
+       unsigned int    len;
+       Hash    hash;
+       GnuID   id;
+
+       char data[MAX_DATA];
+};
+// --------------------------------
+class GnuPacketBuffer
+{
+public:
+       GnuPacketBuffer(int s) 
+       :size(s)
+       ,packets(new GnuPacket[size])
+       {
+               reset();
+       }
+       ~GnuPacketBuffer()
+       {
+               delete [] packets;
+       }
+
+       void    reset()
+       {
+               readPtr = writePtr = 0;
+       }
+
+       GnuPacket *curr()
+       {
+               if (numPending())
+                       return &packets[readPtr%size];
+               else
+                       return NULL;
+
+       }
+       void    next()
+       {
+               readPtr++;
+       }
+
+       int findMinHop()
+       {
+               int min=100;
+               int n = numPending();
+               for(int i=0; i<n; i++)
+               {
+                       int idx = (readPtr+i)%size;
+                       if (packets[idx].hops < min)
+                               min = packets[idx].hops;
+               }
+               return min;
+       }
+       int findMaxHop()
+       {
+               int max=0;
+               int n = numPending();
+               for(int i=0; i<n; i++)
+               {
+                       int idx = (readPtr+i)%size;
+                       if (packets[idx].hops > max)
+                               max = packets[idx].hops;
+               }
+               return max;
+       }
+
+       int percentFull()
+       {
+               return (numPending()*100) / size;
+       }
+
+       
+       int sizeOfPending()
+       {
+               int tot=0;
+               int n = numPending();
+               for(int i=0; i<n; i++)
+                       tot+=packets[(readPtr+i)%size].len;
+               return tot;
+       }
+
+       int     numPending()
+       {
+               return writePtr-readPtr;
+       }
+
+       bool    write(GnuPacket &p) 
+       {
+               if ((writePtr-readPtr) >= size)
+                       return false;
+               else
+               {
+                       packets[writePtr%size] = p;
+                       writePtr++;
+                       return true;
+               }
+       }
+
+       int     size;
+       GnuPacket *packets;
+       int     readPtr,writePtr;
+};
+
+
+
+// --------------------------------
+class GnuStream : public IndirectStream
+{
+public:
+
+       enum R_TYPE
+       {
+               R_PROCESS,
+               R_DEAD,
+               R_DISCARD,
+               R_ACCEPTED,
+               R_BROADCAST,
+               R_ROUTE,
+               R_DUPLICATE,
+               R_BADVERSION,
+               R_DROP
+       };
+
+       GnuStream()
+       {
+               init(NULL);
+       }
+
+       void    init(Stream *s)  
+       {
+               IndirectStream::init(s);
+               packetsIn = packetsOut = 0;
+       }
+
+       bool    readPacket(GnuPacket &);
+       void    sendPacket(GnuPacket &);
+       R_TYPE  processPacket(GnuPacket &, Servent *, GnuID &);
+
+       static const char *getRouteStr(R_TYPE);
+       bool    readHit(Stream &data, ChanHit &ch,int,GnuID &);
+
+
+       
+       void    ping(int);
+
+       int             packetsIn,packetsOut;
+       WLock   lock;
+};
+
+
+#endif
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/html-xml.h b/c:/Git/PeerCast.root/PeerCast/core/common/html-xml.h
new file mode 100644 (file)
index 0000000..ae1d93a
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef _HTML_H
+#define _HTML_H
+
+// ---------------------------------------
+#include "xml.h"
+
+// ---------------------------------------
+class HTML : public XML
+{
+public:
+       HTML(const char *);
+
+       
+       void    startNode(XML::Node *, const char * = NULL);
+       void    addLink(const char *, const char *);
+       void    addArgLink(const char *, const char *);
+       XML::Node *startTag(const char *, const char * = NULL,...);
+       XML::Node *startTagEnd(const char *, const char * = NULL,...);
+       void    startSingleTagEnd(const char *,...);
+       void    startTableRow(int);
+       void    end();
+       void    addRefresh(int);
+
+       char    defArgs[128];
+       XML::Node       *currNode,*headNode,*htmlNode;
+};
+
+#endif
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/html.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/html.cpp
new file mode 100644 (file)
index 0000000..ff659ac
--- /dev/null
@@ -0,0 +1,558 @@
+// ------------------------------------------------
+// File : html.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             HTML protocol handling
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include "html.h"
+#include "http.h"
+#include "stream.h"
+#include "gnutella.h"
+#include "servmgr.h"
+#include "channel.h"
+#include "stats.h"
+#include "version2.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+// --------------------------------------
+HTML::HTML(const char *t, Stream &o)
+{
+       o.writeCRLF = false;
+       out = new WriteBufferStream(8192, &o);
+       out->writeCRLF = false;
+
+       title.set(t);
+       tagLevel = 0;
+       refresh = 0;
+}
+
+HTML::~HTML()
+{
+       try {
+               out->flush();
+       } catch (StreamException &) {}
+       delete out;
+}
+
+// --------------------------------------
+void HTML::writeOK(const char *content)
+{
+       out->writeLine(HTTP_SC_OK);
+       out->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT);
+       //out->writeLine("%s %s",HTTP_HS_CACHE,"no-cache");
+       out->writeLineF("%s %s",HTTP_HS_CONNECTION,"close");
+    out->writeLineF("%s %s",HTTP_HS_CONTENT,content);
+       out->writeLine("");
+}
+// --------------------------------------
+void HTML::writeVariable(Stream &s,const String &varName, int loop)
+{
+       bool r=false;
+       if (varName.startsWith("servMgr."))
+               r=servMgr->writeVariable(s,varName+8);
+       else if (varName.startsWith("chanMgr."))
+               r=chanMgr->writeVariable(s,varName+8,loop);
+       else if (varName.startsWith("stats."))
+               r=stats.writeVariable(s,varName+6);
+       else if (varName.startsWith("sys."))
+       {
+               if (varName == "sys.log.dumpHTML")
+               {
+                       sys->logBuf->dumpHTML(s);
+                       r=true;
+               }
+       }
+       else if (varName.startsWith("loop."))
+       {
+               if (varName.startsWith("loop.channel."))
+               {
+                       Channel *ch = chanMgr->findChannelByIndex(loop);
+                       if (ch)
+                               r = ch->writeVariable(s,varName+13,loop);
+               }else if (varName.startsWith("loop.servent."))
+               {
+                       Servent *sv = servMgr->findServentByIndex(loop);
+                       if (sv)
+                               r = sv->writeVariable(s,varName+13);
+               }else if (varName.startsWith("loop.filter."))
+               {
+                       ServFilter *sf = &servMgr->filters[loop];
+                       r = sf->writeVariable(s,varName+12);
+
+               }else if (varName.startsWith("loop.bcid."))
+               {
+                       BCID *bcid = servMgr->findValidBCID(loop);
+                       if (bcid)
+                               r = bcid->writeVariable(s,varName+10);
+               
+               }else if (varName == "loop.indexEven")
+               {
+                       s.writeStringF("%d",(loop&1)==0);
+                       r = true;
+               }else if (varName == "loop.index")
+               {
+                       s.writeStringF("%d",loop);
+                       r = true;
+               }else if (varName.startsWith("loop.hit."))
+               {
+                       char *idstr = getCGIarg(tmplArgs,"id=");
+                       if (idstr)
+                       {
+                               GnuID id;
+                               id.fromStr(idstr);
+                               ChanHitList *chl = chanMgr->findHitListByID(id);
+                               if (chl)
+                               {
+                                       int cnt=0;
+                                       ChanHit *ch = chl->hit;
+                                       while (ch)
+                                       {
+                                               if (ch->host.ip && !ch->dead)
+                                               {
+                                                       if (cnt == loop)
+                                                       {
+                                                               r = ch->writeVariable(s,varName+9);
+                                                               break;
+                                                       }
+                                                       cnt++;
+                                               }
+                                               ch=ch->next;
+                                       }
+
+                               }
+                       }
+               }
+
+       }
+       else if (varName.startsWith("page."))
+       {
+               if (varName.startsWith("page.channel."))
+               {
+                       char *idstr = getCGIarg(tmplArgs,"id=");
+                       if (idstr)
+                       {
+                               GnuID id;
+                               id.fromStr(idstr);
+                               Channel *ch = chanMgr->findChannelByID(id);
+                               if (ch)
+                                       r = ch->writeVariable(s,varName+13,loop);
+                       }
+               }else
+               {
+
+                       String v = varName+5;
+                       v.append('=');
+                       char *a = getCGIarg(tmplArgs,v);
+                       if (a)
+                       {
+                               s.writeString(a);               
+                               r=true;
+                       }
+               }
+       }
+
+
+       if (!r)
+               s.writeString(varName);
+}
+// --------------------------------------
+int HTML::getIntVariable(const String &varName,int loop)
+{
+       String val;
+       MemoryStream mem(val.cstr(),String::MAX_LEN);
+
+       writeVariable(mem,varName,loop);
+
+       return atoi(val.cstr());
+}
+// --------------------------------------
+bool HTML::getBoolVariable(const String &varName,int loop)
+{
+       String val;
+       MemoryStream mem(val.cstr(),String::MAX_LEN);
+
+       writeVariable(mem,varName,loop);
+
+       // integer
+       if ((val[0] >= '0') && (val[0] <= '9'))
+               return atoi(val.cstr()) != 0;   
+
+       // string
+       if (val[0]!=0)
+               return true;    
+
+       return false;
+}
+
+// --------------------------------------
+void   HTML::readIf(Stream &in,Stream *outp,int loop)
+{
+       String var;
+       bool varCond=true;
+
+       while (!in.eof())
+       {
+               char c = in.readChar();
+
+               if (c == '}')
+               {
+                       if (getBoolVariable(var,loop)==varCond)
+                       {
+                               if (readTemplate(in,outp,loop))
+                                       readTemplate(in,NULL,loop);
+                       }else{
+                               if (readTemplate(in,NULL,loop))
+                                       readTemplate(in,outp,loop);
+                       }
+                       return;
+               }else if (c == '!')
+               {
+                       varCond = !varCond;
+               }else
+               {
+                       var.append(c);
+               }
+       }
+
+}
+
+// --------------------------------------
+void   HTML::readLoop(Stream &in,Stream *outp,int loop)
+{
+       String var;
+       while (!in.eof())
+       {
+               char c = in.readChar();
+
+               if (c == '}')
+               {
+                       int cnt = getIntVariable(var,loop);
+
+                       if (cnt)
+                       {
+                               int spos = in.getPosition();
+                               for(int i=0; i<cnt; i++)
+                               {
+                                       in.seekTo(spos);
+                                       readTemplate(in,outp,i);
+                               }
+                       }else
+                       {
+                               readTemplate(in,NULL,0);
+                       }
+                       return;
+
+               }else
+               {
+                       var.append(c);
+               }
+       }
+
+}
+
+// --------------------------------------
+int HTML::readCmd(Stream &in,Stream *outp,int loop)
+{
+       String cmd;
+
+       int tmpl = TMPL_UNKNOWN;
+
+       while (!in.eof())
+       {
+               char c = in.readChar();
+
+               if (String::isWhitespace(c) || (c=='}'))
+               {
+                       if (cmd == "loop")
+                       {
+                               readLoop(in,outp,loop);
+                               tmpl = TMPL_LOOP;
+                       }else if (cmd == "if")
+                       {
+                               readIf(in,outp,loop);
+                               tmpl = TMPL_IF;
+                       }else if (cmd == "end")
+                       {
+                               tmpl = TMPL_END;
+                       }
+                       else if (cmd == "else")
+                       {
+                               tmpl = TMPL_ELSE;
+                       }
+                       break;
+               }else
+               {
+                       cmd.append(c);
+               }
+       }
+       return tmpl;
+}
+
+// --------------------------------------
+void   HTML::readVariable(Stream &in,Stream *outp,int loop)
+{
+       String var;
+       while (!in.eof())
+       {
+               char c = in.readChar();
+               if (c == '}')
+               {
+                       if (outp)
+                               writeVariable(*outp,var,loop);
+                       return;
+               }else
+               {
+                       var.append(c);
+               }
+       }
+
+}
+// --------------------------------------
+bool HTML::readTemplate(Stream &in,Stream *outp,int loop)
+{
+       while (!in.eof())
+       {
+               char c = in.readChar();
+
+               if (c == '{')
+               {
+                       c = in.readChar();
+                       if (c == '$')
+                       {
+                               readVariable(in,outp,loop);
+                       }
+                       else if (c == '@')
+                       {
+                               int t = readCmd(in,outp,loop);
+                               if (t == TMPL_END)
+                                       return false;
+                               else if (t == TMPL_ELSE)
+                                       return true;
+                       }
+                       else if (c == '{')
+                       {
+                               if (outp)
+                                       outp->writeChar(c);
+                       }
+                       else
+                               throw StreamException("Unknown template escape");
+               }else
+               {
+                       if (outp)
+                               outp->writeChar(c);
+               }
+       }
+       return false;
+}
+
+// --------------------------------------
+void HTML::writeTemplate(const char *fileName, const char *args)
+{
+       FileStream file;
+       MemoryStream mm;
+       try
+       {
+               file.openReadOnly(fileName);
+               mm.readFromFile(file);
+
+               tmplArgs = args;
+               readTemplate(mm,out,0);
+
+       }catch(StreamException &e)
+       {
+               out->writeString(e.msg);
+               out->writeString(" : ");
+               out->writeString(fileName);
+       }
+
+       mm.free2();
+       file.close();
+}
+// --------------------------------------
+void HTML::writeRawFile(const char *fileName)
+{
+       FileStream file;
+       try
+       {
+               file.openReadOnly(fileName);
+
+               file.writeTo(*out,file.length());
+
+       }catch(StreamException &)
+       {
+       }
+
+       file.close();
+}
+
+// --------------------------------------
+void HTML::locateTo(const char *url)
+{
+       out->writeLine(HTTP_SC_FOUND);
+       out->writeLineF("Location: %s",url);
+       out->writeLine("");
+}
+// --------------------------------------
+void HTML::startHTML()
+{
+       startNode("html");
+}
+// --------------------------------------
+void HTML::startBody()
+{
+       startNode("body");
+}
+// --------------------------------------
+void HTML::addHead()
+{
+       char buf[512];
+               startNode("head");
+                       startTagEnd("title",title.cstr());
+                       startTagEnd("meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\"");
+
+                       if (!refreshURL.isEmpty())
+                       {
+                               sprintf(buf,"meta http-equiv=\"refresh\" content=\"%d;URL=%s\"",refresh,refreshURL.cstr());
+                               startTagEnd(buf);
+                       }else if (refresh)
+                       {
+                               sprintf(buf,"meta http-equiv=\"refresh\" content=\"%d\"",refresh);
+                               startTagEnd(buf);
+                       }
+
+
+               end();
+}
+// --------------------------------------
+void HTML::addContent(const char *s)
+{
+       out->writeString(s);
+}
+// --------------------------------------
+void HTML::startNode(const char *tag, const char *data)
+{
+       const char *p = tag;
+       char *o = &currTag[tagLevel][0];
+
+       int i;
+       for(i=0; i<MAX_TAGLEN-1; i++)
+       {
+               char c = *p++;
+               if ((c==0) || (c==' '))
+                       break;
+               else
+                       *o++ = c;
+       }
+       *o = 0;
+
+       out->writeString("<");
+       out->writeString(tag);
+       out->writeString(">");
+       if (data)
+               out->writeString(data);
+
+       tagLevel++;
+       if (tagLevel >= MAX_TAGLEVEL)
+               throw StreamException("HTML too deep!");
+}
+// --------------------------------------
+void HTML::end()
+{
+       tagLevel--;
+       if (tagLevel < 0)
+               throw StreamException("HTML premature end!");
+
+       out->writeString("</");
+       out->writeString(&currTag[tagLevel][0]);
+       out->writeString(">");
+}
+// --------------------------------------
+void HTML::addLink(const char *url, const char *text, bool toblank)
+{
+       char buf[1024];
+
+       sprintf(buf,"a href=\"%s\" %s",url,toblank?"target=\"_blank\"":"");
+       startNode(buf,text);
+       end();
+}
+// --------------------------------------
+void HTML::startTag(const char *tag, const char *fmt,...)
+{
+       if (fmt)
+       {
+
+               va_list ap;
+               va_start(ap, fmt);
+
+               char tmp[512];
+               vsprintf(tmp,fmt,ap);
+               startNode(tag,tmp);
+
+               va_end(ap);     
+       }else{
+               startNode(tag,NULL);
+       }
+}
+// --------------------------------------
+void HTML::startTagEnd(const char *tag, const char *fmt,...)
+{
+       if (fmt)
+       {
+
+               va_list ap;
+               va_start(ap, fmt);
+
+               char tmp[512];
+               vsprintf(tmp,fmt,ap);
+               startNode(tag,tmp);
+
+               va_end(ap);     
+       }else{
+               startNode(tag,NULL);
+       }
+       end();
+}
+// --------------------------------------
+void HTML::startSingleTagEnd(const char *fmt,...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+
+       char tmp[512];
+       vsprintf(tmp,fmt,ap);
+       startNode(tmp);
+
+       va_end(ap);     
+       end();
+}
+
+// --------------------------------------
+void HTML::startTableRow(int i)
+{
+       if (i & 1)
+               startTag("tr bgcolor=\"#dddddd\" align=\"left\"");
+       else
+               startTag("tr bgcolor=\"#eeeeee\" align=\"left\"");
+}
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/html.h b/c:/Git/PeerCast.root/PeerCast/core/common/html.h
new file mode 100644 (file)
index 0000000..7f05c43
--- /dev/null
@@ -0,0 +1,91 @@
+// ------------------------------------------------
+// File : html.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _HTML_H
+#define _HTML_H
+
+// ---------------------------------------
+#include "xml.h"
+#include "sys.h"
+
+class FileStream;
+class WriteBufferStream;
+
+// ---------------------------------------
+class HTML 
+{
+public:
+       enum 
+       {
+               MAX_TAGLEVEL = 64,
+               MAX_TAGLEN = 64
+       };
+
+       enum
+       {
+               TMPL_UNKNOWN,
+               TMPL_LOOP,
+               TMPL_IF,
+               TMPL_ELSE,
+               TMPL_END
+       };
+
+       HTML(const char *,Stream &);
+       ~HTML();
+
+       void    startNode(const char *, const char * = NULL);
+       void    addLink(const char *, const char *, bool = false);
+       void    startTag(const char *, const char * = NULL,...);
+       void    startTagEnd(const char *, const char * = NULL,...);
+       void    startSingleTagEnd(const char *,...);
+       void    startTableRow(int);
+       void    end();
+       void    setRefresh(int sec) {refresh = sec;}
+       void    setRefreshURL(const char *u){refreshURL.set(u);}
+       void    addHead();
+       void    startHTML();
+       void    startBody();
+
+       void    locateTo(const char *);
+       void    addContent(const char *);
+
+       void    writeOK(const char *);
+       void    writeTemplate(const char *, const char *);
+       void    writeRawFile(const char *);
+       void    writeVariable(Stream &,const String &,int);
+       int             getIntVariable(const String &,int);
+       bool    getBoolVariable(const String &,int);
+
+
+       void    readIf(Stream &,Stream *,int);
+       void    readLoop(Stream &,Stream *,int);
+       void    readVariable(Stream &,Stream *,int);
+       bool    readTemplate(Stream &,Stream *,int);
+       int             readCmd(Stream &,Stream *,int);
+
+
+       const char *tmplArgs;
+       String  title,refreshURL;
+       char    currTag[MAX_TAGLEVEL][MAX_TAGLEN];
+       int             tagLevel;
+       int             refresh;
+       WriteBufferStream *out;
+};
+
+#endif
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/http.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/http.cpp
new file mode 100644 (file)
index 0000000..95f4df4
--- /dev/null
@@ -0,0 +1,192 @@
+// ------------------------------------------------
+// File : http.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             HTTP protocol handling
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+#include <stdlib.h>
+#include "http.h"
+#include "sys.h"
+#include "common.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+//-----------------------------------------
+bool HTTP::checkResponse(int r)
+{
+       if (readResponse()!=r)
+       {
+               LOG_ERROR("Unexpected HTTP: %s",cmdLine);
+               throw StreamException("Unexpected HTTP response");
+               return false;
+       }
+       
+       return true;
+}
+//-----------------------------------------
+void HTTP::readRequest()
+{
+       readLine(cmdLine,sizeof(cmdLine));
+}
+//-----------------------------------------
+int HTTP::readResponse()
+{
+       readLine(cmdLine,sizeof(cmdLine));
+
+       char *cp = cmdLine;
+
+       while (*cp)     if (*++cp == ' ') break;
+       while (*cp) if (*++cp != ' ') break;
+
+       char *scp = cp;
+
+       while (*cp)     if (*++cp == ' ') break;
+       *cp = 0;
+
+       return atoi(scp);
+}
+       
+//-----------------------------------------
+bool   HTTP::nextHeader()
+{
+       if (readLine(cmdLine,sizeof(cmdLine)))
+       {
+               char *ap = strstr(cmdLine,":");
+               if (ap)
+                       while (*++ap)
+                               if (*ap!=' ')
+                                       break;
+               arg = ap;
+               return true;
+       }else
+       {
+               arg = NULL;
+               return false;
+       }
+
+}
+//-----------------------------------------
+bool   HTTP::isHeader(const char *hs)
+{
+       return stristr(cmdLine,hs) != NULL;
+}
+//-----------------------------------------
+bool   HTTP::isRequest(const char *rq)
+{
+       return strncmp(cmdLine,rq,strlen(rq)) == 0;
+}
+//-----------------------------------------
+char *HTTP::getArgStr()
+{
+       return arg;
+}
+//-----------------------------------------
+int    HTTP::getArgInt()
+{
+       if (arg) 
+               return atoi(arg);
+       else 
+               return 0;
+}
+//-----------------------------------------
+void HTTP::getAuthUserPass(char *user, char *pass)
+{
+       if (arg)
+       {
+               char *s = stristr(arg,"Basic");
+               if (s)
+               {
+                       while (*s)
+                               if (*s++ == ' ')
+                                       break;
+                       String str;
+                       str.set(s,String::T_BASE64);
+                       str.convertTo(String::T_ASCII);
+                       s = strstr(str.cstr(),":");
+                       if (s)
+                       {
+                               *s = 0;
+                               if (user)
+                                       strcpy(user,str.cstr());
+                               if (pass)
+                                       strcpy(pass,s+1);
+                       }                       
+               }
+       }
+}
+// -----------------------------------
+void   CookieList::init()
+{
+       for(int i=0; i<MAX_COOKIES; i++)
+               list[i].clear();
+
+       neverExpire = false;
+}
+
+// -----------------------------------
+bool   CookieList::contains(Cookie &c)
+{
+       if ((c.id[0]) && (c.ip))
+               for(int i=0; i<MAX_COOKIES; i++)
+                       if (list[i].compare(c))
+                               return true;
+
+       return false;
+}
+// -----------------------------------
+void   Cookie::logDebug(const char *str, int ind)
+{
+       char ipstr[64];
+       Host h;
+       h.ip = ip;
+       h.IPtoStr(ipstr);
+
+       LOG_DEBUG("%s %d: %s - %s",str,ind,ipstr,id);
+}
+
+// -----------------------------------
+bool   CookieList::add(Cookie &c)
+{
+       if (contains(c))
+               return false;
+
+       unsigned int oldestTime=(unsigned int)-1; 
+       int oldestIndex=0;
+
+       for(int i=0; i<MAX_COOKIES; i++)
+               if (list[i].time <= oldestTime)
+               {
+                       oldestIndex = i;
+                       oldestTime = list[i].time;
+               }
+
+       c.logDebug("Added cookie",oldestIndex);
+       c.time = sys->getTime();
+       list[oldestIndex]=c;
+       return true;
+}
+// -----------------------------------
+void   CookieList::remove(Cookie &c)
+{
+       for(int i=0; i<MAX_COOKIES; i++)
+               if (list[i].compare(c))
+                       list[i].clear();
+}
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/http.h b/c:/Git/PeerCast.root/PeerCast/core/common/http.h
new file mode 100644 (file)
index 0000000..2627d3d
--- /dev/null
@@ -0,0 +1,185 @@
+// ------------------------------------------------
+// File : http.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _HTTP_H
+#define _HTTP_H
+
+#include "stream.h"
+
+// -------------------------------------
+class HTTPException : public StreamException
+{
+public:
+       HTTPException(const char *m, int c) : StreamException(m) {code=c;}
+       int code;
+};
+
+// --------------------------------------------
+static const char *HTTP_SC_OK                  = "HTTP/1.0 200 OK";
+static const char *HTTP_SC_NOTFOUND            = "HTTP/1.0 404 Not Found";
+static const char *HTTP_SC_UNAVAILABLE = "HTTP/1.0 503 Service Unavailable";
+static const char *HTTP_SC_UNAUTHORIZED        = "HTTP/1.0 401 Unauthorized";
+static const char *HTTP_SC_FOUND               = "HTTP/1.0 302 Found";
+static const char *HTTP_SC_BADREQUEST  = "HTTP/1.0 400 Bad Request";
+static const char *HTTP_SC_FORBIDDEN   = "HTTP/1.0 403 Forbidden";
+static const char *HTTP_SC_SWITCH              = "HTTP/1.0 101 Switch protocols";
+
+static const char *RTSP_SC_OK                  = "RTSP/1.0 200 OK";
+
+
+static const char *HTTP_PROTO1         = "HTTP/1.";
+static const char *RTSP_PROTO1         = "RTSP/1.";
+
+static const char *HTTP_HS_SERVER              = "Server:";
+static const char *HTTP_HS_AGENT               = "User-Agent:"; 
+static const char *HTTP_HS_CONTENT             = "Content-Type:"; 
+static const char *HTTP_HS_CACHE               = "Cache-Control:"; 
+static const char *HTTP_HS_CONNECTION  = "Connection:"; 
+static const char *HTTP_HS_SETCOOKIE   = "Set-Cookie:";
+static const char *HTTP_HS_COOKIE              = "Cookie:";
+static const char *HTTP_HS_HOST                        = "Host:";
+static const char *HTTP_HS_ACCEPT              = "Accept:";
+static const char *HTTP_HS_LENGTH              = "Content-Length:";
+
+static const char *MIME_MP3                    = "audio/mpeg";
+static const char *MIME_XMP3           = "audio/x-mpeg";
+static const char *MIME_OGG                    = "application/ogg";
+static const char *MIME_XOGG           = "application/x-ogg";
+static const char *MIME_MOV                    = "video/quicktime";
+static const char *MIME_MPG                    = "video/mpeg";
+static const char *MIME_NSV                    = "video/nsv";
+static const char *MIME_ASF                    = "video/x-ms-asf";
+static const char *MIME_ASX                    = "video/x-ms-asf";     // same as ASF
+static const char *MIME_MMS                    = "application/x-mms-framed";
+
+static const char *MIME_RAM                    = "audio/x-pn-realaudio";
+
+
+static const char *MIME_WMA                    = "audio/x-ms-wma";
+static const char *MIME_WMV                    = "video/x-ms-wmv";
+
+static const char *MIME_HTML           = "text/html";
+static const char *MIME_XML                    = "text/xml";
+static const char *MIME_CSS                    = "text/css";
+static const char *MIME_TEXT           = "text/plain";
+static const char *MIME_PLS                    = "audio/mpegurl";
+static const char *MIME_XPLS           = "audio/x-mpegurl";
+static const char *MIME_XSCPLS         = "audio/x-scpls";
+static const char *MIME_SDP                    = "application/sdp";
+static const char *MIME_M3U                    = "audio/m3u";
+static const char *MIME_MPEGURL                = "audio/mpegurl";
+static const char *MIME_XM3U           = "audio/x-mpegurl";
+static const char *MIME_XPEERCAST      = "application/x-peercast";
+static const char *MIME_XPCP           = "application/x-peercast-pcp";
+static const char *MIME_RAW                    = "application/binary";
+static const char *MIME_JPEG           = "image/jpeg";
+static const char *MIME_GIF                    = "image/gif";
+static const char *MIME_PNG                    = "image/png";
+
+
+// --------------------------------------------
+class Cookie
+{
+public:
+       Cookie()
+       {
+               clear();
+       }
+
+       void    clear()
+       {
+               time = 0;
+               ip = 0;
+               id[0]=0;
+       }
+
+       void    set(const char *i, unsigned int nip)
+       {
+               strncpy(id,i,sizeof(id)-1);
+               id[sizeof(id)-1]=0;
+               ip = nip;
+       }
+       bool    compare(Cookie &c)
+       {
+               if (c.ip == ip)
+                       if (strcmp(c.id,id)==0)
+                               return true;
+
+               return false;
+       }
+
+       void    logDebug(const char *,int);
+
+       unsigned int ip;
+       char    id[64];
+       unsigned int time;
+};
+
+// --------------------------------------------
+class CookieList
+{
+public:
+       enum {
+               MAX_COOKIES = 32
+       };
+
+
+
+       void    init();
+       bool    add(Cookie &);
+       void    remove(Cookie &);
+       bool    contains(Cookie &);
+
+
+       Cookie list[MAX_COOKIES];
+       bool    neverExpire;
+
+};
+
+// --------------------------------------------
+class HTTP : public IndirectStream
+{
+public:
+       HTTP(Stream &s)
+       {
+               init(&s);
+       }
+
+       void    initRequest(const char *r)
+       {
+               strcpy(cmdLine,r);
+       }
+       void    readRequest();
+       bool    isRequest(const char *);
+
+       int             readResponse();
+       bool    checkResponse(int);
+
+       bool    nextHeader();
+       bool    isHeader(const char *);
+       char    *getArgStr();
+       int             getArgInt();
+
+       void    getAuthUserPass(char *, char *);
+
+       char    cmdLine[8192],*arg;
+
+};
+
+#endif
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/icy.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/icy.cpp
new file mode 100644 (file)
index 0000000..954be02
--- /dev/null
@@ -0,0 +1,43 @@
+#include "icy.h"
+#include "socket.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ------------------------------------------------
+void ICYSource::stream(Channel *ch)
+{
+       ChannelStream *source=NULL;
+       try 
+       {
+
+               if (!ch->sock)
+                       throw StreamException("ICY channel has no socket");
+
+               ch->resetPlayTime();
+
+               ch->setStatus(Channel::S_BROADCASTING);
+               source = ch->createSource();
+               ch->readStream(*ch->sock,source);
+
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("Channel aborted: %s",e.msg);
+       }
+
+
+       ch->setStatus(Channel::S_CLOSING);
+
+       if (ch->sock)
+       {
+               ch->sock->close();
+               delete ch->sock;
+               ch->sock = NULL;
+       }
+
+       if (source)
+               delete source;
+
+}
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/icy.h b/c:/Git/PeerCast.root/PeerCast/core/common/icy.h
new file mode 100644 (file)
index 0000000..aec507d
--- /dev/null
@@ -0,0 +1,35 @@
+// ------------------------------------------------
+// File : icy.h
+// Date: 20-feb-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _ICY_H
+#define _ICY_H
+
+#include "channel.h"
+
+// ------------------------------------------------
+class ICYSource : public ChannelSource
+{
+public:
+       virtual void stream(Channel *);
+
+};
+
+
+
+
+#endif
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/id.h b/c:/Git/PeerCast.root/PeerCast/core/common/id.h
new file mode 100644 (file)
index 0000000..8052820
--- /dev/null
@@ -0,0 +1,101 @@
+#ifndef _ID_H
+#define _ID_H
+
+#include <string.h>
+
+// ---------------------------------------------------
+class IDString
+{
+private:
+       enum
+       {
+               LENGTH = 31
+       };
+
+       char data[LENGTH+1];
+public:
+       IDString(const char *id,int cnt)
+       {
+               if (cnt >= LENGTH)
+                       cnt=LENGTH;
+               int i;
+               for(i=0; i<cnt; i++)
+                       data[i]=id[i];
+               data[i]=0;
+       }
+
+       operator const char *()
+       {
+               return str();
+       }
+       
+       const char *str() {return data;}
+       
+};
+
+
+
+
+// ---------------------------------------------------
+class ID4
+{
+private:
+       union 
+       {
+               int     iv;
+               char cv[4];
+       };
+
+public:
+
+       ID4()
+       : iv( 0 )
+       {
+       }
+       
+       ID4(int i)
+       :iv(i)
+       {
+       }
+
+       ID4(const char *id)
+       :iv(0)
+       {
+               if (id)
+                       for(int i=0; i<4; i++)
+                               if ((cv[i]=id[i])==0)
+                                       break;
+       }
+
+       void clear()
+       {
+               iv = 0;
+       }
+
+       operator int() const
+       {
+               return iv;
+       }
+
+       int operator == (ID4 id) const
+       {
+               return iv==id.iv;
+       }
+       int operator != (ID4 id) const
+       {
+               return iv!=id.iv;
+       }
+       
+       bool    isSet() const {return iv!=0;}
+
+
+       int getValue() const {return iv;}
+       IDString getString() const {return IDString(cv,4);}
+       void *getData() {return cv;}
+
+};
+
+
+
+
+#endif
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/identify_encoding.c b/c:/Git/PeerCast.root/PeerCast/core/common/identify_encoding.c
new file mode 100644 (file)
index 0000000..fb9cfbb
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ *
+ * \8a¿\8e\9a\83R\81[\83h\82Ì\94»\95Ê\82µ\81Aiconv \97p\82Ì\95\8e\9a\83G\83\93\83R\81[\83f\83B\83\93\83O\95\8e\9a\97ñ\82ð\95Ô\82·
+ *
+ * 2001/10/24  Remove static variables
+ *             Kazuhiko Iwama <iwama@ymc.ne.jp>
+ * 2001/10/14  First version
+ *             Kazuhiko Iwama <iwama@ymc.ne.jp>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include "identify_encoding.h"
+
+enum encoding_id
+{
+       eid_KNOWN = 0,
+       eid_ASCII = 1,
+       eid_JIS   = 2,
+       eid_SJIS  = 3,
+       eid_EUCJP = 4,
+       eid_UTF8  = 5
+};
+
+const char *encoding_str[] =
+{
+       "KNOWN", "ASCII", "ISO-2022-JP", "SJIS", "EUC-JP", "UTF-8"
+};
+
+static int
+is_ascii(ie_state_t *st, const unsigned char *p)
+{
+       if (!(isprint(*p) || isspace(*p)) || *p >= 0x80)
+               st->flag = 0;
+       return st->flag;
+}
+
+static int
+is_jis(ie_state_t *st, const unsigned char *p)
+{
+       if (*p >= 0x80)
+               st->flag = 0;
+    return st->flag;
+}
+
+static int
+is_sjis(ie_state_t *st, const unsigned char *p)
+{
+       switch (st->state)
+       {
+               case 0:
+                       st->c_type = 0;
+                       if (*p >= 0x80)
+                       {
+                               st->state = 1;
+                               if              (*p >= 0x81 && *p <= 0x9f)      st->c_type = 1;
+                               else if (*p >= 0xe0 && *p <= 0xef)      st->c_type = 1;
+                               else if (*p >= 0xa1 && *p <= 0xdf)      st->state = 0;
+                               else                                                            st->flag = 1;
+                       }
+                       break;
+               case 1:
+                       if              (*p >= 0x40 && *p <= 0x7e)      st->state = 0;
+                       else if (*p >= 0x80 && *p <= 0xfc)      st->state = 0;
+                       else                                                            st->flag = 0;
+                       break;
+               default:
+                       st->flag = 0;
+                       break;
+       }
+
+       return st->flag;
+}
+
+static int
+is_eucjp(ie_state_t *st, const unsigned char *p)
+{
+       switch (st->state)
+       {
+               case 0:
+                       st->c_type = 0;
+                       if (*p >= 0x80)
+                       {
+                               st->state = 1;
+                               if              (*p >= 0xa1 && *p <= 0xfe)  st->c_type = 1;
+                               else if (*p == 0x8e              )  st->c_type = 2;
+                               else if (*p == 0x8f              )  st->c_type = 3;
+                           else                                                                st->flag = 0;
+                       }
+                       break;
+               case 1:
+                       switch (st->c_type)
+                       {
+                               case 1:
+                                       if (*p >= 0xa1 && *p <= 0xfe)  st->state = 0;
+                                       else                           st->flag = 0;
+                                       break;
+                               case 2:
+                                       if (*p >= 0x81 && *p <= 0xff)  st->state = 0;
+                                       else                           st->flag = 0;
+                                       break;
+                               case 3:
+                                       if (*p >= 0x81 && *p <= 0xff)  st->state = 2;
+                                       else                           st->flag = 0;
+                                       break;
+                               default:
+                                       st->flag = 0;
+                                       break;
+                       }
+                       break;
+               case 2:
+                       if (*p >= 0x81 && *p <= 0xff)  st->state = 0;
+                       else                           st->flag = 0;
+               default:
+                       st->flag = 0;
+                       break;
+       }
+
+       return st->flag;
+}
+
+static int
+is_utf8(ie_state_t *st, const unsigned char *p)
+{
+    switch (st->state)
+       {
+               case 0:
+                       st->c_type = 0;
+                       if (*p >= 0x80)
+                       {
+                               st->state = 1;
+                               if      (*p >= 0xc2 && *p <= 0xdf)  st->c_type = 1;
+                               else if (*p == 0xe0              )  st->c_type = 2;
+                               else if (*p >= 0xe1 && *p <= 0xef)  st->c_type = 3;
+                               else if (*p == 0xf0              )  st->c_type = 4;
+                               else if (*p >= 0xf1 && *p <= 0xf3)  st->c_type = 5;
+                               else if (*p == 0xf4              )  st->c_type = 6;
+                               else                                                            st->flag = 0;
+                       }
+                       break;
+               case 1:
+                       switch (st->c_type)
+                       {
+                               case 1:
+                                       if (*p >= 0x80 && *p <= 0xbf)  st->state = 0;
+                                       else                           st->flag = 0;
+                                       break;
+                               case 2:
+                                       if (*p >= 0xa0 && *p <= 0xbf)  st->state = 2;
+                                       else                           st->flag = 0;
+                                       break;
+                               case 3:
+                                       if (*p >= 0x80 && *p <= 0xbf)  st->state = 2;
+                                       else                           st->flag = 0;
+                                       break;
+                               case 4:
+                                       if (*p >= 0x90 && *p <= 0xbf)  st->state = 2;
+                                       else                           st->flag = 0;
+                                       break;
+                               case 5:
+                                       if (*p >= 0x80 && *p <= 0xbf)  st->state = 2;
+                                       else                           st->flag = 0;
+                                       break;
+                               case 6:
+                                       if (*p >= 0x80 && *p <= 0x8f)  st->state = 2;
+                                       else                           st->flag = 0;
+                                       break;
+                               default:
+                                       st->flag = 0;
+                                       break;
+                       }
+                       break;
+               case 2:
+                       if (st->c_type >= 2 && st->c_type <= 3)
+                       {
+                               if (*p >= 0x80 && *p <= 0xbf)  st->state = 0;
+                               else                           st->flag = 0;
+                       }else if (st->c_type >= 4 && st->c_type <= 6)
+                       {
+                               if (*p >= 0x80 && *p <= 0xbf)  st->state = 3;
+                               else                           st->flag = 0;
+                       }else{
+                               st->flag = 0;
+                       }
+                       break;
+               case 3:
+                       if (st->c_type >= 4 && st->c_type <= 6)
+                       {
+                               if (*p >= 0x80 && *p <= 0xbf)  st->state = 0;
+                               else                           st->flag = 0;
+                       }else{
+                               st->flag = 0;
+                       }
+                       break;
+               default:
+                       st->flag = 0;
+                       break;
+       }
+
+       return st->flag;
+}
+
+identify_encoding_t*
+identify_encoding_open(enum identify_encoding_order order)
+{
+       identify_encoding_t* cd;
+       cd = (identify_encoding_t*)malloc(sizeof(identify_encoding_t));
+
+       if (cd == NULL)
+       {
+               cd = (identify_encoding_t*)(-1);
+    }else{
+               cd->order = order;
+               identify_encoding_reset(cd);
+       }
+       return cd;
+}
+
+void
+identify_encoding_close(identify_encoding_t* cd)
+{
+       if (cd != (identify_encoding_t*)(-1) || cd != NULL)
+       {
+               free(cd);
+    }
+}
+
+static void
+identify_encoding_reset_state(ie_state_t* st)
+{
+       st->flag = 1;
+       st->state = 0;
+       st->c_type = 0;
+}
+
+void
+identify_encoding_reset(identify_encoding_t* cd)
+{
+       identify_encoding_reset_state(&(cd->st_ascii));
+       identify_encoding_reset_state(&(cd->st_jis));
+       identify_encoding_reset_state(&(cd->st_sjis));
+       identify_encoding_reset_state(&(cd->st_eucjp));
+       identify_encoding_reset_state(&(cd->st_utf8));
+}
+
+const char*
+identify_encoding(identify_encoding_t *cd, char* instr)
+{
+       int n;
+       unsigned char *p;
+       enum encoding_id eid = eid_KNOWN;
+
+       identify_encoding_reset(cd);
+
+       for (n = 0, p = (unsigned char *)instr; *p != '\0' && n < IDENTIFY_MAX_LENGTH; p++, n++)
+       {
+               if (cd->st_ascii.flag == 1)  is_ascii(&(cd->st_ascii), p);
+               if (cd->st_jis.flag   == 1)  is_jis(&(cd->st_jis), p);
+               if (cd->st_sjis.flag  == 1)  is_sjis(&(cd->st_sjis), p);
+               if (cd->st_eucjp.flag == 1)  is_eucjp(&(cd->st_eucjp), p);
+               if (cd->st_utf8.flag  == 1)  is_utf8(&(cd->st_utf8), p);
+    }
+
+       if      (cd->st_ascii.flag == 1)  eid = eid_ASCII;
+       else if (cd->st_jis.flag   == 1)  eid = eid_JIS;
+       else if (cd->st_utf8.flag  == 1)  eid = eid_UTF8;
+       else if (cd->order == ieo_EUCJP)
+       {
+               if      (cd->st_eucjp.flag == 1)  eid = eid_EUCJP;
+               else if (cd->st_sjis.flag  == 1)  eid = eid_SJIS;
+    }else{
+               if      (cd->st_sjis.flag  == 1)  eid = eid_SJIS;
+               else if (cd->st_eucjp.flag == 1)  eid = eid_EUCJP;
+       }
+
+       return encoding_str[ eid ];
+}
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/identify_encoding.h b/c:/Git/PeerCast.root/PeerCast/core/common/identify_encoding.h
new file mode 100644 (file)
index 0000000..5ccaf72
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ *
+ * \8a¿\8e\9a\83R\81[\83h\82Ì\94»\95Ê\82µ\81Aiconv \97p\82Ì\95\8e\9a\83G\83\93\83R\81[\83f\83B\83\93\83O\95\8e\9a\97ñ\82ð\95Ô\82·
+ *
+ * 2001/10/24  Remove static variables
+ *             Kazuhiko Iwama <iwama@ymc.ne.jp>
+ * 2001/10/14  First version
+ *             Kazuhiko Iwama <iwama@ymc.ne.jp>
+ *
+ */
+
+#ifndef IDENTIFY_ENCODING_H
+#define IDENTIFY_ENCODING_H
+
+#define IDENTIFY_MAX_LENGTH 256
+
+enum identify_encoding_order {
+       ieo_EUCJP = 0,
+       ieo_SJIS  = 1
+};
+
+typedef struct {
+       int flag;
+       int state;
+       int c_type;
+} ie_state_t;
+
+typedef struct {
+       enum identify_encoding_order order;
+       ie_state_t  st_ascii;
+       ie_state_t  st_jis;
+       ie_state_t  st_sjis;
+       ie_state_t  st_eucjp;
+       ie_state_t  st_utf8;
+} identify_encoding_t;
+
+identify_encoding_t* identify_encoding_open(enum identify_encoding_order order);
+void identify_encoding_close(identify_encoding_t* cd);
+void identify_encoding_reset(identify_encoding_t* cd);
+const char *identify_encoding(identify_encoding_t *cd, char* instr);
+
+#endif
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/inifile.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/inifile.cpp
new file mode 100644 (file)
index 0000000..965f2a9
--- /dev/null
@@ -0,0 +1,168 @@
+// ------------------------------------------------
+// File : inifile.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             .INI file reading/writing class
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include <stdlib.h>
+#include "inifile.h"
+#include "sys.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+       void    openReadOnly(const char *);
+       void    openWriteReplace(const char *);
+// -----------------------------------------
+bool IniFile::openReadOnly(const char *fn)
+{
+       try 
+       {
+               fStream.openReadOnly(fn);
+       }catch(StreamException &)
+       {
+               return false;
+       }
+       return true;
+}
+// -----------------------------------------
+bool IniFile::openWriteReplace(const char *fn)
+{
+       try 
+       {
+               fStream.openWriteReplace(fn);
+#if defined(_LINUX) || defined(__APPLE__)
+               fStream.writeCRLF = false;
+#endif
+
+       }catch(StreamException &)
+       {
+               return false;
+       }
+       return true;
+}
+// -----------------------------------------
+void IniFile::close()
+{
+       fStream.close();
+}
+
+
+// -----------------------------------------
+bool   IniFile::readNext()
+{
+       if (fStream.eof())
+               return false;
+
+       try
+       {
+               fStream.readLine(currLine,256);
+       }catch(StreamException &)
+       {
+               return false;
+       }
+
+
+       // find end of value name and null terminate
+       char *nend = strstr(currLine,"=");
+
+       if (nend)
+       {
+               *nend = 0;
+               valueStr = trimstr(nend+1);
+       }else
+               valueStr = NULL;
+
+       nameStr = trimstr(currLine);
+
+       return true;
+}
+// -----------------------------------------
+bool IniFile::isName(const char *str)
+{
+       return stricmp(getName(),str)==0;
+}
+
+// -----------------------------------------
+char * IniFile::getName()
+{
+       return nameStr;
+}
+// -----------------------------------------
+int            IniFile::getIntValue()
+{
+       if (valueStr)
+               return atoi(valueStr);
+       else
+               return 0;
+}
+// -----------------------------------------
+char * IniFile::getStrValue()
+{
+       if (valueStr)
+               return valueStr;
+       else
+               return "";
+}
+// -----------------------------------------
+bool   IniFile::getBoolValue()
+{
+       if (!valueStr)
+               return false;
+
+
+       if ( (stricmp(valueStr,"yes")==0) ||
+                (stricmp(valueStr,"y")==0) ||
+                (stricmp(valueStr,"1")==0) )
+               return true;
+
+       return false;
+}
+
+// -----------------------------------------
+void   IniFile::writeIntValue(const char *name, int iv)
+{
+       sprintf(currLine,"%s = %d",name,iv);
+       fStream.writeLine(currLine);
+}
+// -----------------------------------------
+void   IniFile::writeStrValue(const char *name, const char *sv)
+{
+       sprintf(currLine,"%s = %s",name,sv);
+       fStream.writeLine(currLine);
+}
+// -----------------------------------------
+void   IniFile::writeSection(const char *name)
+{
+       fStream.writeLine("");
+       sprintf(currLine,"[%s]",name);
+       fStream.writeLine(currLine);
+}
+// -----------------------------------------
+void   IniFile::writeBoolValue(const char *name, int v)
+{
+       sprintf(currLine,"%s = %s",name,(v!=0)?"Yes":"No");
+       fStream.writeLine(currLine);
+}
+// -----------------------------------------
+void   IniFile::writeLine(const char *str)
+{
+       fStream.writeLine(str);
+}
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/inifile.h b/c:/Git/PeerCast.root/PeerCast/core/common/inifile.h
new file mode 100644 (file)
index 0000000..2b75cca
--- /dev/null
@@ -0,0 +1,53 @@
+// ------------------------------------------------
+// File : inifile.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _INIFILE
+#define _INIFILE
+
+#include "stream.h"
+
+// -----------------------------------------
+class IniFile 
+{
+public:
+       bool    openReadOnly(const char *);
+       bool    openWriteReplace(const char *);
+       void    close();
+
+       bool    readNext();
+
+       bool    isName(const char *);
+       char *  getName();
+       int             getIntValue();
+       char *  getStrValue();
+       bool    getBoolValue();
+
+       void    writeSection(const char *);
+       void    writeIntValue(const char *, int);
+       void    writeStrValue(const char *, const char *);
+       void    writeBoolValue(const char *, int);
+       void    writeLine(const char *);
+
+
+       FileStream      fStream;
+       char    currLine[256];
+       char    *nameStr,*valueStr;
+};
+
+#endif
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/jis.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/jis.cpp
new file mode 100644 (file)
index 0000000..1ce75f2
--- /dev/null
@@ -0,0 +1,755 @@
+// ------------------------------------------------
+// File : jis.cpp
+// Date: 1-april-2004
+// Author: giles
+//
+//     ShiftJIS/EUC to Unicode conversions 
+//     (modified version of program by Y. Kuno, see below)
+//
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+
+/* J2Uc.c --- written by Y. Kuno, July 1996.                             */
+/* Compile with -DSJIS if you want to convert from SJIS; otherwise       */
+/* EUC-JP is assumed.                                                    */
+/* We are thankful to following people for permitting us free use        */
+/* of the following materials.                                           */
+/*   * Itaru Ichikawa (Fujitsu)  --- nkf 1.4 source code.                */
+/*   * Glenn Adams (Unicode Inc.) --- JISx0208 to Unicode mapping table. */
+/* This source code can freely be used, distributed, modified provided   */
+/* that this credit is also included in the source code.                 */
+
+// -----------------------------------
+
+#include "jis.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+// -----------------------------------
+
+#define                SJ0162  0x00e1          /* 01 - 62 ku offset */
+#define                SJ6394  0x0161          /* 63 - 94 ku offset */
+
+
+// -----------------------------------
+static unsigned short uniTable[94][94] = {
+{12288,12289,12290,65292,65294,12539,65306,65307,65311,65281,12443,12444,
+ 180,65344,168,65342,65507,65343,12541,12542,12445,12446,12291,20189,
+ 12293,12294,12295,12540,8213,8208,65295,92,12316,8214,65372,8230,
+ 8229,8216,8217,8220,8221,65288,65289,12308,12309,65339,65341,65371,
+ 65373,12296,12297,12298,12299,12300,12301,12302,12303,12304,12305,65291,
+ 8722,177,215,247,65309,8800,65308,65310,8806,8807,8734,8756,
+ 9794,9792,176,8242,8243,8451,65509,65284,162,163,65285,65283,
+ 65286,65290,65312,167,9734,9733,9675,9679,9678,9671,},
+{9670,9633,9632,9651,9650,9661,9660,8251,12306,8594,8592,8593,
+ 8595,12307,0,0,0,0,0,0,0,0,0,0,0,8712,8715,8838,8839,8834,8835,
+ 8746,8745,0,0,0,0,0,0,0,0,8743,8744,172,8658,8660,8704,8707,0,0,
+ 0,0,0,0,0,0,0,0,0,8736,8869,8978,8706,8711,8801,8786,8810,8811,
+ 8730,8765,8733,8757,8747,8748,0,0,0,0,0,0,0,8491,8240,9839,9837,
+ 9834,8224,8225,182,0,0,0,0,9711,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65296,65297,65298,65299,65300,65301,65302,
+ 65303,65304,65305,0,0,0,0,0,0,0,65313,65314,65315,65316,65317,65318,65319,
+ 65320,65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331,
+ 65332,65333,65334,65335,65336,65337,65338,0,0,0,0,0,0,65345,65346,65347,
+ 65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358,65359,
+ 65360,65361,65362,65363,65364,65365,65366,65367,65368,65369,65370,0,0,0,0,},
+{12353,12354,12355,12356,12357,12358,12359,12360,12361,12362,12363,12364,
+ 12365,12366,12367,12368,12369,12370,12371,12372,12373,12374,12375,12376,
+ 12377,12378,12379,12380,12381,12382,12383,12384,12385,12386,12387,12388,
+ 12389,12390,12391,12392,12393,12394,12395,12396,12397,12398,12399,12400,
+ 12401,12402,12403,12404,12405,12406,12407,12408,12409,12410,12411,12412,
+ 12413,12414,12415,12416,12417,12418,12419,12420,12421,12422,12423,12424,
+ 12425,12426,12427,12428,12429,12430,12431,12432,12433,12434,12435,0,0,0,0,
+ 0,0,0,0,0,0,0,},
+{12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460,
+ 12461,12462,12463,12464,12465,12466,12467,12468,12469,12470,12471,12472,
+ 12473,12474,12475,12476,12477,12478,12479,12480,12481,12482,12483,12484,
+ 12485,12486,12487,12488,12489,12490,12491,12492,12493,12494,12495,12496,
+ 12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507,12508,
+ 12509,12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520,
+ 12521,12522,12523,12524,12525,12526,12527,12528,12529,12530,12531,12532,
+ 12533,12534,0,0,0,0,0,0,0,0,},
+{913,914,915,916,917,918,919,920,921,922,923,924,
+ 925,926,927,928,929,931,932,933,934,935,936,937,0,
+ 0,0,0,0,0,0,0,945,946,947,948,949,950,951,952,953,954,
+ 955,956,957,958,959,960,961,963,964,965,966,967,
+ 968,969,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,},
+{1040,1041,1042,1043,1044,1045,1025,1046,1047,1048,1049,1050,
+ 1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,
+ 1063,1064,1065,1066,1067,1068,1069,1070,1071,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,1072,1073,1074,1075,1076,1077,1105,1078,1079,1080,
+ 1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,
+ 1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,},
+{9472,9474,9484,9488,9496,9492,9500,9516,9508,9524,9532,9473,
+ 9475,9487,9491,9499,9495,9507,9523,9515,9531,9547,9504,9519,
+ 9512,9527,9535,9501,9520,9509,9528,9538,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{20124,21782,23043,38463,21696,24859,25384,23030,36898,33909,33564,31312,
+ 24746,25569,28197,26093,33894,33446,39925,26771,22311,26017,25201,23451,
+ 22992,34427,39156,32098,32190,39822,25110,31903,34999,23433,24245,25353,
+ 26263,26696,38343,38797,26447,20197,20234,20301,20381,20553,22258,22839,
+ 22996,23041,23561,24799,24847,24944,26131,26885,28858,30031,30064,31227,
+ 32173,32239,32963,33806,34915,35586,36949,36986,21307,20117,20133,22495,
+ 32946,37057,30959,19968,22769,28322,36920,31282,33576,33419,39983,20801,
+ 21360,21693,21729,22240,23035,24341,39154,28139,32996,34093,},
+{38498,38512,38560,38907,21515,21491,23431,28879,32701,36802,38632,21359,
+ 40284,31418,19985,30867,33276,28198,22040,21764,27421,34074,39995,23013,
+ 21417,28006,29916,38287,22082,20113,36939,38642,33615,39180,21473,21942,
+ 23344,24433,26144,26355,26628,27704,27891,27945,29787,30408,31310,38964,
+ 33521,34907,35424,37613,28082,30123,30410,39365,24742,35585,36234,38322,
+ 27022,21421,20870,22290,22576,22852,23476,24310,24616,25513,25588,27839,
+ 28436,28814,28948,29017,29141,29503,32257,33398,33489,34199,36960,37467,
+ 40219,22633,26044,27738,29989,20985,22830,22885,24448,24540,},
+{25276,26106,27178,27431,27572,29579,32705,35158,40236,40206,40644,23713,
+ 27798,33659,20740,23627,25014,33222,26742,29281,20057,20474,21368,24681,
+ 28201,31311,38899,19979,21270,20206,20309,20285,20385,20339,21152,21487,
+ 22025,22799,23233,23478,23521,31185,26247,26524,26550,27468,27827,28779,
+ 29634,31117,31166,31292,31623,33457,33499,33540,33655,33775,33747,34662,
+ 35506,22057,36008,36838,36942,38686,34442,20420,23784,25105,29273,30011,
+ 33253,33469,34558,36032,38597,39187,39381,20171,20250,35299,22238,22602,
+ 22730,24315,24555,24618,24724,24674,25040,25106,25296,25913,},
+{39745,26214,26800,28023,28784,30028,30342,32117,33445,34809,38283,38542,
+ 35997,20977,21182,22806,21683,23475,23830,24936,27010,28079,30861,33995,
+ 34903,35442,37799,39608,28012,39336,34521,22435,26623,34510,37390,21123,
+ 22151,21508,24275,25313,25785,26684,26680,27579,29554,30906,31339,35226,
+ 35282,36203,36611,37101,38307,38548,38761,23398,23731,27005,38989,38990,
+ 25499,31520,27179,27263,26806,39949,28511,21106,21917,24688,25324,27963,
+ 28167,28369,33883,35088,36676,19988,39993,21494,26907,27194,38788,26666,
+ 20828,31427,33970,37340,37772,22107,40232,26658,33541,33841,},
+{31909,21000,33477,29926,20094,20355,20896,23506,21002,21208,21223,24059,
+ 21914,22570,23014,23436,23448,23515,24178,24185,24739,24863,24931,25022,
+ 25563,25954,26577,26707,26874,27454,27475,27735,28450,28567,28485,29872,
+ 29976,30435,30475,31487,31649,31777,32233,32566,32752,32925,33382,33694,
+ 35251,35532,36011,36996,37969,38291,38289,38306,38501,38867,39208,33304,
+ 20024,21547,23736,24012,29609,30284,30524,23721,32747,36107,38593,38929,
+ 38996,39000,20225,20238,21361,21916,22120,22522,22855,23305,23492,23696,
+ 24076,24190,24524,25582,26426,26071,26082,26399,26827,26820,},
+{27231,24112,27589,27671,27773,30079,31048,23395,31232,32000,24509,35215,
+ 35352,36020,36215,36556,36637,39138,39438,39740,20096,20605,20736,22931,
+ 23452,25135,25216,25836,27450,29344,30097,31047,32681,34811,35516,35696,
+ 25516,33738,38816,21513,21507,21931,26708,27224,35440,30759,26485,40653,
+ 21364,23458,33050,34384,36870,19992,20037,20167,20241,21450,21560,23470,
+ 24339,24613,25937,26429,27714,27762,27875,28792,29699,31350,31406,31496,
+ 32026,31998,32102,26087,29275,21435,23621,24040,25298,25312,25369,28192,
+ 34394,35377,36317,37624,28417,31142,39770,20136,20139,20140,},
+{20379,20384,20689,20807,31478,20849,20982,21332,21281,21375,21483,21932,
+ 22659,23777,24375,24394,24623,24656,24685,25375,25945,27211,27841,29378,
+ 29421,30703,33016,33029,33288,34126,37111,37857,38911,39255,39514,20208,
+ 20957,23597,26241,26989,23616,26354,26997,29577,26704,31873,20677,21220,
+ 22343,24062,37670,26020,27427,27453,29748,31105,31165,31563,32202,33465,
+ 33740,34943,35167,35641,36817,37329,21535,37504,20061,20534,21477,21306,
+ 29399,29590,30697,33510,36527,39366,39368,39378,20855,24858,34398,21936,
+ 31354,20598,23507,36935,38533,20018,27355,37351,23633,23624,},
+{25496,31391,27795,38772,36705,31402,29066,38536,31874,26647,32368,26705,
+ 37740,21234,21531,34219,35347,32676,36557,37089,21350,34952,31041,20418,
+ 20670,21009,20804,21843,22317,29674,22411,22865,24418,24452,24693,24950,
+ 24935,25001,25522,25658,25964,26223,26690,28179,30054,31293,31995,32076,
+ 32153,32331,32619,33550,33610,34509,35336,35427,35686,36605,38938,40335,
+ 33464,36814,39912,21127,25119,25731,28608,38553,26689,20625,27424,27770,
+ 28500,31348,32080,34880,35363,26376,20214,20537,20518,20581,20860,21048,
+ 21091,21927,22287,22533,23244,24314,25010,25080,25331,25458,},
+{26908,27177,29309,29356,29486,30740,30831,32121,30476,32937,35211,35609,
+ 36066,36562,36963,37749,38522,38997,39443,40568,20803,21407,21427,24187,
+ 24358,28187,28304,29572,29694,32067,33335,35328,35578,38480,20046,20491,
+ 21476,21628,22266,22993,23396,24049,24235,24359,25144,25925,26543,28246,
+ 29392,31946,34996,32929,32993,33776,34382,35463,36328,37431,38599,39015,
+ 40723,20116,20114,20237,21320,21577,21566,23087,24460,24481,24735,26791,
+ 27278,29786,30849,35486,35492,35703,37264,20062,39881,20132,20348,20399,
+ 20505,20502,20809,20844,21151,21177,21246,21402,21475,21521,},
+{21518,21897,22353,22434,22909,23380,23389,23439,24037,24039,24055,24184,
+ 24195,24218,24247,24344,24658,24908,25239,25304,25511,25915,26114,26179,
+ 26356,26477,26657,26775,27083,27743,27946,28009,28207,28317,30002,30343,
+ 30828,31295,31968,32005,32024,32094,32177,32789,32771,32943,32945,33108,
+ 33167,33322,33618,34892,34913,35611,36002,36092,37066,37237,37489,30783,
+ 37628,38308,38477,38917,39321,39640,40251,21083,21163,21495,21512,22741,
+ 25335,28640,35946,36703,40633,20811,21051,21578,22269,31296,37239,40288,
+ 40658,29508,28425,33136,29969,24573,24794,39592,29403,36796,},
+{27492,38915,20170,22256,22372,22718,23130,24680,25031,26127,26118,26681,
+ 26801,28151,30165,32058,33390,39746,20123,20304,21449,21766,23919,24038,
+ 24046,26619,27801,29811,30722,35408,37782,35039,22352,24231,25387,20661,
+ 20652,20877,26368,21705,22622,22971,23472,24425,25165,25505,26685,27507,
+ 28168,28797,37319,29312,30741,30758,31085,25998,32048,33756,35009,36617,
+ 38555,21092,22312,26448,32618,36001,20916,22338,38442,22586,27018,32948,
+ 21682,23822,22524,30869,40442,20316,21066,21643,25662,26152,26388,26613,
+ 31364,31574,32034,37679,26716,39853,31545,21273,20874,21047,},
+{23519,25334,25774,25830,26413,27578,34217,38609,30352,39894,25420,37638,
+ 39851,30399,26194,19977,20632,21442,23665,24808,25746,25955,26719,29158,
+ 29642,29987,31639,32386,34453,35715,36059,37240,39184,26028,26283,27531,
+ 20181,20180,20282,20351,21050,21496,21490,21987,22235,22763,22987,22985,
+ 23039,23376,23629,24066,24107,24535,24605,25351,25903,23388,26031,26045,
+ 26088,26525,27490,27515,27663,29509,31049,31169,31992,32025,32043,32930,
+ 33026,33267,35222,35422,35433,35430,35468,35566,36039,36060,38604,39164,
+ 27503,20107,20284,20365,20816,23383,23546,24904,25345,26178,},
+{27425,28363,27835,29246,29885,30164,30913,31034,32780,32819,33258,33940,
+ 36766,27728,40575,24335,35672,40235,31482,36600,23437,38635,19971,21489,
+ 22519,22833,23241,23460,24713,28287,28422,30142,36074,23455,34048,31712,
+ 20594,26612,33437,23649,34122,32286,33294,20889,23556,25448,36198,26012,
+ 29038,31038,32023,32773,35613,36554,36974,34503,37034,20511,21242,23610,
+ 26451,28796,29237,37196,37320,37675,33509,23490,24369,24825,20027,21462,
+ 23432,25163,26417,27530,29417,29664,31278,33131,36259,37202,39318,20754,
+ 21463,21610,23551,25480,27193,32172,38656,22234,21454,21608,},
+{23447,23601,24030,20462,24833,25342,27954,31168,31179,32066,32333,32722,
+ 33261,33311,33936,34886,35186,35728,36468,36655,36913,37195,37228,38598,
+ 37276,20160,20303,20805,21313,24467,25102,26580,27713,28171,29539,32294,
+ 37325,37507,21460,22809,23487,28113,31069,32302,31899,22654,29087,20986,
+ 34899,36848,20426,23803,26149,30636,31459,33308,39423,20934,24490,26092,
+ 26991,27529,28147,28310,28516,30462,32020,24033,36981,37255,38918,20966,
+ 21021,25152,26257,26329,28186,24246,32210,32626,26360,34223,34295,35576,
+ 21161,21465,22899,24207,24464,24661,37604,38500,20663,20767,},
+{21213,21280,21319,21484,21736,21830,21809,22039,22888,22974,23100,23477,
+ 23558,23567,23569,23578,24196,24202,24288,24432,25215,25220,25307,25484,
+ 25463,26119,26124,26157,26230,26494,26786,27167,27189,27836,28040,28169,
+ 28248,28988,28966,29031,30151,30465,30813,30977,31077,31216,31456,31505,
+ 31911,32057,32918,33750,33931,34121,34909,35059,35359,35388,35412,35443,
+ 35937,36062,37284,37478,37758,37912,38556,38808,19978,19976,19998,20055,
+ 20887,21104,22478,22580,22732,23330,24120,24773,25854,26465,26454,27972,
+ 29366,30067,31331,33976,35698,37304,37664,22065,22516,39166,},
+{25325,26893,27542,29165,32340,32887,33394,35302,39135,34645,36785,23611,
+ 20280,20449,20405,21767,23072,23517,23529,24515,24910,25391,26032,26187,
+ 26862,27035,28024,28145,30003,30137,30495,31070,31206,32051,33251,33455,
+ 34218,35242,35386,36523,36763,36914,37341,38663,20154,20161,20995,22645,
+ 22764,23563,29978,23613,33102,35338,36805,38499,38765,31525,35535,38920,
+ 37218,22259,21416,36887,21561,22402,24101,25512,27700,28810,30561,31883,
+ 32736,34928,36930,37204,37648,37656,38543,29790,39620,23815,23913,25968,
+ 26530,36264,38619,25454,26441,26905,33733,38935,38592,35070,},
+{28548,25722,23544,19990,28716,30045,26159,20932,21046,21218,22995,24449,
+ 24615,25104,25919,25972,26143,26228,26866,26646,27491,28165,29298,29983,
+ 30427,31934,32854,22768,35069,35199,35488,35475,35531,36893,37266,38738,
+ 38745,25993,31246,33030,38587,24109,24796,25114,26021,26132,26512,30707,
+ 31309,31821,32318,33034,36012,36196,36321,36447,30889,20999,25305,25509,
+ 25666,25240,35373,31363,31680,35500,38634,32118,33292,34633,20185,20808,
+ 21315,21344,23459,23554,23574,24029,25126,25159,25776,26643,26676,27849,
+ 27973,27927,26579,28508,29006,29053,26059,31359,31661,32218,},
+{32330,32680,33146,33307,33337,34214,35438,36046,36341,36984,36983,37549,
+ 37521,38275,39854,21069,21892,28472,28982,20840,31109,32341,33203,31950,
+ 22092,22609,23720,25514,26366,26365,26970,29401,30095,30094,30990,31062,
+ 31199,31895,32032,32068,34311,35380,38459,36961,40736,20711,21109,21452,
+ 21474,20489,21930,22766,22863,29245,23435,23652,21277,24803,24819,25436,
+ 25475,25407,25531,25805,26089,26361,24035,27085,27133,28437,29157,20105,
+ 30185,30456,31379,31967,32207,32156,32865,33609,33624,33900,33980,34299,
+ 35013,36208,36865,36973,37783,38684,39442,20687,22679,24974,},
+{33235,34101,36104,36896,20419,20596,21063,21363,24687,25417,26463,28204,
+ 36275,36895,20439,23646,36042,26063,32154,21330,34966,20854,25539,23384,
+ 23403,23562,25613,26449,36956,20182,22810,22826,27760,35409,21822,22549,
+ 22949,24816,25171,26561,33333,26965,38464,39364,39464,20307,22534,23550,
+ 32784,23729,24111,24453,24608,24907,25140,26367,27888,28382,32974,33151,
+ 33492,34955,36024,36864,36910,38538,40667,39899,20195,21488,22823,31532,
+ 37261,38988,40441,28381,28711,21331,21828,23429,25176,25246,25299,27810,
+ 28655,29730,35351,37944,28609,35582,33592,20967,34552,21482,},
+{21481,20294,36948,36784,22890,33073,24061,31466,36799,26842,35895,29432,
+ 40008,27197,35504,20025,21336,22022,22374,25285,25506,26086,27470,28129,
+ 28251,28845,30701,31471,31658,32187,32829,32966,34507,35477,37723,22243,
+ 22727,24382,26029,26262,27264,27573,30007,35527,20516,30693,22320,24347,
+ 24677,26234,27744,30196,31258,32622,33268,34584,36933,39347,31689,30044,
+ 31481,31569,33988,36880,31209,31378,33590,23265,30528,20013,20210,23449,
+ 24544,25277,26172,26609,27880,34411,34935,35387,37198,37619,39376,27159,
+ 28710,29482,33511,33879,36015,19969,20806,20939,21899,23541,},
+{24086,24115,24193,24340,24373,24427,24500,25074,25361,26274,26397,28526,
+ 29266,30010,30522,32884,33081,33144,34678,35519,35548,36229,36339,37530,
+ 38263,38914,40165,21189,25431,30452,26389,27784,29645,36035,37806,38515,
+ 27941,22684,26894,27084,36861,37786,30171,36890,22618,26626,25524,27131,
+ 20291,28460,26584,36795,34086,32180,37716,26943,28528,22378,22775,23340,
+ 32044,29226,21514,37347,40372,20141,20302,20572,20597,21059,35998,21576,
+ 22564,23450,24093,24213,24237,24311,24351,24716,25269,25402,25552,26799,
+ 27712,30855,31118,31243,32224,33351,35330,35558,36420,36883,},
+{37048,37165,37336,40718,27877,25688,25826,25973,28404,30340,31515,36969,
+ 37841,28346,21746,24505,25764,36685,36845,37444,20856,22635,22825,23637,
+ 24215,28155,32399,29980,36028,36578,39003,28857,20253,27583,28593,30000,
+ 38651,20814,21520,22581,22615,22956,23648,24466,26007,26460,28193,30331,
+ 33759,36077,36884,37117,37709,30757,30778,21162,24230,22303,22900,24594,
+ 20498,20826,20908,20941,20992,21776,22612,22616,22871,23445,23798,23947,
+ 24764,25237,25645,26481,26691,26812,26847,30423,28120,28271,28059,28783,
+ 29128,24403,30168,31095,31561,31572,31570,31958,32113,21040,},
+{33891,34153,34276,35342,35588,35910,36367,36867,36879,37913,38518,38957,
+ 39472,38360,20685,21205,21516,22530,23566,24999,25758,27934,30643,31461,
+ 33012,33796,36947,37509,23776,40199,21311,24471,24499,28060,29305,30563,
+ 31167,31716,27602,29420,35501,26627,27233,20984,31361,26932,23626,40182,
+ 33515,23493,37193,28702,22136,23663,24775,25958,27788,35930,36929,38931,
+ 21585,26311,37389,22856,37027,20869,20045,20970,34201,35598,28760,25466,
+ 37707,26978,39348,32260,30071,21335,26976,36575,38627,27741,20108,23612,
+ 24336,36841,21250,36049,32905,34425,24319,26085,20083,20837,},
+{22914,23615,38894,20219,22922,24525,35469,28641,31152,31074,23527,33905,
+ 29483,29105,24180,24565,25467,25754,29123,31896,20035,24316,20043,22492,
+ 22178,24745,28611,32013,33021,33075,33215,36786,35223,34468,24052,25226,
+ 25773,35207,26487,27874,27966,29750,30772,23110,32629,33453,39340,20467,
+ 24259,25309,25490,25943,26479,30403,29260,32972,32954,36649,37197,20493,
+ 22521,23186,26757,26995,29028,29437,36023,22770,36064,38506,36889,34687,
+ 31204,30695,33833,20271,21093,21338,25293,26575,27850,30333,31636,31893,
+ 33334,34180,36843,26333,28448,29190,32283,33707,39361,40614,},
+{20989,31665,30834,31672,32903,31560,27368,24161,32908,30033,30048,20843,
+ 37474,28300,30330,37271,39658,20240,32624,25244,31567,38309,40169,22138,
+ 22617,34532,38588,20276,21028,21322,21453,21467,24070,25644,26001,26495,
+ 27710,27726,29256,29359,29677,30036,32321,33324,34281,36009,31684,37318,
+ 29033,38930,39151,25405,26217,30058,30436,30928,34115,34542,21290,21329,
+ 21542,22915,24199,24444,24754,25161,25209,25259,26000,27604,27852,30130,
+ 30382,30865,31192,32203,32631,32933,34987,35513,36027,36991,38750,39131,
+ 27147,31800,20633,23614,24494,26503,27608,29749,30473,32654,},
+{40763,26570,31255,21305,30091,39661,24422,33181,33777,32920,24380,24517,
+ 30050,31558,36924,26727,23019,23195,32016,30334,35628,20469,24426,27161,
+ 27703,28418,29922,31080,34920,35413,35961,24287,25551,30149,31186,33495,
+ 37672,37618,33948,34541,39981,21697,24428,25996,27996,28693,36007,36051,
+ 38971,25935,29942,19981,20184,22496,22827,23142,23500,20904,24067,24220,
+ 24598,25206,25975,26023,26222,28014,29238,31526,33104,33178,33433,35676,
+ 36000,36070,36212,38428,38468,20398,25771,27494,33310,33889,34154,37096,
+ 23553,26963,39080,33914,34135,20239,21103,24489,24133,26381,},
+{31119,33145,35079,35206,28149,24343,25173,27832,20175,29289,39826,20998,
+ 21563,22132,22707,24996,25198,28954,22894,31881,31966,32027,38640,25991,
+ 32862,19993,20341,20853,22592,24163,24179,24330,26564,20006,34109,38281,
+ 38491,31859,38913,20731,22721,30294,30887,21029,30629,34065,31622,20559,
+ 22793,29255,31687,32232,36794,36820,36941,20415,21193,23081,24321,38829,
+ 20445,33303,37610,22275,25429,27497,29995,35036,36628,31298,21215,22675,
+ 24917,25098,26286,27597,31807,33769,20515,20472,21253,21574,22577,22857,
+ 23453,23792,23791,23849,24214,25265,25447,25918,26041,26379,},
+{27861,27873,28921,30770,32299,32990,33459,33804,34028,34562,35090,35370,
+ 35914,37030,37586,39165,40179,40300,20047,20129,20621,21078,22346,22952,
+ 24125,24536,24537,25151,26292,26395,26576,26834,20882,32033,32938,33192,
+ 35584,35980,36031,37502,38450,21536,38956,21271,20693,21340,22696,25778,
+ 26420,29287,30566,31302,37350,21187,27809,27526,22528,24140,22868,26412,
+ 32763,20961,30406,25705,30952,39764,40635,22475,22969,26151,26522,27598,
+ 21737,27097,24149,33180,26517,39850,26622,40018,26717,20134,20451,21448,
+ 25273,26411,27819,36804,20397,32365,40639,19975,24930,28288,},
+{28459,34067,21619,26410,39749,24051,31637,23724,23494,34588,28234,34001,
+ 31252,33032,22937,31885,27665,30496,21209,22818,28961,29279,30683,38695,
+ 40289,26891,23167,23064,20901,21517,21629,26126,30431,36855,37528,40180,
+ 23018,29277,28357,20813,26825,32191,32236,38754,40634,25720,27169,33538,
+ 22916,23391,27611,29467,30450,32178,32791,33945,20786,26408,40665,30446,
+ 26466,21247,39173,23588,25147,31870,36016,21839,24758,32011,38272,21249,
+ 20063,20918,22812,29242,32822,37326,24357,30690,21380,24441,32004,34220,
+ 35379,36493,38742,26611,34222,37971,24841,24840,27833,30290,},
+{35565,36664,21807,20305,20778,21191,21451,23461,24189,24736,24962,25558,
+ 26377,26586,28263,28044,29494,29495,30001,31056,35029,35480,36938,37009,
+ 37109,38596,34701,22805,20104,20313,19982,35465,36671,38928,20653,24188,
+ 22934,23481,24248,25562,25594,25793,26332,26954,27096,27915,28342,29076,
+ 29992,31407,32650,32768,33865,33993,35201,35617,36362,36965,38525,39178,
+ 24958,25233,27442,27779,28020,32716,32764,28096,32645,34746,35064,26469,
+ 33713,38972,38647,27931,32097,33853,37226,20081,21365,23888,27396,28651,
+ 34253,34349,35239,21033,21519,23653,26446,26792,29702,29827,},
+{30178,35023,35041,37324,38626,38520,24459,29575,31435,33870,25504,30053,
+ 21129,27969,28316,29705,30041,30827,31890,38534,31452,40845,20406,24942,
+ 26053,34396,20102,20142,20698,20001,20940,23534,26009,26753,28092,29471,
+ 30274,30637,31260,31975,33391,35538,36988,37327,38517,38936,21147,32209,
+ 20523,21400,26519,28107,29136,29747,33256,36650,38563,40023,40607,29792,
+ 22593,28057,32047,39006,20196,20278,20363,20919,21169,23994,24604,29618,
+ 31036,33491,37428,38583,38646,38666,40599,40802,26278,27508,21015,21155,
+ 28872,35010,24265,24651,24976,28451,29001,31806,32244,32879,},
+{34030,36899,37676,21570,39791,27347,28809,36034,36335,38706,21172,23105,
+ 24266,24324,26391,27004,27028,28010,28431,29282,29436,31725,32769,32894,
+ 34635,37070,20845,40595,31108,32907,37682,35542,20525,21644,35441,27498,
+ 36036,33031,24785,26528,40434,20121,20120,39952,35435,34241,34152,26880,
+ 28286,30871,33109,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{24332,19984,19989,20010,20017,20022,20028,20031,20034,20054,20056,20098,
+ 20101,35947,20106,33298,24333,20110,20126,20127,20128,20130,20144,20147,
+ 20150,20174,20173,20164,20166,20162,20183,20190,20205,20191,20215,20233,
+ 20314,20272,20315,20317,20311,20295,20342,20360,20367,20376,20347,20329,
+ 20336,20369,20335,20358,20374,20760,20436,20447,20430,20440,20443,20433,
+ 20442,20432,20452,20453,20506,20520,20500,20522,20517,20485,20252,20470,
+ 20513,20521,20524,20478,20463,20497,20486,20547,20551,26371,20565,20560,
+ 20552,20570,20566,20588,20600,20608,20634,20613,20660,20658,},
+{20681,20682,20659,20674,20694,20702,20709,20717,20707,20718,20729,20725,
+ 20745,20737,20738,20758,20757,20756,20762,20769,20794,20791,20796,20795,
+ 20799,20800,20818,20812,20820,20834,31480,20841,20842,20846,20864,20866,
+ 22232,20876,20873,20879,20881,20883,20885,20886,20900,20902,20898,20905,
+ 20906,20907,20915,20913,20914,20912,20917,20925,20933,20937,20955,20960,
+ 34389,20969,20973,20976,20981,20990,20996,21003,21012,21006,21031,21034,
+ 21038,21043,21049,21071,21060,21067,21068,21086,21076,21098,21108,21097,
+ 21107,21119,21117,21133,21140,21138,21105,21128,21137,36776,},
+{36775,21164,21165,21180,21173,21185,21197,21207,21214,21219,21222,39149,
+ 21216,21235,21237,21240,21241,21254,21256,30008,21261,21264,21263,21269,
+ 21274,21283,21295,21297,21299,21304,21312,21318,21317,19991,21321,21325,
+ 20950,21342,21353,21358,22808,21371,21367,21378,21398,21408,21414,21413,
+ 21422,21424,21430,21443,31762,38617,21471,26364,29166,21486,21480,21485,
+ 21498,21505,21565,21568,21548,21549,21564,21550,21558,21545,21533,21582,
+ 21647,21621,21646,21599,21617,21623,21616,21650,21627,21632,21622,21636,
+ 21648,21638,21703,21666,21688,21669,21676,21700,21704,21672,},
+{21675,21698,21668,21694,21692,21720,21733,21734,21775,21780,21757,21742,
+ 21741,21754,21730,21817,21824,21859,21836,21806,21852,21829,21846,21847,
+ 21816,21811,21853,21913,21888,21679,21898,21919,21883,21886,21912,21918,
+ 21934,21884,21891,21929,21895,21928,21978,21957,21983,21956,21980,21988,
+ 21972,22036,22007,22038,22014,22013,22043,22009,22094,22096,29151,22068,
+ 22070,22066,22072,22123,22116,22063,22124,22122,22150,22144,22154,22176,
+ 22164,22159,22181,22190,22198,22196,22210,22204,22209,22211,22208,22216,
+ 22222,22225,22227,22231,22254,22265,22272,22271,22276,22281,},
+{22280,22283,22285,22291,22296,22294,21959,22300,22310,22327,22328,22350,
+ 22331,22336,22351,22377,22464,22408,22369,22399,22409,22419,22432,22451,
+ 22436,22442,22448,22467,22470,22484,22482,22483,22538,22486,22499,22539,
+ 22553,22557,22642,22561,22626,22603,22640,27584,22610,22589,22649,22661,
+ 22713,22687,22699,22714,22750,22715,22712,22702,22725,22739,22737,22743,
+ 22745,22744,22757,22748,22756,22751,22767,22778,22777,22779,22780,22781,
+ 22786,22794,22800,22811,26790,22821,22828,22829,22834,22840,22846,31442,
+ 22869,22864,22862,22874,22872,22882,22880,22887,22892,22889,},
+{22904,22913,22941,20318,20395,22947,22962,22982,23016,23004,22925,23001,
+ 23002,23077,23071,23057,23068,23049,23066,23104,23148,23113,23093,23094,
+ 23138,23146,23194,23228,23230,23243,23234,23229,23267,23255,23270,23273,
+ 23254,23290,23291,23308,23307,23318,23346,23248,23338,23350,23358,23363,
+ 23365,23360,23377,23381,23386,23387,23397,23401,23408,23411,23413,23416,
+ 25992,23418,23424,23427,23462,23480,23491,23495,23497,23508,23504,23524,
+ 23526,23522,23518,23525,23531,23536,23542,23539,23557,23559,23560,23565,
+ 23571,23584,23586,23592,23608,23609,23617,23622,23630,23635,},
+{23632,23631,23409,23660,23662,20066,23670,23673,23692,23697,23700,22939,
+ 23723,23739,23734,23740,23735,23749,23742,23751,23769,23785,23805,23802,
+ 23789,23948,23786,23819,23829,23831,23900,23839,23835,23825,23828,23842,
+ 23834,23833,23832,23884,23890,23886,23883,23916,23923,23926,23943,23940,
+ 23938,23970,23965,23980,23982,23997,23952,23991,23996,24009,24013,24019,
+ 24018,24022,24027,24043,24050,24053,24075,24090,24089,24081,24091,24118,
+ 24119,24132,24131,24128,24142,24151,24148,24159,24162,24164,24135,24181,
+ 24182,24186,40636,24191,24224,24257,24258,24264,24272,24271,},
+{24278,24291,24285,24282,24283,24290,24289,24296,24297,24300,24305,24307,
+ 24304,24308,24312,24318,24323,24329,24413,24412,24331,24337,24342,24361,
+ 24365,24376,24385,24392,24396,24398,24367,24401,24406,24407,24409,24417,
+ 24429,24435,24439,24451,24450,24447,24458,24456,24465,24455,24478,24473,
+ 24472,24480,24488,24493,24508,24534,24571,24548,24568,24561,24541,24755,
+ 24575,24609,24672,24601,24592,24617,24590,24625,24603,24597,24619,24614,
+ 24591,24634,24666,24641,24682,24695,24671,24650,24646,24653,24675,24643,
+ 24676,24642,24684,24683,24665,24705,24717,24807,24707,24730,},
+{24708,24731,24726,24727,24722,24743,24715,24801,24760,24800,24787,24756,
+ 24560,24765,24774,24757,24792,24909,24853,24838,24822,24823,24832,24820,
+ 24826,24835,24865,24827,24817,24845,24846,24903,24894,24872,24871,24906,
+ 24895,24892,24876,24884,24893,24898,24900,24947,24951,24920,24921,24922,
+ 24939,24948,24943,24933,24945,24927,24925,24915,24949,24985,24982,24967,
+ 25004,24980,24986,24970,24977,25003,25006,25036,25034,25033,25079,25032,
+ 25027,25030,25018,25035,32633,25037,25062,25059,25078,25082,25076,25087,
+ 25085,25084,25086,25088,25096,25097,25101,25100,25108,25115,},
+{25118,25121,25130,25134,25136,25138,25139,25153,25166,25182,25187,25179,
+ 25184,25192,25212,25218,25225,25214,25234,25235,25238,25300,25219,25236,
+ 25303,25297,25275,25295,25343,25286,25812,25288,25308,25292,25290,25282,
+ 25287,25243,25289,25356,25326,25329,25383,25346,25352,25327,25333,25424,
+ 25406,25421,25628,25423,25494,25486,25472,25515,25462,25507,25487,25481,
+ 25503,25525,25451,25449,25534,25577,25536,25542,25571,25545,25554,25590,
+ 25540,25622,25652,25606,25619,25638,25654,25885,25623,25640,25615,25703,
+ 25711,25718,25678,25898,25749,25747,25765,25769,25736,25788,},
+{25818,25810,25797,25799,25787,25816,25794,25841,25831,33289,25824,25825,
+ 25260,25827,25839,25900,25846,25844,25842,25850,25856,25853,25880,25884,
+ 25861,25892,25891,25899,25908,25909,25911,25910,25912,30027,25928,25942,
+ 25941,25933,25944,25950,25949,25970,25976,25986,25987,35722,26011,26015,
+ 26027,26039,26051,26054,26049,26052,26060,26066,26075,26073,26080,26081,
+ 26097,26482,26122,26115,26107,26483,26165,26166,26164,26140,26191,26180,
+ 26185,26177,26206,26205,26212,26215,26216,26207,26210,26224,26243,26248,
+ 26254,26249,26244,26264,26269,26305,26297,26313,26302,26300,},
+{26308,26296,26326,26330,26336,26175,26342,26345,26352,26357,26359,26383,
+ 26390,26398,26406,26407,38712,26414,26431,26422,26433,26424,26423,26438,
+ 26462,26464,26457,26467,26468,26505,26480,26537,26492,26474,26508,26507,
+ 26534,26529,26501,26551,26607,26548,26604,26547,26601,26552,26596,26590,
+ 26589,26594,26606,26553,26574,26566,26599,27292,26654,26694,26665,26688,
+ 26701,26674,26702,26803,26667,26713,26723,26743,26751,26783,26767,26797,
+ 26772,26781,26779,26755,27310,26809,26740,26805,26784,26810,26895,26765,
+ 26750,26881,26826,26888,26840,26914,26918,26849,26892,26829,},
+{26836,26855,26837,26934,26898,26884,26839,26851,26917,26873,26848,26863,
+ 26920,26922,26906,26915,26913,26822,27001,26999,26972,27000,26987,26964,
+ 27006,26990,26937,26996,26941,26969,26928,26977,26974,26973,27009,26986,
+ 27058,27054,27088,27071,27073,27091,27070,27086,23528,27082,27101,27067,
+ 27075,27047,27182,27025,27040,27036,27029,27060,27102,27112,27138,27163,
+ 27135,27402,27129,27122,27111,27141,27057,27166,27117,27156,27115,27146,
+ 27154,27329,27171,27155,27204,27148,27250,27190,27256,27207,27234,27225,
+ 27238,27208,27192,27170,27280,27277,27296,27268,27298,27299,},
+{27287,34327,27323,27331,27330,27320,27315,27308,27358,27345,27359,27306,
+ 27354,27370,27387,27397,34326,27386,27410,27414,39729,27423,27448,27447,
+ 30428,27449,39150,27463,27459,27465,27472,27481,27476,27483,27487,27489,
+ 27512,27513,27519,27520,27524,27523,27533,27544,27541,27550,27556,27562,
+ 27563,27567,27570,27569,27571,27575,27580,27590,27595,27603,27615,27628,
+ 27627,27635,27631,40638,27656,27667,27668,27675,27684,27683,27742,27733,
+ 27746,27754,27778,27789,27802,27777,27803,27774,27752,27763,27794,27792,
+ 27844,27889,27859,27837,27863,27845,27869,27822,27825,27838,},
+{27834,27867,27887,27865,27882,27935,34893,27958,27947,27965,27960,27929,
+ 27957,27955,27922,27916,28003,28051,28004,27994,28025,27993,28046,28053,
+ 28644,28037,28153,28181,28170,28085,28103,28134,28088,28102,28140,28126,
+ 28108,28136,28114,28101,28154,28121,28132,28117,28138,28142,28205,28270,
+ 28206,28185,28274,28255,28222,28195,28267,28203,28278,28237,28191,28227,
+ 28218,28238,28196,28415,28189,28216,28290,28330,28312,28361,28343,28371,
+ 28349,28335,28356,28338,28372,28373,28303,28325,28354,28319,28481,28433,
+ 28748,28396,28408,28414,28479,28402,28465,28399,28466,28364,},
+{28478,28435,28407,28550,28538,28536,28545,28544,28527,28507,28659,28525,
+ 28546,28540,28504,28558,28561,28610,28518,28595,28579,28577,28580,28601,
+ 28614,28586,28639,28629,28652,28628,28632,28657,28654,28635,28681,28683,
+ 28666,28689,28673,28687,28670,28699,28698,28532,28701,28696,28703,28720,
+ 28734,28722,28753,28771,28825,28818,28847,28913,28844,28856,28851,28846,
+ 28895,28875,28893,28889,28937,28925,28956,28953,29029,29013,29064,29030,
+ 29026,29004,29014,29036,29071,29179,29060,29077,29096,29100,29143,29113,
+ 29118,29138,29129,29140,29134,29152,29164,29159,29173,29180,},
+{29177,29183,29197,29200,29211,29224,29229,29228,29232,29234,29243,29244,
+ 29247,29248,29254,29259,29272,29300,29310,29314,29313,29319,29330,29334,
+ 29346,29351,29369,29362,29379,29382,29380,29390,29394,29410,29408,29409,
+ 29433,29431,20495,29463,29450,29468,29462,29469,29492,29487,29481,29477,
+ 29502,29518,29519,40664,29527,29546,29544,29552,29560,29557,29563,29562,
+ 29640,29619,29646,29627,29632,29669,29678,29662,29858,29701,29807,29733,
+ 29688,29746,29754,29781,29759,29791,29785,29761,29788,29801,29808,29795,
+ 29802,29814,29822,29835,29854,29863,29898,29903,29908,29681,},
+{29920,29923,29927,29929,29934,29938,29936,29937,29944,29943,29956,29955,
+ 29957,29964,29966,29965,29973,29971,29982,29990,29996,30012,30020,30029,
+ 30026,30025,30043,30022,30042,30057,30052,30055,30059,30061,30072,30070,
+ 30086,30087,30068,30090,30089,30082,30100,30106,30109,30117,30115,30146,
+ 30131,30147,30133,30141,30136,30140,30129,30157,30154,30162,30169,30179,
+ 30174,30206,30207,30204,30209,30192,30202,30194,30195,30219,30221,30217,
+ 30239,30247,30240,30241,30242,30244,30260,30256,30267,30279,30280,30278,
+ 30300,30296,30305,30306,30312,30313,30314,30311,30316,30320,},
+{30322,30326,30328,30332,30336,30339,30344,30347,30350,30358,30355,30361,
+ 30362,30384,30388,30392,30393,30394,30402,30413,30422,30418,30430,30433,
+ 30437,30439,30442,34351,30459,30472,30471,30468,30505,30500,30494,30501,
+ 30502,30491,30519,30520,30535,30554,30568,30571,30555,30565,30591,30590,
+ 30585,30606,30603,30609,30624,30622,30640,30646,30649,30655,30652,30653,
+ 30651,30663,30669,30679,30682,30684,30691,30702,30716,30732,30738,31014,
+ 30752,31018,30789,30862,30836,30854,30844,30874,30860,30883,30901,30890,
+ 30895,30929,30918,30923,30932,30910,30908,30917,30922,30956,},
+{30951,30938,30973,30964,30983,30994,30993,31001,31020,31019,31040,31072,
+ 31063,31071,31066,31061,31059,31098,31103,31114,31133,31143,40779,31146,
+ 31150,31155,31161,31162,31177,31189,31207,31212,31201,31203,31240,31245,
+ 31256,31257,31264,31263,31104,31281,31291,31294,31287,31299,31319,31305,
+ 31329,31330,31337,40861,31344,31353,31357,31368,31383,31381,31384,31382,
+ 31401,31432,31408,31414,31429,31428,31423,36995,31431,31434,31437,31439,
+ 31445,31443,31449,31450,31453,31457,31458,31462,31469,31472,31490,31503,
+ 31498,31494,31539,31512,31513,31518,31541,31528,31542,31568,},
+{31610,31492,31565,31499,31564,31557,31605,31589,31604,31591,31600,31601,
+ 31596,31598,31645,31640,31647,31629,31644,31642,31627,31634,31631,31581,
+ 31641,31691,31681,31692,31695,31668,31686,31709,31721,31761,31764,31718,
+ 31717,31840,31744,31751,31763,31731,31735,31767,31757,31734,31779,31783,
+ 31786,31775,31799,31787,31805,31820,31811,31828,31823,31808,31824,31832,
+ 31839,31844,31830,31845,31852,31861,31875,31888,31908,31917,31906,31915,
+ 31905,31912,31923,31922,31921,31918,31929,31933,31936,31941,31938,31960,
+ 31954,31964,31970,39739,31983,31986,31988,31990,31994,32006,},
+{32002,32028,32021,32010,32069,32075,32046,32050,32063,32053,32070,32115,
+ 32086,32078,32114,32104,32110,32079,32099,32147,32137,32091,32143,32125,
+ 32155,32186,32174,32163,32181,32199,32189,32171,32317,32162,32175,32220,
+ 32184,32159,32176,32216,32221,32228,32222,32251,32242,32225,32261,32266,
+ 32291,32289,32274,32305,32287,32265,32267,32290,32326,32358,32315,32309,
+ 32313,32323,32311,32306,32314,32359,32349,32342,32350,32345,32346,32377,
+ 32362,32361,32380,32379,32387,32213,32381,36782,32383,32392,32393,32396,
+ 32402,32400,32403,32404,32406,32398,32411,32412,32568,32570,},
+{32581,32588,32589,32590,32592,32593,32597,32596,32600,32607,32608,32616,
+ 32617,32615,32632,32642,32646,32643,32648,32647,32652,32660,32670,32669,
+ 32666,32675,32687,32690,32697,32686,32694,32696,35697,32709,32710,32714,
+ 32725,32724,32737,32742,32745,32755,32761,39132,32774,32772,32779,32786,
+ 32792,32793,32796,32801,32808,32831,32827,32842,32838,32850,32856,32858,
+ 32863,32866,32872,32883,32882,32880,32886,32889,32893,32895,32900,32902,
+ 32901,32923,32915,32922,32941,20880,32940,32987,32997,32985,32989,32964,
+ 32986,32982,33033,33007,33009,33051,33065,33059,33071,33099,},
+{38539,33094,33086,33107,33105,33020,33137,33134,33125,33126,33140,33155,
+ 33160,33162,33152,33154,33184,33173,33188,33187,33119,33171,33193,33200,
+ 33205,33214,33208,33213,33216,33218,33210,33225,33229,33233,33241,33240,
+ 33224,33242,33247,33248,33255,33274,33275,33278,33281,33282,33285,33287,
+ 33290,33293,33296,33302,33321,33323,33336,33331,33344,33369,33368,33373,
+ 33370,33375,33380,33378,33384,33386,33387,33326,33393,33399,33400,33406,
+ 33421,33426,33451,33439,33467,33452,33505,33507,33503,33490,33524,33523,
+ 33530,33683,33539,33531,33529,33502,33542,33500,33545,33497,},
+{33589,33588,33558,33586,33585,33600,33593,33616,33605,33583,33579,33559,
+ 33560,33669,33690,33706,33695,33698,33686,33571,33678,33671,33674,33660,
+ 33717,33651,33653,33696,33673,33704,33780,33811,33771,33742,33789,33795,
+ 33752,33803,33729,33783,33799,33760,33778,33805,33826,33824,33725,33848,
+ 34054,33787,33901,33834,33852,34138,33924,33911,33899,33965,33902,33922,
+ 33897,33862,33836,33903,33913,33845,33994,33890,33977,33983,33951,34009,
+ 33997,33979,34010,34000,33985,33990,34006,33953,34081,34047,34036,34071,
+ 34072,34092,34079,34069,34068,34044,34112,34147,34136,34120,},
+{34113,34306,34123,34133,34176,34212,34184,34193,34186,34216,34157,34196,
+ 34203,34282,34183,34204,34167,34174,34192,34249,34234,34255,34233,34256,
+ 34261,34269,34277,34268,34297,34314,34323,34315,34302,34298,34310,34338,
+ 34330,34352,34367,34381,20053,34388,34399,34407,34417,34451,34467,34473,
+ 34474,34443,34444,34486,34479,34500,34502,34480,34505,34851,34475,34516,
+ 34526,34537,34540,34527,34523,34543,34578,34566,34568,34560,34563,34555,
+ 34577,34569,34573,34553,34570,34612,34623,34615,34619,34597,34601,34586,
+ 34656,34655,34680,34636,34638,34676,34647,34664,34670,34649,},
+{34643,34659,34666,34821,34722,34719,34690,34735,34763,34749,34752,34768,
+ 38614,34731,34756,34739,34759,34758,34747,34799,34802,34784,34831,34829,
+ 34814,34806,34807,34830,34770,34833,34838,34837,34850,34849,34865,34870,
+ 34873,34855,34875,34884,34882,34898,34905,34910,34914,34923,34945,34942,
+ 34974,34933,34941,34997,34930,34946,34967,34962,34990,34969,34978,34957,
+ 34980,34992,35007,34993,35011,35012,35028,35032,35033,35037,35065,35074,
+ 35068,35060,35048,35058,35076,35084,35082,35091,35139,35102,35109,35114,
+ 35115,35137,35140,35131,35126,35128,35148,35101,35168,35166,},
+{35174,35172,35181,35178,35183,35188,35191,35198,35203,35208,35210,35219,
+ 35224,35233,35241,35238,35244,35247,35250,35258,35261,35263,35264,35290,
+ 35292,35293,35303,35316,35320,35331,35350,35344,35340,35355,35357,35365,
+ 35382,35393,35419,35410,35398,35400,35452,35437,35436,35426,35461,35458,
+ 35460,35496,35489,35473,35493,35494,35482,35491,35524,35533,35522,35546,
+ 35563,35571,35559,35556,35569,35604,35552,35554,35575,35550,35547,35596,
+ 35591,35610,35553,35606,35600,35607,35616,35635,38827,35622,35627,35646,
+ 35624,35649,35660,35663,35662,35657,35670,35675,35674,35691,},
+{35679,35692,35695,35700,35709,35712,35724,35726,35730,35731,35734,35737,
+ 35738,35898,35905,35903,35912,35916,35918,35920,35925,35938,35948,35960,
+ 35962,35970,35977,35973,35978,35981,35982,35988,35964,35992,25117,36013,
+ 36010,36029,36018,36019,36014,36022,36040,36033,36068,36067,36058,36093,
+ 36090,36091,36100,36101,36106,36103,36111,36109,36112,40782,36115,36045,
+ 36116,36118,36199,36205,36209,36211,36225,36249,36290,36286,36282,36303,
+ 36314,36310,36300,36315,36299,36330,36331,36319,36323,36348,36360,36361,
+ 36351,36381,36382,36368,36383,36418,36405,36400,36404,36426,},
+{36423,36425,36428,36432,36424,36441,36452,36448,36394,36451,36437,36470,
+ 36466,36476,36481,36487,36485,36484,36491,36490,36499,36497,36500,36505,
+ 36522,36513,36524,36528,36550,36529,36542,36549,36552,36555,36571,36579,
+ 36604,36603,36587,36606,36618,36613,36629,36626,36633,36627,36636,36639,
+ 36635,36620,36646,36659,36667,36665,36677,36674,36670,36684,36681,36678,
+ 36686,36695,36700,36706,36707,36708,36764,36767,36771,36781,36783,36791,
+ 36826,36837,36834,36842,36847,36999,36852,36869,36857,36858,36881,36885,
+ 36897,36877,36894,36886,36875,36903,36918,36917,36921,36856,},
+{36943,36944,36945,36946,36878,36937,36926,36950,36952,36958,36968,36975,
+ 36982,38568,36978,36994,36989,36993,36992,37002,37001,37007,37032,37039,
+ 37041,37045,37090,37092,25160,37083,37122,37138,37145,37170,37168,37194,
+ 37206,37208,37219,37221,37225,37235,37234,37259,37257,37250,37282,37291,
+ 37295,37290,37301,37300,37306,37312,37313,37321,37323,37328,37334,37343,
+ 37345,37339,37372,37365,37366,37406,37375,37396,37420,37397,37393,37470,
+ 37463,37445,37449,37476,37448,37525,37439,37451,37456,37532,37526,37523,
+ 37531,37466,37583,37561,37559,37609,37647,37626,37700,37678,},
+{37657,37666,37658,37667,37690,37685,37691,37724,37728,37756,37742,37718,
+ 37808,37804,37805,37780,37817,37846,37847,37864,37861,37848,37827,37853,
+ 37840,37832,37860,37914,37908,37907,37891,37895,37904,37942,37931,37941,
+ 37921,37946,37953,37970,37956,37979,37984,37986,37982,37994,37417,38000,
+ 38005,38007,38013,37978,38012,38014,38017,38015,38274,38279,38282,38292,
+ 38294,38296,38297,38304,38312,38311,38317,38332,38331,38329,38334,38346,
+ 28662,38339,38349,38348,38357,38356,38358,38364,38369,38373,38370,38433,
+ 38440,38446,38447,38466,38476,38479,38475,38519,38492,38494,},
+{38493,38495,38502,38514,38508,38541,38552,38549,38551,38570,38567,38577,
+ 38578,38576,38580,38582,38584,38585,38606,38603,38601,38605,35149,38620,
+ 38669,38613,38649,38660,38662,38664,38675,38670,38673,38671,38678,38681,
+ 38692,38698,38704,38713,38717,38718,38724,38726,38728,38722,38729,38748,
+ 38752,38756,38758,38760,21202,38763,38769,38777,38789,38780,38785,38778,
+ 38790,38795,38799,38800,38812,38824,38822,38819,38835,38836,38851,38854,
+ 38856,38859,38876,38893,40783,38898,31455,38902,38901,38927,38924,38968,
+ 38948,38945,38967,38973,38982,38991,38987,39019,39023,39024,},
+{39025,39028,39027,39082,39087,39089,39094,39108,39107,39110,39145,39147,
+ 39171,39177,39186,39188,39192,39201,39197,39198,39204,39200,39212,39214,
+ 39229,39230,39234,39241,39237,39248,39243,39249,39250,39244,39253,39319,
+ 39320,39333,39341,39342,39356,39391,39387,39389,39384,39377,39405,39406,
+ 39409,39410,39419,39416,39425,39439,39429,39394,39449,39467,39479,39493,
+ 39490,39488,39491,39486,39509,39501,39515,39511,39519,39522,39525,39524,
+ 39529,39531,39530,39597,39600,39612,39616,39631,39633,39635,39636,39646,
+ 39647,39650,39651,39654,39663,39659,39662,39668,39665,39671,},
+{39675,39686,39704,39706,39711,39714,39715,39717,39719,39720,39721,39722,
+ 39726,39727,39730,39748,39747,39759,39757,39758,39761,39768,39796,39827,
+ 39811,39825,39830,39831,39839,39840,39848,39860,39872,39882,39865,39878,
+ 39887,39889,39890,39907,39906,39908,39892,39905,39994,39922,39921,39920,
+ 39957,39956,39945,39955,39948,39942,39944,39954,39946,39940,39982,39963,
+ 39973,39972,39969,39984,40007,39986,40006,39998,40026,40032,40039,40054,
+ 40056,40167,40172,40176,40201,40200,40171,40195,40198,40234,40230,40367,
+ 40227,40223,40260,40213,40210,40257,40255,40254,40262,40264,},
+{40285,40286,40292,40273,40272,40281,40306,40329,40327,40363,40303,40314,
+ 40346,40356,40361,40370,40388,40385,40379,40376,40378,40390,40399,40386,
+ 40409,40403,40440,40422,40429,40431,40445,40474,40475,40478,40565,40569,
+ 40573,40577,40584,40587,40588,40594,40597,40593,40605,40613,40617,40632,
+ 40618,40621,38753,40652,40654,40655,40656,40660,40668,40670,40669,40672,
+ 40677,40680,40687,40692,40694,40695,40697,40699,40700,40701,40711,40712,
+ 30391,40725,40737,40748,40766,40778,40786,40788,40803,40799,40800,40801,
+ 40806,40807,40812,40810,40823,40818,40822,40853,40860,40864,},
+{22575,27079,36953,29796,20956,29081,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+};
+
+
+// ------------------------------------------------------------
+unsigned short JISConverter::sjisToUnicode(unsigned short sjis)
+{
+       unsigned short u;
+       unsigned int c = sjis>>8;
+       unsigned int c1 = sjis&0xff;
+  
+       c = c + c - ((c <= 0x9f) ? SJ0162 : SJ6394);
+       if(c1 < 0x9f) 
+       {
+               c1 = c1 - ((c1 > 0x7f) ? 0x20 : 0x1f); 
+       }
+       else 
+       {
+           c1 = c1 - 0x7e; c++; 
+       }
+       c -= 33; 
+       c1 -= 33;
+       if(c < 0 || c1 < 0 || c > 93 || c1 > 93)
+               u = 0x3013; 
+       else
+       {
+               u = uniTable[c][c1]; 
+               if(!u) 
+                       u = 0x3013; 
+       }
+
+       return u;
+}
+// ------------------------------------------------------------
+unsigned short JISConverter::eucToUnicode(unsigned short euc)
+{      
+       unsigned short u;
+       unsigned int c = euc>>8;
+       unsigned int c1 = euc&0xff; 
+
+       c &= 0x7f; 
+       c -= 33; 
+       c1 &= 0x7f; 
+       c1 -= 33;
+    if(c < 0 || c1 < 0 || c > 93 || c1 > 93)
+               u = 0x3013; 
+    else 
+       {
+        u = uniTable[c][c1]; 
+               if(!u) 
+                       u = 0x3013; 
+       }
+       return u;
+}
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/jis.h b/c:/Git/PeerCast.root/PeerCast/core/common/jis.h
new file mode 100644 (file)
index 0000000..da4df03
--- /dev/null
@@ -0,0 +1,35 @@
+// ------------------------------------------------
+// File : jis.h
+// Date: 1-april-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _JIS_H
+#define _JIS_H
+
+// ----------------------------------
+class JISConverter
+{
+public:
+
+       static unsigned short sjisToUnicode(unsigned short);
+       static unsigned short eucToUnicode(unsigned short);
+};
+
+
+
+#endif
+
+
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/mms.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/mms.cpp
new file mode 100644 (file)
index 0000000..2ddafbc
--- /dev/null
@@ -0,0 +1,194 @@
+// ------------------------------------------------
+// File : mms.cpp
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "channel.h"
+#include "mms.h"
+#include "asf.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ------------------------------------------
+ASFInfo parseASFHeader(Stream &in);
+
+
+// ------------------------------------------
+void MMSStream::readEnd(Stream &,Channel *)
+{
+}
+
+// ------------------------------------------
+void MMSStream::readHeader(Stream &,Channel *)
+{
+}
+// ------------------------------------------
+int MMSStream::readPacket(Stream &in,Channel *ch)
+{
+       {
+               ASFChunk chunk;
+
+               chunk.read(in);
+
+               switch (chunk.type)
+               {
+                       case 0x4824:            // asf header
+                       {
+                               MemoryStream mem(ch->headPack.data,sizeof(ch->headPack.data));
+
+                               chunk.write(mem);
+
+
+
+
+                               MemoryStream asfm(chunk.data,chunk.dataLen);
+                               ASFObject asfHead;
+                               asfHead.readHead(asfm);
+
+                               ASFInfo asf = parseASFHeader(asfm);
+                               LOG_DEBUG("ASF Info: pnum=%d, psize=%d, br=%d",asf.numPackets,asf.packetSize,asf.bitrate);
+                               for(int i=0; i<ASFInfo::MAX_STREAMS; i++)
+                               {
+                                       ASFStream *s = &asf.streams[i];
+                                       if (s->id)
+                                               LOG_DEBUG("ASF Stream %d : %s, br=%d",s->id,s->getTypeName(),s->bitrate);
+                               }
+
+                               ch->info.bitrate = asf.bitrate/1000;
+
+                               ch->headPack.type = ChanPacket::T_HEAD;
+                               ch->headPack.len = mem.pos;
+                               ch->headPack.pos = ch->streamPos;
+                               ch->newPacket(ch->headPack);
+
+                               ch->streamPos += ch->headPack.len;
+
+                               break;
+                       }
+                       case 0x4424:            // asf data
+                       {
+
+                               ChanPacket pack;
+
+                               MemoryStream mem(pack.data,sizeof(pack.data));
+
+                               chunk.write(mem);
+
+                               pack.type = ChanPacket::T_DATA;
+                               pack.len = mem.pos;
+                               pack.pos = ch->streamPos;
+
+                               ch->newPacket(pack);
+                               ch->streamPos += pack.len;
+
+                               break;
+                       }
+                       default:
+                               throw StreamException("Unknown ASF chunk");
+
+               }
+
+       }
+       return 0;
+}
+
+
+// -----------------------------------
+ASFInfo parseASFHeader(Stream &in)
+{
+       ASFInfo asf;
+
+       try
+       {
+               int numHeaders = in.readLong();
+
+               in.readChar();
+               in.readChar();
+
+               LOG_CHANNEL("ASF Headers: %d",numHeaders);
+               for(int i=0; i<numHeaders; i++)
+               {
+
+                       ASFObject obj;
+
+                       unsigned int l = obj.readHead(in);
+                       obj.readData(in,l);
+
+
+                       MemoryStream data(obj.data,obj.lenLo);
+
+
+                       switch (obj.type)
+                       {
+                               case ASFObject::T_FILE_PROP:
+                               {
+                                       data.skip(32);
+
+                                       unsigned int dpLo = data.readLong();
+                                       unsigned int dpHi = data.readLong();
+
+                                       data.skip(24);
+
+                                       data.readLong();
+                                       //data.writeLong(1);    // flags = broadcast, not seekable
+
+                                       int min = data.readLong();
+                                       int max = data.readLong();
+                                       int br = data.readLong();
+
+                                       if (min != max)
+                                               throw StreamException("ASF packetsizes (min/max) must match");
+
+                                       asf.packetSize = max;
+                                       asf.bitrate = br;
+                                       asf.numPackets = dpLo;
+                                       break;
+                               }
+                               case ASFObject::T_STREAM_BITRATE:
+                               {
+                                       int cnt = data.readShort();
+                                       for(int i=0; i<cnt; i++)
+                                       {
+                                               unsigned int id = data.readShort();
+                                               int bitrate = data.readLong();
+                                               if (id < ASFInfo::MAX_STREAMS)
+                                                       asf.streams[id].bitrate = bitrate;
+                                       }
+                                       break;
+                               }
+                               case ASFObject::T_STREAM_PROP:
+                               {
+                                       ASFStream s;
+                                       s.read(data);
+                                       asf.streams[s.id].id = s.id;
+                                       asf.streams[s.id].type = s.type;
+                                       break;
+                               }
+                       }
+
+               }
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("ASF: %s",e.msg);
+       }
+
+       return asf;
+}
+
+
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/mms.h b/c:/Git/PeerCast.root/PeerCast/core/common/mms.h
new file mode 100644 (file)
index 0000000..11195a7
--- /dev/null
@@ -0,0 +1,37 @@
+// ------------------------------------------------
+// File : mms.h
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _MMS_H
+#define _MMS_H
+
+
+#include "channel.h"
+
+// ----------------------------------------------
+class MMSStream : public ChannelStream
+{
+public:
+
+       virtual void readHeader(Stream &,Channel *);
+       virtual int readPacket(Stream &,Channel *);
+       virtual void readEnd(Stream &,Channel *);
+};
+
+
+#endif 
+
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/mp3.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/mp3.cpp
new file mode 100644 (file)
index 0000000..4997927
--- /dev/null
@@ -0,0 +1,82 @@
+// ------------------------------------------------
+// File : mp3.cpp
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "channel.h"
+#include "mp3.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+// ------------------------------------------
+void MP3Stream::readEnd(Stream &,Channel *)
+{
+}
+
+// ------------------------------------------
+void MP3Stream::readHeader(Stream &,Channel *)
+{
+}
+// ------------------------------------------
+int MP3Stream::readPacket(Stream &in,Channel *ch)
+{
+       ChanPacket pack;
+
+       if (ch->icyMetaInterval)
+       {
+
+               int rlen = ch->icyMetaInterval;
+
+               while (rlen)
+               {
+                       int rl = rlen;
+                       if (rl > ChanMgr::MAX_METAINT)
+                               rl = ChanMgr::MAX_METAINT;
+
+                       pack.init(ChanPacket::T_DATA,pack.data,rl,ch->streamPos);
+                       in.read(pack.data,pack.len);
+                       ch->newPacket(pack);
+                       ch->checkReadDelay(pack.len);
+                       ch->streamPos+=pack.len;
+
+                       rlen-=rl;
+               }
+
+               unsigned char len;
+               in.read(&len,1);
+               if (len)
+               {
+                       if (len*16 > 1024) len = 1024/16;
+                       char buf[1024];
+                       in.read(buf,len*16);
+                       ch->processMp3Metadata(buf);
+               }
+
+       }else{
+
+               pack.init(ChanPacket::T_DATA,pack.data,ChanMgr::MAX_METAINT,ch->streamPos);
+               in.read(pack.data,pack.len);
+               ch->newPacket(pack);
+               ch->checkReadDelay(pack.len);
+
+               ch->streamPos += pack.len;
+       }
+       return 0;
+}
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/mp3.h b/c:/Git/PeerCast.root/PeerCast/core/common/mp3.h
new file mode 100644 (file)
index 0000000..2297d10
--- /dev/null
@@ -0,0 +1,35 @@
+// ------------------------------------------------
+// File : mp3.h
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _MP3_H
+#define _MP3_H
+
+
+#include "channel.h"
+
+// ----------------------------------------------
+class MP3Stream : public ChannelStream
+{
+public:
+       virtual void readHeader(Stream &,Channel *);
+       virtual int      readPacket(Stream &,Channel *);
+       virtual void readEnd(Stream &,Channel *);
+};
+
+
+#endif 
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/nsv.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/nsv.cpp
new file mode 100644 (file)
index 0000000..55cdb98
--- /dev/null
@@ -0,0 +1,80 @@
+// ------------------------------------------------
+// File : nsv.cpp
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "nsv.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ------------------------------------------
+void NSVStream::readEnd(Stream &,Channel *)
+{
+}
+
+// ------------------------------------------
+void NSVStream::readHeader(Stream &,Channel *)
+{
+}
+// ------------------------------------------
+int NSVStream::readPacket(Stream &in,Channel *ch)
+{
+       ChanPacket pack;
+
+       if (ch->icyMetaInterval)
+       {
+
+               int rlen = ch->icyMetaInterval;
+
+               while (rlen)
+               {
+                       int rl = rlen;
+                       if (rl > ChanMgr::MAX_METAINT)
+                               rl = ChanMgr::MAX_METAINT;
+
+                       pack.init(ChanPacket::T_DATA,pack.data,rl,ch->streamPos);
+                       in.read(pack.data,pack.len);
+                       ch->newPacket(pack);
+                       ch->checkReadDelay(pack.len);
+                       ch->streamPos+=pack.len;
+
+                       rlen-=rl;
+               }
+
+               unsigned char len;
+               in.read(&len,1);
+               if (len)
+               {
+                       if (len*16 > 1024) len = 1024/16;
+                       char buf[1024];
+                       in.read(buf,len*16);
+                       ch->processMp3Metadata(buf);
+               }
+
+       }else{
+
+               pack.init(ChanPacket::T_DATA,pack.data,ChanMgr::MAX_METAINT,ch->streamPos);
+               in.read(pack.data,pack.len);
+               ch->newPacket(pack);
+               ch->checkReadDelay(pack.len);
+
+               ch->streamPos += pack.len;
+       }
+       return 0;
+}
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/nsv.h b/c:/Git/PeerCast.root/PeerCast/core/common/nsv.h
new file mode 100644 (file)
index 0000000..cca0106
--- /dev/null
@@ -0,0 +1,35 @@
+// ------------------------------------------------
+// File : nsv.h
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _NSV_H
+#define _NSV_H
+
+
+#include "channel.h"
+
+// ----------------------------------------------
+class NSVStream : public ChannelStream
+{
+public:
+       virtual void readHeader(Stream &,Channel *);
+       virtual int readPacket(Stream &,Channel *);
+       virtual void readEnd(Stream &,Channel *);
+};
+
+
+#endif 
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/ogg.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/ogg.cpp
new file mode 100644 (file)
index 0000000..ed38bc7
--- /dev/null
@@ -0,0 +1,494 @@
+// ------------------------------------------------
+// File : mp3.cpp
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "channel.h"
+#include "ogg.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+static int test=0;
+// ------------------------------------------
+void OGGStream::readHeader(Stream &,Channel *)
+{
+       test = 0;
+}
+
+// ------------------------------------------
+void OGGStream::readEnd(Stream &,Channel *)
+{
+}
+
+// ------------------------------------------
+int OGGStream::readPacket(Stream &in,Channel *ch)
+{
+       OggPage ogg;
+       ChanPacket pack;
+
+       ogg.read(in);
+
+       if (ogg.isBOS())
+       {
+               if (!vorbis.needHeader() && !theora.needHeader())
+               {
+                       ch->headPack.len = 0;
+               }
+
+               if (ogg.detectVorbis())
+                       vorbis.bos(ogg.getSerialNo());
+               if (ogg.detectTheora())
+                       theora.bos(ogg.getSerialNo());
+       }
+
+       if (ogg.isEOS())
+       {
+
+               if (ogg.getSerialNo() == vorbis.serialNo)
+               {
+                       LOG_CHANNEL("Vorbis stream: EOS");
+                       vorbis.eos();
+               }
+               if (ogg.getSerialNo() == theora.serialNo)
+               {
+                       LOG_CHANNEL("Theora stream: EOS");
+                       theora.eos();
+               }
+       }
+
+       if (vorbis.needHeader() || theora.needHeader())
+       {
+
+               if (ogg.getSerialNo() == vorbis.serialNo)
+                       vorbis.readHeader(ch,ogg);
+               else if (ogg.getSerialNo() == theora.serialNo)
+                       theora.readHeader(ch,ogg);
+               else
+                       throw StreamException("Bad OGG serial no.");
+
+
+               if (!vorbis.needHeader() && !theora.needHeader())
+               {
+
+                       ch->info.bitrate = 0;
+
+                       if (vorbis.isActive())
+                               ch->info.bitrate += vorbis.bitrate;
+
+                       if (theora.isActive())
+                       {
+                               ch->info.bitrate += theora.bitrate;
+                               ch->info.contentType = ChanInfo::T_OGM;
+                       }
+
+                       
+                       ch->headPack.type = ChanPacket::T_HEAD;
+                       ch->headPack.pos = ch->streamPos;
+
+                       ch->startTime = sys->getDTime();                
+
+                       ch->streamPos += ch->headPack.len;
+
+                       ch->newPacket(ch->headPack);
+                       LOG_CHANNEL("Got %d bytes of headers",ch->headPack.len);
+               }
+
+       }else
+       {
+
+
+               pack.init(ChanPacket::T_DATA,ogg.data,ogg.headLen+ogg.bodyLen,ch->streamPos);
+               ch->newPacket(pack);
+
+               ch->streamPos+=pack.len;
+
+               if (theora.isActive())
+               {
+                       if (ogg.getSerialNo() == theora.serialNo)
+                       {
+                               ch->sleepUntil(theora.getTime(ogg));
+                       }
+               }else if (vorbis.isActive())
+               {
+                       if (ogg.getSerialNo() == vorbis.serialNo)
+                       {
+                               ch->sleepUntil(vorbis.getTime(ogg));
+                       }
+               }
+
+       }
+       return 0;
+}
+
+// -----------------------------------
+void OggSubStream::readHeader(Channel *ch,OggPage &ogg)
+{
+       if ((pack.bodyLen + ogg.bodyLen) >= OggPacket::MAX_BODYLEN)
+               throw StreamException("OGG packet too big");
+
+       if (ch->headPack.len+(ogg.bodyLen+ogg.headLen) >= ChanMeta::MAX_DATALEN)
+               throw StreamException("OGG packet too big for headMeta");
+
+// copy complete packet into head packet
+       memcpy(&ch->headPack.data[ch->headPack.len],ogg.data,ogg.headLen+ogg.bodyLen);
+       ch->headPack.len += ogg.headLen+ogg.bodyLen;
+
+       // add body to packet
+       memcpy(&pack.body[pack.bodyLen],&ogg.data[ogg.headLen],ogg.bodyLen);
+       pack.bodyLen += ogg.bodyLen;
+
+       pack.addLacing(ogg);
+
+       if (pack.numPackets >= maxHeaders)
+               procHeaders(ch);
+
+}
+// -----------------------------------
+void OggVorbisSubStream::procHeaders(Channel *ch)
+{
+       unsigned int packPtr=0;
+
+       for(int i=0; i<pack.numPackets; i++)
+       {
+               MemoryStream vin(&pack.body[packPtr],pack.packetSizes[i]);
+
+               packPtr += pack.packetSizes[i];
+
+               char id[8];
+
+               vin.read(id,7);
+               id[7]=0;
+
+               switch (id[0])
+               {
+                       case 1: // ident
+                               LOG_CHANNEL("OGG Vorbis Header: Ident (%d bytes)",vin.len);
+                               readIdent(vin,ch->info);
+                               break;
+                       case 3: // comment
+                               {
+                                       LOG_CHANNEL("OGG Vorbis Header: Comment (%d bytes)",vin.len);
+                                       ChanInfo newInfo = ch->info;
+                                       readComment(vin,newInfo);
+                                       ch->updateInfo(newInfo);
+                               }
+                               break;
+                       case 5: // setup
+                               LOG_CHANNEL("OGG Vorbis Header: Setup (%d bytes)",vin.len);
+                               //readSetup(vin);
+                               break;
+                       default:
+                               throw StreamException("Unknown Vorbis packet header type");
+                               break;
+               }
+       }
+
+}
+// -----------------------------------
+double OggTheoraSubStream::getTime(OggPage &ogg)
+{
+    int64_t iframe=ogg.granPos>>granposShift;
+    int64_t pframe=ogg.granPos-(iframe<<granposShift);
+
+    return (iframe+pframe)*frameTime;
+}
+// -----------------------------------
+void OggTheoraSubStream::readInfo(Stream &in, ChanInfo &info)
+{
+       int verMaj = in.readBits(8);
+       int verMin = in.readBits(8);
+       int verSub = in.readBits(8);
+
+       int encWidth = in.readBits(16) << 4;
+       int encHeight = in.readBits(16) << 4;
+
+       in.readBits(24+24+8+8);
+
+       int fpsNum = in.readBits(32);
+       int fpsDen = in.readBits(32);
+
+       float fps = (float)fpsNum/(float)fpsDen;
+       frameTime = (double)fpsDen/(double)fpsNum;
+
+       in.readBits(24+24+8);
+
+       bitrate = in.readBits(24) / 1000;
+       int quality = in.readBits(6);
+
+       granposShift = in.readBits(5);
+
+       LOG_CHANNEL("OGG Theora Info: %dx%dx%.1ffps %dkbps %dQ %dG",encWidth,encHeight,fps,bitrate,quality,granposShift);
+
+
+}
+// -----------------------------------
+void OggTheoraSubStream::procHeaders(Channel *ch)
+{
+       unsigned int packPtr=0;
+
+       for(int i=0; i<pack.numPackets; i++)
+       {
+               MemoryStream vin(&pack.body[packPtr],pack.packetSizes[i]);
+
+               packPtr += pack.packetSizes[i];
+
+               unsigned char id[8];
+
+               vin.read(id,7);
+               id[7]=0;
+
+               switch (id[0] & 0xff)
+               {
+                       case 128:       // info
+                               LOG_CHANNEL("OGG Theora Header: Info (%d bytes)",vin.len);
+                               readInfo(vin,ch->info);
+                               break;
+                       default:
+                               LOG_CHANNEL("OGG Theora Header: Unknown %d (%d bytes)",id[0] & 0xff,vin.len);
+                               break;
+               }
+
+
+
+       }
+
+}
+
+// -----------------------------------
+double OggVorbisSubStream::getTime(OggPage &ogg)
+{
+       return (double)ogg.granPos / (double)samplerate;
+
+}
+
+// -----------------------------------
+void OggVorbisSubStream::readIdent(Stream &in, ChanInfo &info)
+{
+       int ver = in.readLong();
+       int chans = in.readChar();
+       samplerate = in.readLong();
+       int brMax = in.readLong();
+       int brNom = in.readLong();
+       int brLow = in.readLong();
+       
+
+       in.readChar();  // skip blocksize 0+1
+
+       LOG_CHANNEL("OGG Vorbis Ident: ver=%d, chans=%d, rate=%d, brMax=%d, brNom=%d, brLow=%d",
+               ver,chans,samplerate,brMax,brNom,brLow);
+
+
+       bitrate = brNom/1000;
+
+       char frame = in.readChar();             // framing bit
+       if (!frame)
+               throw StreamException("Bad Indent frame");
+
+}
+
+// -----------------------------------
+void OggVorbisSubStream::readSetup(Stream &in)
+{
+       // skip everything in packet
+       int cnt=0;
+       while (!in.eof())
+       {
+               cnt++;
+               in.readChar();
+       }
+
+       LOG_CHANNEL("Read %d bytes of Vorbis Setup",cnt);
+}
+// -----------------------------------
+void OggVorbisSubStream::readComment(Stream &in, ChanInfo &info)
+{
+       int vLen = in.readLong();       // vendor len
+
+       in.skip(vLen);
+
+       char argBuf[8192];
+
+       info.track.clear();
+
+       int cLen = in.readLong();       // comment len
+       for(int i=0; i<cLen; i++)
+       {
+               int l = in.readLong();
+               if (l > sizeof(argBuf))
+                       throw StreamException("Comment string too long");
+               in.read(argBuf,l);
+               argBuf[l] = 0;
+               LOG_CHANNEL("OGG Comment: %s",argBuf);
+
+               char *arg;
+               if ((arg=stristr(argBuf,"ARTIST=")))
+               {
+                       info.track.artist.set(arg+7,String::T_ASCII);
+                       info.track.artist.convertTo(String::T_UNICODE);
+
+               }else if ((arg=stristr(argBuf,"TITLE=")))
+               {
+                       info.track.title.set(arg+6,String::T_ASCII);
+                       info.track.title.convertTo(String::T_UNICODE);
+
+               }else if ((arg=stristr(argBuf,"GENRE=")))
+               {
+                       info.track.genre.set(arg+6,String::T_ASCII);
+                       info.track.genre.convertTo(String::T_UNICODE);
+
+               }else if ((arg=stristr(argBuf,"CONTACT=")))
+               {
+                       info.track.contact.set(arg+8,String::T_ASCII);
+                       info.track.contact.convertTo(String::T_UNICODE);
+
+               }else if ((arg=stristr(argBuf,"ALBUM=")))
+               {
+                       info.track.album.set(arg+6,String::T_ASCII);
+                       info.track.album.convertTo(String::T_UNICODE);
+               }
+       }
+
+       char frame = in.readChar();             // framing bit
+       if (!frame)
+               throw StreamException("Bad Comment frame");
+
+//     updateMeta();
+
+}
+
+// -----------------------------------
+bool OggPage::isBOS()
+{
+       return (data[5] & 0x02) != 0;
+}
+// -----------------------------------
+bool OggPage::isEOS()
+{
+       return (data[5] & 0x04) != 0;
+}
+// -----------------------------------
+bool OggPage::isNewPacket()
+{
+       return (data[5] & 0x01) == 0;
+}
+// -----------------------------------
+bool OggPage::isHeader()
+{
+       return ((*(unsigned int *)&data[6]) || (*(unsigned int *)&data[10])) == 0;
+}
+// -----------------------------------
+unsigned int OggPage::getSerialNo()
+{
+       return *(unsigned int *)&data[14];
+}
+
+// -----------------------------------
+void OggPage::read(Stream &in)
+{
+       // skip until we get OGG capture pattern
+       bool gotOgg=false;
+       while (!gotOgg)
+       {
+               if (in.readChar() == 'O')
+                       if (in.readChar() == 'g')
+                               if (in.readChar() == 'g')
+                                       if (in.readChar() == 'S')
+                                               gotOgg = true;
+               if (!gotOgg)
+                       LOG_CHANNEL("Skipping OGG packet");
+       }
+
+
+
+       memcpy(&data[0],"OggS",4);
+
+       in.read(&data[4],27-4);
+
+       int numSegs = data[26];
+       bodyLen = 0;
+
+       // read segment table
+       in.read(&data[27],numSegs);
+       for(int i=0; i<numSegs; i++)
+               bodyLen += data[27+i];
+
+       if (bodyLen >= MAX_BODYLEN)             
+               throw StreamException("OGG body too big");
+
+       headLen = 27+numSegs;
+
+       if (headLen > MAX_HEADERLEN)
+               throw StreamException("OGG header too big");
+
+       in.read(&data[headLen],bodyLen);
+
+       granPos = *(unsigned int *)&data[10];
+       granPos <<= 32;
+       granPos |= *(unsigned int *)&data[6];
+
+
+       #if 0
+               LOG_DEBUG("OGG Packet - page %d, id = %x - %s %s %s - %d:%d - %d segs, %d bytes",
+                       *(unsigned int *)&data[18],
+                       *(unsigned int *)&data[14],
+                       data[5]&0x1?"cont":"new",
+                       data[5]&0x2?"bos":"",
+                       data[5]&0x4?"eos":"",
+                       (unsigned int)(granPos>>32),
+                       (unsigned int)(granPos&0xffffffff),
+                       numSegs,
+                       headLen+bodyLen);
+
+       #endif
+
+}
+// -----------------------------------
+bool OggPage::detectVorbis()
+{
+       return memcmp(&data[headLen+1],"vorbis",6) == 0;
+}
+// -----------------------------------
+bool OggPage::detectTheora()
+{
+       return memcmp(&data[headLen+1],"theora",6) == 0;
+}
+
+// -----------------------------------
+void   OggPacket::addLacing(OggPage &ogg)
+{
+       
+       int numSegs = ogg.data[26];
+       for(int i=0; i<numSegs; i++)
+       {
+               int seg = ogg.data[27+i];
+
+               packetSizes[numPackets]+=seg;
+
+               if (seg < 255)
+               {
+                       numPackets++;
+                       if (numPackets >= MAX_PACKETS)
+                               throw StreamException("Too many OGG packets");
+                       packetSizes[numPackets]=0;
+               }
+       }
+
+}
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/ogg.h b/c:/Git/PeerCast.root/PeerCast/core/common/ogg.h
new file mode 100644 (file)
index 0000000..67a228c
--- /dev/null
@@ -0,0 +1,169 @@
+// ------------------------------------------------
+// File : ogg.h
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _OGG_H
+#define _OGG_H
+
+
+#include "channel.h"
+// ----------------------------------------------
+class OggPage;
+
+// ----------------------------------
+class OggPacket
+{
+public:
+       enum 
+       {
+               MAX_BODYLEN = 65536,            // probably too small
+               MAX_PACKETS = 256                       // prolly too small too, but realloc?!?!?!
+       };
+
+       void    addLacing(OggPage &);
+
+       int     bodyLen;
+       unsigned char body[MAX_BODYLEN];
+
+
+       int     numPackets;
+       unsigned int packetSizes[MAX_PACKETS];
+};
+
+// ----------------------------------------------
+class OggSubStream
+{
+public:
+       OggSubStream()
+       :maxHeaders(0),serialNo(0),bitrate(0)
+       {}
+
+       bool needHeader()
+       {
+               return maxHeaders && (pack.numPackets < maxHeaders);
+       }
+
+       void eos()
+       {
+               maxHeaders=0;
+               serialNo=0;
+       }
+
+       void bos(unsigned int ser)
+       {
+               maxHeaders = 3;
+               pack.numPackets=0;
+               pack.packetSizes[0]=0;
+               pack.bodyLen = 0;
+               serialNo = ser;
+               bitrate = 0;
+       }
+
+       bool    isActive() {return serialNo!=0;}
+
+       void readHeader(Channel *,OggPage &);
+
+       virtual void procHeaders(Channel *) = 0;
+
+       int     bitrate;
+
+       OggPacket       pack;
+       int     maxHeaders;
+       unsigned int serialNo;
+};
+// ----------------------------------------------
+class OggVorbisSubStream : public OggSubStream
+{
+public:
+       OggVorbisSubStream()
+       :samplerate(0)
+       {}
+
+       virtual void procHeaders(Channel *);
+
+       void    readIdent(Stream &, ChanInfo &);
+       void    readSetup(Stream &);
+       void    readComment(Stream &, ChanInfo &);
+
+       double  getTime(OggPage &);
+
+       int samplerate;
+
+};
+// ----------------------------------------------
+class OggTheoraSubStream : public OggSubStream
+{
+public:
+       OggTheoraSubStream() : granposShift(0), frameTime(0) {}
+
+       virtual void procHeaders(Channel *);
+
+       void readInfo(Stream &, ChanInfo &);
+
+       double  getTime(OggPage &);
+
+       int granposShift;
+       double frameTime;
+};
+
+// ----------------------------------------------
+class OGGStream : public ChannelStream
+{
+public:
+       OGGStream()
+       {}
+
+
+       virtual void readHeader(Stream &,Channel *);
+       virtual int readPacket(Stream &,Channel *);
+       virtual void readEnd(Stream &,Channel *);
+
+
+       void    readHeaders(Stream &,Channel *, OggPage &);
+
+       OggVorbisSubStream      vorbis;
+       OggTheoraSubStream      theora; 
+};
+
+// ----------------------------------
+class OggPage
+{
+public:
+       enum 
+       {
+               MAX_BODYLEN = 65536,
+               MAX_HEADERLEN = 27+256
+       };
+
+       void    read(Stream &);
+       bool    isBOS();
+       bool    isEOS();
+       bool    isNewPacket();
+       bool    isHeader();
+       unsigned int getSerialNo();
+
+       bool    detectVorbis();
+       bool    detectTheora();
+
+
+       int64_t granPos;
+       int headLen,bodyLen;
+       unsigned char data[MAX_HEADERLEN+MAX_BODYLEN];
+};
+
+
+#endif 
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/pcp.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/pcp.cpp
new file mode 100644 (file)
index 0000000..37514ed
--- /dev/null
@@ -0,0 +1,886 @@
+// ------------------------------------------------
+// File : pcp.cpp
+// Date: 1-mar-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "atom.h"
+#include "pcp.h"
+#include "peercast.h"
+#include "version2.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ------------------------------------------
+void PCPStream::init(GnuID &rid)
+{
+       remoteID = rid;
+       routeList.clear();
+
+       lastPacketTime = 0;
+       nextRootPacket = 0;      // 0 seconds (never)
+
+       inData.init();
+       inData.accept = ChanPacket::T_PCP;
+
+       outData.init();
+       outData.accept = ChanPacket::T_PCP;
+}
+// ------------------------------------------
+void PCPStream::readVersion(Stream &in)
+{
+       int len = in.readInt();
+
+       if (len != 4)
+               throw StreamException("Invalid PCP");
+
+       int ver = in.readInt();
+
+       LOG_DEBUG("PCP ver: %d",ver);
+}
+// ------------------------------------------
+void PCPStream::readHeader(Stream &in,Channel *)
+{
+//     AtomStream atom(in);
+
+//     if (in.readInt() != PCP_CONNECT)
+//             throw StreamException("Not PCP");
+
+//     readVersion(in);
+}
+// ------------------------------------------
+bool PCPStream::sendPacket(ChanPacket &pack,GnuID &destID)
+{
+       if (destID.isSet())
+               if (!destID.isSame(remoteID))
+                       if (!routeList.contains(destID))
+                               return false;
+
+       return outData.writePacket(pack);
+}
+// ------------------------------------------
+void PCPStream::flush(Stream &in)
+{
+       ChanPacket pack;
+       // send outward packets
+       while (outData.numPending())
+       {
+               outData.readPacket(pack);
+               pack.writeRaw(in);
+       }
+}
+// ------------------------------------------
+int PCPStream::readPacket(Stream &in,Channel *)
+{
+       BroadcastState bcs;
+       return readPacket(in,bcs);
+}
+// ------------------------------------------
+int PCPStream::readPacket(Stream &in,BroadcastState &bcs)
+{
+       int error = PCP_ERROR_GENERAL;
+       try
+       {
+               AtomStream atom(in);
+
+               ChanPacket pack;
+               MemoryStream mem(pack.data,sizeof(pack.data));
+               AtomStream patom(mem);
+
+
+               // send outward packets
+               error = PCP_ERROR_WRITE;
+               if (outData.numPending())
+               {
+                       outData.readPacket(pack);
+                       pack.writeRaw(in);
+               }
+               error = PCP_ERROR_GENERAL;
+
+               if (outData.willSkip())
+               {
+                       error = PCP_ERROR_WRITE+PCP_ERROR_SKIP;
+                       throw StreamException("Send too slow");
+               }
+
+
+               error = PCP_ERROR_READ;
+               // poll for new downward packet
+               if (in.readReady())
+               {
+                       int numc,numd;
+                       ID4 id;
+
+                       id = atom.read(numc,numd);
+
+                       mem.rewind();
+                       pack.len = patom.writeAtoms(id, in, numc, numd);
+                       pack.type = ChanPacket::T_PCP;
+
+                       //inData.writePacket(pack);
+               //}
+               error = PCP_ERROR_GENERAL;
+
+               // process downward packets
+               //if (inData.numPending())
+               //{
+                       //inData.readPacket(pack);
+
+                       mem.rewind();
+
+                       //int numc,numd;
+                       id = patom.read(numc,numd);
+
+                       error = PCPStream::procAtom(patom,id,numc,numd,bcs);
+                       
+                       if (error)
+                               throw StreamException("PCP exception");
+               }
+
+               error = 0;
+
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("PCP readPacket: %s (%d)",e.msg,error);
+       }
+
+       return error;
+}
+
+// ------------------------------------------
+void PCPStream::readEnd(Stream &,Channel *)
+{
+}
+
+
+// ------------------------------------------
+void PCPStream::readPushAtoms(AtomStream &atom, int numc,BroadcastState &bcs)
+{
+       Host host;
+       GnuID   chanID;
+
+       chanID.clear();
+
+       for(int i=0; i<numc; i++)
+       {
+               int c,d;
+               ID4 id = atom.read(c,d);
+
+               if (id == PCP_PUSH_IP)
+                       host.ip = atom.readInt();
+               else if (id == PCP_PUSH_PORT)
+                       host.port = atom.readShort();
+               else if (id == PCP_PUSH_CHANID)
+                       atom.readBytes(chanID.id,16);
+               else
+               {
+                       LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d);
+                       atom.skip(c,d);
+               }
+       }
+
+
+       if (bcs.forMe)
+       {
+               char ipstr[64];
+               host.toStr(ipstr);
+
+               Servent *s = NULL;
+
+               if (chanID.isSet())
+               {
+                       Channel *ch = chanMgr->findChannelByID(chanID);
+                       if (ch)
+                               if (ch->isBroadcasting() || !ch->isFull() && !servMgr->relaysFull() && ch->info.id.isSame(chanID))
+                                       s = servMgr->allocServent();
+               }else{
+                       s = servMgr->allocServent();
+               }
+
+               if (s)
+               {
+                       LOG_DEBUG("GIVing to %s",ipstr);
+                       s->initGIV(host,chanID);
+               }
+       }
+
+}
+// ------------------------------------------
+void PCPStream::readRootAtoms(AtomStream &atom, int numc,BroadcastState &bcs)
+{
+       String url;
+
+       for(int i=0; i<numc; i++)
+       {
+               int c,d;
+               ID4 id = atom.read(c,d);
+
+               if (id == PCP_ROOT_UPDINT)
+               {
+                       int si = atom.readInt();
+
+                       chanMgr->setUpdateInterval(si);
+                       LOG_DEBUG("PCP got new host update interval: %ds",si);
+               }else if (id == PCP_ROOT_URL)
+               {
+                       url = "http://www.peercast.org/";
+                       String loc;
+                       atom.readString(loc.data,sizeof(loc.data),d);
+                       url.append(loc);
+
+               }else if (id == PCP_ROOT_CHECKVER)
+               {
+                       unsigned int newVer = atom.readInt();
+                       if (newVer > PCP_CLIENT_VERSION)
+                       {
+                               strcpy(servMgr->downloadURL,url.cstr());
+                               peercastApp->notifyMessage(ServMgr::NT_UPGRADE,"There is a new version available, please click here to upgrade your client.");
+                       }
+                       LOG_DEBUG("PCP got version check: %d / %d",newVer,PCP_CLIENT_VERSION);
+
+               }else if (id == PCP_ROOT_NEXT)
+               {
+                       unsigned int time = atom.readInt();
+
+                       if (time)
+                       {
+                               unsigned int ctime = sys->getTime();
+                               nextRootPacket = ctime+time;
+                               LOG_DEBUG("PCP expecting next root packet in %ds",time);
+                       }else
+                       {
+                               nextRootPacket = 0;
+                       }
+
+               }else if (id == PCP_ROOT_UPDATE)
+               {
+                       atom.skip(c,d);
+
+                       chanMgr->broadcastTrackerUpdate(remoteID,true);
+
+               }else if ((id == PCP_MESG_ASCII) || (id == PCP_MESG))                   // PCP_MESG_ASCII to be depreciated 
+               {
+                       String newMsg;
+
+                       atom.readString(newMsg.data,sizeof(newMsg.data),d);
+                       if (!newMsg.isSame(servMgr->rootMsg.cstr()))
+                       {
+                               servMgr->rootMsg = newMsg;
+                               LOG_DEBUG("PCP got new root mesg: %s",servMgr->rootMsg.cstr());
+                               peercastApp->notifyMessage(ServMgr::NT_PEERCAST,servMgr->rootMsg.cstr());
+                       }
+               }else
+               {
+                       LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d);
+                       atom.skip(c,d);
+               }
+       }
+}
+
+// ------------------------------------------
+void PCPStream::readPktAtoms(Channel *ch,AtomStream &atom,int numc,BroadcastState &bcs)
+{
+       ChanPacket pack;
+       ID4 type;
+
+
+       for(int i=0; i<numc; i++)
+       {
+               int c,d;
+               ID4 id = atom.read(c,d);
+
+               if (id == PCP_CHAN_PKT_TYPE)
+               {
+                       type = atom.readID4();
+
+                       if (type == PCP_CHAN_PKT_HEAD)
+                               pack.type = ChanPacket::T_HEAD;
+                       else if (type == PCP_CHAN_PKT_DATA)
+                               pack.type = ChanPacket::T_DATA;
+                       else
+                               pack.type = ChanPacket::T_UNKNOWN;
+
+               }else if (id == PCP_CHAN_PKT_POS)
+               {
+                       pack.pos = atom.readInt();
+
+
+               }else if (id == PCP_CHAN_PKT_DATA)
+               {
+                       pack.len = d;
+                       atom.readBytes(pack.data,pack.len);
+               }
+               else
+               {
+                       LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d);
+                       atom.skip(c,d);
+               }
+       }
+
+       if (ch)
+       {
+
+               int diff = pack.pos - ch->streamPos;
+               if (diff)
+               {
+                       LOG_DEBUG("PCP skipping %s%8d (%10d -> %10d) count=%2d",(diff>0)?"+":"",diff,ch->streamPos,pack.pos, ch->skipCount);
+                       if (ch->lastSkipTime + 120 < sys->getTime()){
+                               ch->skipCount = 0;
+                       }
+                       ch->lastSkipTime = sys->getTime();
+                       ch->skipCount++; //JP-EX
+                       pack.skip = true;
+               }
+
+               if (servMgr->autoBumpSkipCount) //JP-EX
+               {
+                       if (ch->skipCount > servMgr->autoBumpSkipCount)
+                       {
+                               LOG_DEBUG("Auto bump");
+                               ch->bump = true;
+                       }
+               }
+
+               if (pack.type == ChanPacket::T_HEAD)
+               {
+                       LOG_DEBUG("New head packet at %d",pack.pos);
+                       bool renewhead;
+                       if (servMgr->keepDownstreams)
+                               renewhead = (memcmp(ch->headPack.data, pack.data, pack.len) != 0);
+                       else
+                               renewhead = true;
+
+                       /*
+                       // check for stream restart
+                       if (pack.pos == 0)              
+                       {
+                               LOG_CHANNEL("PCP resetting stream");
+                               ch->streamIndex++;
+                               ch->rawData.init();
+                       }
+                       */
+                       if (renewhead || ch->lastStopTime + 30 < sys->getTime()) {
+                               // check for stream restart
+                               if (pack.pos == 0)
+                               {
+                                       LOG_CHANNEL("PCP resetting stream");
+                                       ch->streamIndex++;
+                                       ch->rawData.init();
+                               }
+
+                               ch->headPack = pack;
+
+                               ch->rawData.writePacket(pack,true);
+                               ch->streamPos = pack.pos+pack.len;
+                       }
+
+               }else if (pack.type == ChanPacket::T_DATA)
+               {
+                       ch->rawData.writePacket(pack,true);
+                       ch->streamPos = pack.pos+pack.len;
+               }
+
+       }
+
+       // update this parent packet stream position
+       if ((pack.pos) && (!bcs.streamPos || (pack.pos < bcs.streamPos)))
+               bcs.streamPos = pack.pos;
+
+}
+// -----------------------------------
+void PCPStream::readHostAtoms(AtomStream &atom, int numc, BroadcastState &bcs, ChanHit &hit, bool flg)
+{
+//     ChanHit hit;
+       hit.init();
+       GnuID chanID = bcs.chanID;      //use default
+
+       bool busy=false;
+
+       unsigned int ipNum=0;
+
+       for(int i=0; i<numc; i++)
+       {
+               int c,d;
+               ID4 id = atom.read(c,d);
+
+               if (id == PCP_HOST_IP)
+               {
+                       unsigned int ip = atom.readInt();
+                       hit.rhost[ipNum].ip = ip;
+               }else if (id == PCP_HOST_PORT)
+               {
+                       int port = atom.readShort();
+                       hit.rhost[ipNum++].port = port;
+
+                       if (ipNum > 1)
+                               ipNum = 1;
+               }
+               else if (id == PCP_HOST_NUML)
+                       hit.numListeners = atom.readInt();
+               else if (id == PCP_HOST_NUMR)
+                       hit.numRelays = atom.readInt();
+               else if (id == PCP_HOST_UPTIME)
+                       hit.upTime = atom.readInt();
+               else if (id == PCP_HOST_OLDPOS)
+                       hit.oldestPos = atom.readInt();
+               else if (id == PCP_HOST_NEWPOS)
+                       hit.newestPos = atom.readInt();
+               else if (id == PCP_HOST_VERSION)
+                       hit.version = atom.readInt();
+               else if (id == PCP_HOST_VERSION_VP)
+                       hit.version_vp = atom.readInt();
+               else if (id == PCP_HOST_VERSION_EX_PREFIX)
+                       atom.readBytes(hit.version_ex_prefix,2);
+               else if (id == PCP_HOST_VERSION_EX_NUMBER){
+                       hit.version_ex_number = atom.readShort();
+               }
+               else if (id == PCP_HOST_FLAGS1)
+               {
+                       int fl1 = atom.readChar();
+
+                       hit.recv = (fl1 & PCP_HOST_FLAGS1_RECV) !=0;
+                       hit.relay = (fl1 & PCP_HOST_FLAGS1_RELAY) !=0;
+                       hit.direct = (fl1 & PCP_HOST_FLAGS1_DIRECT) !=0;
+                       hit.cin = (fl1 & PCP_HOST_FLAGS1_CIN) !=0;
+                       hit.tracker = (fl1 & PCP_HOST_FLAGS1_TRACKER) !=0;
+                       hit.firewalled = (fl1 & PCP_HOST_FLAGS1_PUSH) !=0;
+
+
+               }else if (id == PCP_HOST_ID)
+                       atom.readBytes(hit.sessionID.id,16);
+               else if (id == PCP_HOST_CHANID)
+                       atom.readBytes(chanID.id,16);
+               else if (id == PCP_HOST_UPHOST_IP)
+                       hit.uphost.ip = atom.readInt();
+               else if (id == PCP_HOST_UPHOST_PORT)
+                       hit.uphost.port = atom.readInt();
+               else if (id == PCP_HOST_UPHOST_HOPS)
+                       hit.uphostHops = atom.readInt();
+               else
+               {
+                       LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d);
+                       atom.skip(c,d);
+               }
+       }
+
+       hit.host = hit.rhost[0];
+       hit.chanID = chanID;
+
+       hit.numHops = bcs.numHops;
+
+       hit.servent_id = bcs.servent_id;
+
+       if (flg){
+//             LOG_DEBUG("readHostAtoms HITLISTLOCK ON-------------");
+               chanMgr->hitlistlock.on();
+               if (hit.recv)
+                       chanMgr->addHit(hit);
+               else
+                       chanMgr->delHit(hit);
+//             LOG_DEBUG("readHostAtoms HITLISTLOCK OFF-------------");
+               chanMgr->hitlistlock.off();
+       }
+
+       if (hit.numHops == 1){
+               Servent *sv = servMgr->findServentByServentID(hit.servent_id);
+               if (sv){
+//                     LOG_DEBUG("set servent's waitPort = %d", hit.host.port);
+                       sv->waitPort = hit.host.port;
+               }
+       }
+}
+
+// ------------------------------------------
+void PCPStream::readChanAtoms(AtomStream &atom,int numc,BroadcastState &bcs)
+{
+/*     Channel *ch=NULL;
+       ChanHitList *chl=NULL;
+       ChanInfo newInfo;
+
+       ch = chanMgr->findChannelByID(bcs.chanID);
+       chl = chanMgr->findHitListByID(bcs.chanID);
+
+       if (ch)
+               newInfo = ch->info;
+       else if (chl)
+               newInfo = chl->info;*/
+
+       Channel *ch=NULL;
+       ChanHitList *chl=NULL;
+       ChanInfo newInfo, chaInfo;
+
+       ch = this->parent;
+       if (ch){
+               newInfo = ch->info;
+               chaInfo = ch->info;
+       }
+
+       for(int i=0; i<numc; i++)
+       {
+
+               int c,d;
+               ID4 id = atom.read(c,d);
+
+               if ((id == PCP_CHAN_PKT) && (ch))
+               {
+                       readPktAtoms(ch,atom,c,bcs);
+               }else if (id == PCP_CHAN_INFO)
+               {
+                       newInfo.readInfoAtoms(atom,c);
+
+               }else if (id == PCP_CHAN_TRACK)
+               {
+                       newInfo.readTrackAtoms(atom,c);
+
+               }else if (id == PCP_CHAN_BCID)
+               {
+                       atom.readBytes(newInfo.bcID.id,16);
+
+               }else if (id == PCP_CHAN_KEY)                   // depreciated
+               {
+                       atom.readBytes(newInfo.bcID.id,16);
+                       newInfo.bcID.id[0] = 0;                         // clear flags
+
+               }else if (id == PCP_CHAN_ID)
+               {
+                       atom.readBytes(newInfo.id.id,16);
+
+                       ch = chanMgr->findChannelByID(newInfo.id);
+                       chl = chanMgr->findHitListByID(newInfo.id);
+
+               }else
+               {
+                       LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d);
+                       atom.skip(c,d);
+               }
+       }
+
+       chl = chanMgr->findHitList(newInfo);
+
+       if (!chl)
+               chl = chanMgr->addHitList(newInfo);
+
+       if (chl)
+       {
+               chl->info.update(newInfo);
+       
+               if (!servMgr->chanLog.isEmpty())
+               {
+                       //if (chl->numListeners())
+                       {
+                               try
+                               {
+                                       FileStream file;
+                                       file.openWriteAppend(servMgr->chanLog.cstr());
+
+                                       XML::Node *rn = new XML::Node("update time=\"%d\"",sys->getTime());
+                                               XML::Node *n = chl->info.createChannelXML();
+                                       n->add(chl->createXML(false));
+                                       n->add(chl->info.createTrackXML());
+                                       rn->add(n);     
+       
+                                       rn->write(file,0);
+                                       delete rn;
+                                       file.close();
+                               }catch(StreamException &e)
+                               {
+                                       LOG_ERROR("Unable to update channel log: %s",e.msg);
+                               }
+                       }
+               }
+
+       }
+
+       if (ch && !ch->isBroadcasting())
+               ch->updateInfo(newInfo);
+
+
+}
+// ------------------------------------------
+int PCPStream::readBroadcastAtoms(AtomStream &atom,int numc,BroadcastState &bcs)
+{
+       ChanPacket pack;
+       int ttl=0;              
+       int ver=0;
+       int ver_vp=0;
+       GnuID fromID,destID;
+       int r=0;
+       char ver_ex_prefix[2];
+       int ver_ex_number = 0;
+
+       fromID.clear();
+       destID.clear();
+
+       bcs.initPacketSettings();
+
+       MemoryStream pmem(pack.data,sizeof(pack.data));
+       AtomStream patom(pmem);
+
+       patom.writeParent(PCP_BCST,numc);
+
+       for(int i=0; i<numc; i++)
+       {
+               int c,d;
+               ID4 id = atom.read(c,d);
+               
+               if (id == PCP_BCST_TTL)
+               {
+                       ttl = atom.readChar()-1;
+                       patom.writeChar(id,ttl);
+
+               }else if (id == PCP_BCST_HOPS)
+               {
+                       bcs.numHops = atom.readChar()+1;
+                       patom.writeChar(id,bcs.numHops);
+
+               }else if (id == PCP_BCST_FROM)
+               {
+                       atom.readBytes(fromID.id,16);
+                       patom.writeBytes(id,fromID.id,16);
+
+                       routeList.add(fromID);
+               }else if (id == PCP_BCST_GROUP)
+               {
+                       bcs.group = atom.readChar();
+                       patom.writeChar(id,bcs.group);
+               }else if (id == PCP_BCST_DEST)
+               {
+                       atom.readBytes(destID.id,16);
+                       patom.writeBytes(id,destID.id,16);
+                       bcs.forMe = destID.isSame(servMgr->sessionID);
+
+                       char idstr1[64];
+                       char idstr2[64];
+
+                       destID.toStr(idstr1);
+                       servMgr->sessionID.toStr(idstr2);
+
+               }else if (id == PCP_BCST_CHANID)
+               {
+                       atom.readBytes(bcs.chanID.id,16);
+                       patom.writeBytes(id,bcs.chanID.id,16);
+               }else if (id == PCP_BCST_VERSION)
+               {
+                       ver = atom.readInt();
+                       patom.writeInt(id,ver);
+               }else if (id == PCP_BCST_VERSION_VP)
+               {
+                       ver_vp = atom.readInt();
+                       patom.writeInt(id,ver_vp);
+               }else if (id == PCP_BCST_VERSION_EX_PREFIX)
+               {
+                       atom.readBytes(ver_ex_prefix,2);
+                       patom.writeBytes(id,ver_ex_prefix,2);
+               }else if (id == PCP_BCST_VERSION_EX_NUMBER)
+               {
+                       ver_ex_number = atom.readShort();
+                       patom.writeShort(id,ver_ex_number);
+               }else if (id == PCP_HOST)
+               {
+                       ChanHit hit;
+                       readHostAtoms(atom,c,bcs,hit,false);
+                       if (hit.uphost.ip == 0){
+//                             LOG_DEBUG("bcs servent_id = %d", bcs.servent_id);
+                               if (bcs.numHops == 1){
+                                       hit.uphost.ip = servMgr->serverHost.ip;
+                                       hit.uphost.port = servMgr->serverHost.port;
+                                       hit.uphostHops = 1;
+                               } else {
+                                       Servent *sv = servMgr->findServentByServentID(bcs.servent_id);
+                                       if (sv){
+                                               hit.uphost.ip = sv->getHost().ip;
+                                               hit.uphost.port = sv->waitPort;
+                                               hit.uphostHops = bcs.numHops - 1;
+                                       }
+                               }
+                       }
+                       int oldPos = pmem.pos;
+                       hit.writeAtoms(patom, hit.chanID);
+                       pmem.pos = oldPos;
+                       r = readAtom(patom,bcs);
+               } else {
+                       // copy and process atoms
+                       int oldPos = pmem.pos;
+                       patom.writeAtoms(id,atom.io,c,d);
+                       pmem.pos = oldPos;
+                       r = readAtom(patom,bcs);
+               }
+       }
+
+       char fromStr[64];
+       fromStr[0] = 0;
+       if (fromID.isSet())
+               fromID.toStr(fromStr);
+       char destStr[64];
+       destStr[0] = 0;
+       if (destID.isSet())
+               destID.toStr(destStr);
+       char tmp[64];
+       bcs.chanID.toStr(tmp);
+
+//     LOG_DEBUG(tmp);
+
+       if (ver_ex_number){
+               LOG_DEBUG("PCP bcst: group=%d, hops=%d, ver=%d(%c%c%04d), from=%s, dest=%s ttl=%d",
+                       bcs.group,bcs.numHops,ver,ver_ex_prefix[0],ver_ex_prefix[1],ver_ex_number,fromStr,destStr,ttl);
+       } else if (ver_vp){
+               LOG_DEBUG("PCP bcst: group=%d, hops=%d, ver=%d(VP%04d), from=%s, dest=%s ttl=%d",bcs.group,bcs.numHops,ver,ver_vp,fromStr,destStr,ttl);
+       } else {
+               LOG_DEBUG("PCP bcst: group=%d, hops=%d, ver=%d, from=%s, dest=%s ttl=%d",bcs.group,bcs.numHops,ver,fromStr,destStr,ttl);
+       }
+
+       if (fromID.isSet())
+               if (fromID.isSame(servMgr->sessionID))
+               {
+                       LOG_ERROR("BCST loopback"); 
+                       return PCP_ERROR_BCST+PCP_ERROR_LOOPBACK;
+               }
+
+       // broadcast back out if ttl > 0 
+       if ((ttl>0) && (!bcs.forMe))
+       {
+               pack.len = pmem.pos;
+               pack.type = ChanPacket::T_PCP;
+
+               if (bcs.group & (/*PCP_BCST_GROUP_ROOT|*/PCP_BCST_GROUP_TRACKERS|PCP_BCST_GROUP_RELAYS))
+               {
+                       chanMgr->broadcastPacketUp(pack,bcs.chanID,remoteID,destID);
+               }
+
+               if (bcs.group & (/*PCP_BCST_GROUP_ROOT|*/PCP_BCST_GROUP_TRACKERS|PCP_BCST_GROUP_RELAYS))
+               {
+                       servMgr->broadcastPacket(pack,bcs.chanID,remoteID,destID,Servent::T_COUT);
+               }
+
+               if (bcs.group & (PCP_BCST_GROUP_RELAYS|PCP_BCST_GROUP_TRACKERS))
+               {
+                       servMgr->broadcastPacket(pack,bcs.chanID,remoteID,destID,Servent::T_CIN);
+               }
+
+               if (bcs.group & (PCP_BCST_GROUP_RELAYS))
+               {
+                       servMgr->broadcastPacket(pack,bcs.chanID,remoteID,destID,Servent::T_RELAY);
+               }
+
+
+//             LOG_DEBUG("ttl=%d",ttl);
+
+       } else {
+//             LOG_DEBUG("ttl=%d",ttl);
+       }
+       return r;
+}
+
+
+// ------------------------------------------
+int PCPStream::procAtom(AtomStream &atom,ID4 id,int numc, int dlen,BroadcastState &bcs)
+{
+       int r=0;
+       ChanHit hit;
+       int rBan = 0;
+
+       if (id == PCP_CHAN)
+       {
+               readChanAtoms(atom,numc,bcs);
+       }else if (id == PCP_ROOT)
+       {
+               if (servMgr->isRoot)
+                       throw StreamException("Unauthorized root message");                             
+               else
+                       readRootAtoms(atom,numc,bcs);
+
+       }else if (id == PCP_HOST)
+       {
+               readHostAtoms(atom,numc,bcs,hit);
+               Channel *ch = chanMgr->findChannelByID(hit.chanID);
+               if (ch && (ch->isBroadcasting() || servMgr->vpDebug)){
+                       if (servMgr->autoPort0Kick && (hit.numHops == 1) && (hit.firewalled || (!hit.relay && !hit.numRelays))){
+                               char tmp[32];
+                               hit.host.IPtoStr(tmp);
+                               LOG_DEBUG("host that can't relay is disconnect: %s", tmp);
+                               rBan = PCP_ERROR_BANNED;
+                       }
+                       if (servMgr->allowOnlyVP && (hit.numHops == 1) && !hit.version_vp){
+                               char tmp[32];
+                               hit.host.IPtoStr(tmp);
+                               LOG_DEBUG("host that is not VP is disconnect: %s", tmp);
+                               rBan = PCP_ERROR_BANNED;
+                       }
+               }
+
+       }else if ((id == PCP_MESG_ASCII) || (id == PCP_MESG))           // PCP_MESG_ASCII to be depreciated
+       {
+               String msg;
+               atom.readString(msg.data,sizeof(msg.data),dlen);
+               LOG_DEBUG("PCP got text: %s",msg.cstr());
+       }else if (id == PCP_BCST)
+       {
+               r = readBroadcastAtoms(atom,numc,bcs);
+       }else if (id == PCP_HELO)
+       {
+               atom.skip(numc,dlen);
+               atom.writeParent(PCP_OLEH,1);
+                       atom.writeBytes(PCP_HELO_SESSIONID,servMgr->sessionID.id,16);
+       }else if (id == PCP_PUSH)
+       {
+
+               readPushAtoms(atom,numc,bcs);
+       }else if (id == PCP_OK)
+       {
+               atom.readInt();
+
+       }else if (id == PCP_QUIT)
+       {
+               r = atom.readInt();
+               if (!r)
+                       r = PCP_ERROR_QUIT;
+
+       }else if (id == PCP_ATOM)
+       {
+               for(int i=0; i<numc; i++)
+               {
+                       int nc,nd;
+                       ID4 aid = atom.read(nc,nd);
+                       int ar = procAtom(atom,aid,nc,nd,bcs);
+                       if (ar)
+                               r = ar;
+               }
+
+       }else
+       {
+               LOG_CHANNEL("PCP skip: %s",id.getString().str());
+               atom.skip(numc,dlen);
+       }
+
+       if (!r)
+               r = rBan;
+
+       return r;
+
+}
+
+// ------------------------------------------
+int PCPStream::readAtom(AtomStream &atom,BroadcastState &bcs)
+{
+       int numc,dlen;
+       ID4 id = atom.read(numc,dlen);
+
+       return  procAtom(atom,id,numc,dlen,bcs);
+}
+
+
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/pcp.h b/c:/Git/PeerCast.root/PeerCast/core/common/pcp.h
new file mode 100644 (file)
index 0000000..4085941
--- /dev/null
@@ -0,0 +1,268 @@
+// ------------------------------------------------
+// File : pcp.h
+// Date: 1-mar-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _PCP_H
+#define _PCP_H
+
+// ------------------------------------------------
+
+
+#include "id.h"
+#include "cstream.h"
+#include "channel.h"
+
+// ------------------------------------------------
+
+class Servent;
+
+
+// ------------------------------------------------
+
+static const ID4 PCP_CONNECT           = "pcp\n";
+
+static const ID4 PCP_OK                                = "ok";
+
+static const ID4 PCP_HELO                      = "helo";
+static const ID4 PCP_HELO_AGENT                = "agnt";
+static const ID4 PCP_HELO_OSTYPE       = "ostp";
+static const ID4 PCP_HELO_SESSIONID    = "sid";
+static const ID4 PCP_HELO_PORT         = "port";
+static const ID4 PCP_HELO_PING         = "ping";
+static const ID4 PCP_HELO_PONG         = "pong";
+static const ID4 PCP_HELO_REMOTEIP     = "rip";
+static const ID4 PCP_HELO_VERSION      = "ver";
+static const ID4 PCP_HELO_BCID         = "bcid";
+static const ID4 PCP_HELO_DISABLE      = "dis";
+
+static const ID4 PCP_OLEH                      = "oleh";
+
+static const ID4 PCP_MODE                      = "mode";
+static const ID4 PCP_MODE_GNUT06       = "gn06";
+
+static const ID4 PCP_ROOT                      = "root";
+static const ID4 PCP_ROOT_UPDINT       = "uint";
+static const ID4 PCP_ROOT_CHECKVER     = "chkv";
+static const ID4 PCP_ROOT_URL          = "url";
+static const ID4 PCP_ROOT_UPDATE       = "upd";
+static const ID4 PCP_ROOT_NEXT         = "next";
+
+
+static const ID4 PCP_OS_LINUX          = "lnux";
+static const ID4 PCP_OS_WINDOWS                = "w32";
+static const ID4 PCP_OS_OSX                    = "osx";
+static const ID4 PCP_OS_WINAMP         = "wamp";
+static const ID4 PCP_OS_ZAURUS         = "zaur";
+
+static const ID4 PCP_GET                       = "get";
+static const ID4 PCP_GET_ID                    = "id";
+static const ID4 PCP_GET_NAME          = "name";
+
+static const ID4 PCP_HOST                      = "host";
+static const ID4 PCP_HOST_ID           = "id";
+static const ID4 PCP_HOST_IP           = "ip";
+static const ID4 PCP_HOST_PORT         = "port";
+static const ID4 PCP_HOST_NUML         = "numl";
+static const ID4 PCP_HOST_NUMR         = "numr";
+static const ID4 PCP_HOST_UPTIME       = "uptm";
+static const ID4 PCP_HOST_TRACKER      = "trkr";
+static const ID4 PCP_HOST_CHANID       = "cid";
+static const ID4 PCP_HOST_VERSION      = "ver";
+static const ID4 PCP_HOST_VERSION_VP   = "vevp";
+static const ID4 PCP_HOST_VERSION_EX_PREFIX = "vexp";
+static const ID4 PCP_HOST_VERSION_EX_NUMBER = "vexn";
+static const ID4 PCP_HOST_FLAGS1       = "flg1";
+static const ID4 PCP_HOST_OLDPOS       = "oldp";
+static const ID4 PCP_HOST_NEWPOS       = "newp";
+static const ID4 PCP_HOST_UPHOST_IP    = "upip";
+static const ID4 PCP_HOST_UPHOST_PORT  = "uppt";
+static const ID4 PCP_HOST_UPHOST_HOPS  = "uphp";
+
+static const ID4 PCP_QUIT                      = "quit";
+
+static const ID4 PCP_CHAN                      = "chan";
+static const ID4 PCP_CHAN_ID           = "id";
+static const ID4 PCP_CHAN_BCID         = "bcid";
+static const ID4 PCP_CHAN_KEY          = "key";
+
+static const ID4 PCP_CHAN_PKT          = "pkt";
+static const ID4 PCP_CHAN_PKT_TYPE     = "type";
+static const ID4 PCP_CHAN_PKT_POS      = "pos";
+static const ID4 PCP_CHAN_PKT_HEAD     = "head";
+static const ID4 PCP_CHAN_PKT_DATA     = "data";
+static const ID4 PCP_CHAN_PKT_META     = "meta";
+
+static const ID4 PCP_CHAN_INFO                 = "info";
+static const ID4 PCP_CHAN_INFO_TYPE            = "type";
+static const ID4 PCP_CHAN_INFO_BITRATE = "bitr";
+static const ID4 PCP_CHAN_INFO_GENRE   = "gnre";
+static const ID4 PCP_CHAN_INFO_NAME            = "name";
+static const ID4 PCP_CHAN_INFO_URL             = "url";
+static const ID4 PCP_CHAN_INFO_DESC            = "desc";
+static const ID4 PCP_CHAN_INFO_COMMENT = "cmnt";
+
+static const ID4 PCP_CHAN_TRACK                        = "trck";
+static const ID4 PCP_CHAN_TRACK_TITLE  = "titl";
+static const ID4 PCP_CHAN_TRACK_CREATOR        = "crea";
+static const ID4 PCP_CHAN_TRACK_URL            = "url";
+static const ID4 PCP_CHAN_TRACK_ALBUM  = "albm";
+
+static const ID4 PCP_MESG                              = "mesg";
+static const ID4 PCP_MESG_ASCII                        = "asci";               // ascii/sjis to be depreciated.. utf8/unicode is the only supported format from now.
+static const ID4 PCP_MESG_SJIS                 = "sjis";
+
+static const ID4 PCP_BCST                              = "bcst";       
+static const ID4 PCP_BCST_TTL                  = "ttl";        
+static const ID4 PCP_BCST_HOPS                 = "hops";       
+static const ID4 PCP_BCST_FROM                 = "from";       
+static const ID4 PCP_BCST_DEST                 = "dest";       
+static const ID4 PCP_BCST_GROUP                        = "grp";        
+static const ID4 PCP_BCST_CHANID               = "cid";        
+static const ID4 PCP_BCST_VERSION              = "vers";
+static const ID4 PCP_BCST_VERSION_VP   = "vrvp";
+static const ID4 PCP_BCST_VERSION_EX_PREFIX = "vexp";
+static const ID4 PCP_BCST_VERSION_EX_NUMBER = "vexn";
+
+static const ID4 PCP_PUSH                              = "push";       
+static const ID4 PCP_PUSH_IP                   = "ip"; 
+static const ID4 PCP_PUSH_PORT                 = "port";       
+static const ID4 PCP_PUSH_CHANID               = "cid";        
+
+static const ID4 PCP_SPKT                              = "spkt";
+
+static const ID4 PCP_ATOM                              = "atom";       
+
+static const ID4 PCP_SESSIONID                 = "sid";
+
+static const int PCP_BCST_GROUP_ALL                    = (char)0xff;   
+static const int PCP_BCST_GROUP_ROOT           = 1;    
+static const int PCP_BCST_GROUP_TRACKERS       = 2;    
+static const int PCP_BCST_GROUP_RELAYS         = 4;    
+
+
+static const int PCP_ERROR_QUIT                        = 1000;
+static const int PCP_ERROR_BCST                        = 2000;
+static const int PCP_ERROR_READ                        = 3000;
+static const int PCP_ERROR_WRITE               = 4000;
+static const int PCP_ERROR_GENERAL             = 5000;
+
+static const int PCP_ERROR_SKIP                                = 1;
+static const int PCP_ERROR_ALREADYCONNECTED    = 2;
+static const int PCP_ERROR_UNAVAILABLE         = 3;
+static const int PCP_ERROR_LOOPBACK                    = 4;
+static const int PCP_ERROR_NOTIDENTIFIED       = 5;
+static const int PCP_ERROR_BADRESPONSE         = 6;
+static const int PCP_ERROR_BADAGENT                    = 7;
+static const int PCP_ERROR_OFFAIR                      = 8;
+static const int PCP_ERROR_SHUTDOWN                    = 9;
+static const int PCP_ERROR_NOROOT                      = 10;
+static const int PCP_ERROR_BANNED                      = 11;
+
+static const int PCP_HOST_FLAGS1_TRACKER       = 0x01;
+static const int PCP_HOST_FLAGS1_RELAY         = 0x02;
+static const int PCP_HOST_FLAGS1_DIRECT                = 0x04;
+static const int PCP_HOST_FLAGS1_PUSH          = 0x08;
+static const int PCP_HOST_FLAGS1_RECV          = 0x10;
+static const int PCP_HOST_FLAGS1_CIN           = 0x20;
+static const int PCP_HOST_FLAGS1_PRIVATE       = 0x40;
+
+
+// ----------------------------------------------
+class BroadcastState 
+{
+public:
+       BroadcastState()
+       :numHops(0)
+       ,forMe(false) 
+       ,streamPos(0)
+       ,group(0)
+       ,servent_id(0)
+       {
+               chanID.clear();
+               bcID.clear();
+       }
+
+
+       void initPacketSettings()
+       {
+               forMe = false;
+               group = 0;
+               numHops = 0;
+               bcID.clear();
+               chanID.clear();
+       }
+
+
+       GnuID chanID,bcID;
+       int numHops;
+       bool forMe;
+       unsigned int streamPos;
+       int group;
+       int servent_id;
+};
+
+// ----------------------------------------------
+class PCPStream : public ChannelStream
+{
+public:
+       PCPStream(GnuID &rid) 
+       :routeList(1000)
+       {
+               init(rid);
+       }
+
+       void    init(GnuID &);
+
+       virtual void kill()
+       {
+               inData.lock.on();
+               outData.lock.on();
+       }
+
+       virtual bool sendPacket(ChanPacket &,GnuID &);
+       virtual void flush(Stream &);
+       virtual void readHeader(Stream &,Channel *);
+       virtual int readPacket(Stream &,Channel *);
+       virtual void readEnd(Stream &,Channel *);
+
+       int             readPacket(Stream &,BroadcastState &);
+       void    flushOutput(Stream &in,BroadcastState &);
+       static void     readVersion(Stream &);
+
+       int             procAtom(AtomStream &,ID4,int,int,BroadcastState &);
+       int             readAtom(AtomStream &,BroadcastState &);
+       void    readChanAtoms(AtomStream &,int,BroadcastState &);
+//     void    readHostAtoms(AtomStream &, int, BroadcastState &);
+       void    readHostAtoms(AtomStream &, int, BroadcastState &, ChanHit &, bool flg=true);
+       void    readPushAtoms(AtomStream &, int,BroadcastState &);
+
+       void    readPktAtoms(Channel *,AtomStream &,int,BroadcastState &);
+       void    readRootAtoms(AtomStream &, int,BroadcastState &);
+
+       int             readBroadcastAtoms(AtomStream &,int,BroadcastState &);
+
+       ChanPacketBuffer inData,outData;
+       unsigned int lastPacketTime;
+       unsigned int nextRootPacket;    
+
+       //int   error;
+       GnuIDList       routeList;
+       GnuID   remoteID;
+
+};
+
+#endif
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/peercast.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/peercast.cpp
new file mode 100644 (file)
index 0000000..9560fa8
--- /dev/null
@@ -0,0 +1,242 @@
+#include "sys.h"
+#include "peercast.h"
+#include "channel.h"
+#include "servmgr.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+
+// ---------------------------------
+// globals
+
+Sys *sys=NULL;
+ChanMgr *chanMgr;
+ServMgr *servMgr;
+
+PeercastInstance *peercastInst=NULL;
+PeercastApplication *peercastApp=NULL;
+
+
+// ---------------------------------
+void APICALL PeercastInstance::init()
+{
+       sys = createSys();
+       servMgr = new ServMgr();
+       chanMgr = new ChanMgr();
+
+       if (peercastApp->getIniFilename())
+               servMgr->loadSettings(peercastApp->getIniFilename());
+
+       servMgr->start();
+}
+// --------------------------------------------------
+void   APICALL PeercastInstance::setNotifyMask(int mask)
+{
+       if (servMgr)
+               servMgr->notifyMask = mask;
+}
+// --------------------------------------------------
+int            APICALL PeercastInstance::getNotifyMask()
+{
+       if (servMgr)
+               return servMgr->notifyMask;
+       else    
+               return 0;
+}
+
+// --------------------------------------------------
+void   APICALL PeercastInstance::setAutoConnect(bool on)
+{
+       if (servMgr)
+               servMgr->autoConnect = on;
+}
+// --------------------------------------------------
+bool   APICALL PeercastInstance::getAutoConnect()
+{
+       if (servMgr)
+               return servMgr->autoConnect;
+       else
+               return false;
+}
+// --------------------------------------------------
+void   APICALL PeercastInstance::setMaxOutput(int kbps)
+{
+       if (servMgr)
+               servMgr->maxBitrateOut = kbps;
+}
+// --------------------------------------------------
+int            APICALL PeercastInstance::getMaxOutput()
+{
+       if (servMgr)
+               return servMgr->maxBitrateOut;
+       else
+               return 0;
+}
+// --------------------------------------------------
+void   APICALL PeercastInstance::setMaxRelays(int max)
+{
+       if (servMgr)
+               servMgr->setMaxRelays(max);
+}
+// --------------------------------------------------
+int            APICALL PeercastInstance::getMaxRelays()
+{
+       if (servMgr)
+               return servMgr->maxRelays;
+       else
+               return 0;
+}
+// --------------------------------------------------
+void   APICALL PeercastInstance::setActive(bool on)
+{
+       if (servMgr)
+       {
+               servMgr->autoConnect = on;
+               servMgr->autoServe = on;
+       }
+}
+// --------------------------------------------------
+bool   APICALL PeercastInstance::getActive()
+{
+       if (servMgr)
+               return servMgr->autoConnect&&servMgr->autoServe;
+       else
+               return false;
+}
+// --------------------------------------------------
+void   APICALL PeercastInstance::saveSettings()
+{
+       if (servMgr)
+               servMgr->saveSettings(peercastApp->getIniFilename());
+}
+// --------------------------------------------------
+void   APICALL PeercastInstance::quit()
+{
+       isQuitting = true;
+       if (chanMgr)
+               chanMgr->quit();
+       if (servMgr)
+               servMgr->quit();
+}
+// --------------------------------------------------
+void   APICALL PeercastInstance::setServerPort(int port)
+{
+       if (servMgr)
+       {
+               servMgr->serverHost.port = port;
+               servMgr->restartServer = true;
+       }
+}
+// --------------------------------------------------
+int            APICALL PeercastInstance::getServerPort()
+{
+       if (servMgr)
+               return servMgr->serverHost.port;
+       else
+               return 0;
+}
+// --------------------------------------------------
+void   APICALL PeercastInstance::setServerPassword(const char *pwd)
+{
+       if (servMgr)
+               strcpy(servMgr->password,pwd);
+}
+// --------------------------------------------------
+const char *APICALL    PeercastInstance::getServerPassword()
+{
+       return servMgr->password;
+}
+// --------------------------------------------------
+void   APICALL PeercastInstance::callLocalURL(const char *url)
+{
+       if (sys && servMgr)
+               sys->callLocalURL(url,servMgr->serverHost.port);
+}
+
+
+// --------------------------------------------------
+void ADDLOG(const char *fmt,va_list ap,LogBuffer::TYPE type)
+{
+       if(sys)
+       {
+               const int MAX_LINELEN = 1024;
+
+               char str[MAX_LINELEN+1];
+               vsnprintf(str,MAX_LINELEN-1,fmt,ap);
+               str[MAX_LINELEN-1]=0;
+
+               if (type != LogBuffer::T_NONE)
+                       sys->logBuf->write(str,type);
+
+               peercastApp->printLog(type,str);
+       }
+}
+// --------------------------------------------------
+void LOG(const char *fmt,...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       ADDLOG(fmt,ap,LogBuffer::T_DEBUG);
+       va_end(ap);     
+}
+
+// --------------------------------------------------
+void LOG_ERROR(const char *fmt,...)
+{
+       if (servMgr)
+       {
+               if ((servMgr->showLog & (1<<LogBuffer::T_ERROR)) && (!servMgr->pauseLog))
+               {
+                       va_list ap;
+                       va_start(ap, fmt);
+                       ADDLOG(fmt,ap,LogBuffer::T_ERROR);
+                       va_end(ap);     
+               }
+       }
+}
+// --------------------------------------------------
+void LOG_DEBUG(const char *fmt,...)
+{
+       if (servMgr)
+       {
+               if ((servMgr->showLog & (1<<LogBuffer::T_DEBUG)) && (!servMgr->pauseLog))
+               {
+                       va_list ap;
+                       va_start(ap, fmt);
+                       ADDLOG(fmt,ap,LogBuffer::T_DEBUG);
+                       va_end(ap);     
+               }
+       }
+}
+// --------------------------------------------------
+void LOG_NETWORK(const char *fmt,...)
+{
+       if (servMgr)
+       {
+               if ((servMgr->showLog & (1<<LogBuffer::T_NETWORK)) && (!servMgr->pauseLog))
+               {
+                       va_list ap;
+                       va_start(ap, fmt);
+                       ADDLOG(fmt,ap,LogBuffer::T_NETWORK);
+                       va_end(ap);     
+               }
+       }
+}
+// --------------------------------------------------
+void LOG_CHANNEL(const char *fmt,...)
+{
+       if (servMgr)
+       {
+               if ((servMgr->showLog & (1<<LogBuffer::T_CHANNEL)) && (!servMgr->pauseLog))
+               {
+                       va_list ap;
+                       va_start(ap, fmt);
+                       ADDLOG(fmt,ap,LogBuffer::T_CHANNEL);
+                       va_end(ap);     
+               }
+       }
+}
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/peercast.h b/c:/Git/PeerCast.root/PeerCast/core/common/peercast.h
new file mode 100644 (file)
index 0000000..ef8732b
--- /dev/null
@@ -0,0 +1,102 @@
+#ifndef _PEERCAST_H
+#define _PEERCAST_H
+
+
+//#define APICALL _stdcall
+#ifdef WIN32
+#define APICALL _cdecl
+#else
+#define APICALL 
+#endif
+
+
+class ChanInfo;
+class Sys;
+
+#include "servmgr.h"
+
+
+// ------------------------------------------------------------
+// This is the interface from the application to the core.
+class PeercastInstance 
+{
+public:
+       PeercastInstance()
+       :isQuitting(false) 
+       {}
+
+       virtual void    APICALL init();
+
+       virtual void    APICALL setAutoConnect(bool);
+       virtual bool    APICALL getAutoConnect();
+
+       virtual void    APICALL setActive(bool);
+       virtual bool    APICALL getActive();
+
+       virtual int             APICALL getMaxOutput();
+       virtual void    APICALL setMaxOutput(int);
+
+       virtual int             APICALL getMaxRelays();
+       virtual void    APICALL setMaxRelays(int);
+
+       virtual void    APICALL setServerPort(int);
+       virtual int             APICALL getServerPort();
+       virtual void    APICALL setServerPassword(const char *);
+       virtual const char *APICALL     getServerPassword();
+
+       virtual void    APICALL saveSettings();
+
+       virtual void    APICALL callLocalURL(const char *);
+
+       virtual void    APICALL setNotifyMask(int);
+       virtual int             APICALL getNotifyMask();
+
+       virtual void    APICALL quit();
+
+       virtual Sys     *       APICALL createSys()=0;
+
+       bool isQuitting;
+
+};
+// ------------------------------------------------------------
+// This is the interface from the core to the application.
+class PeercastApplication
+{
+public:
+
+       virtual const char * APICALL getPath() {return "./";}
+       virtual const char * APICALL getIniFilename() {return "peercast.ini";}
+       virtual bool    APICALL clearTemp() { return false; } //JP-EX
+       virtual void    APICALL openLogFile() {} //JP-EX
+       virtual void    APICALL getDirectory() {} //JP-EX
+       virtual void    APICALL printLog(LogBuffer::TYPE, const char *) {}
+       virtual void    APICALL addChannel(ChanInfo *) {}
+       virtual void    APICALL delChannel(ChanInfo *) {}
+       virtual void    APICALL resetChannels() {}
+       virtual void    APICALL test(char *) {}
+       virtual const char *APICALL getClientTypeOS() = 0;
+       virtual void    APICALL updateSettings() {}
+
+       virtual void    APICALL notifyMessage(ServMgr::NOTIFY_TYPE, const char *) {}
+       virtual void    APICALL channelStart(ChanInfo *) {}
+       virtual void    APICALL channelStop(ChanInfo *) {}
+       virtual void    APICALL channelUpdate(ChanInfo *) {}
+};
+
+
+// ----------------------------------
+extern PeercastInstance *peercastInst;
+extern PeercastApplication *peercastApp;
+
+// ----------------------------------
+#ifdef WIN32
+extern "C"
+{
+__declspec( dllexport ) PeercastInstance * newPeercast(PeercastApplication *);
+};
+#endif
+
+// ----------------------------------
+
+
+#endif
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/rtsp.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/rtsp.cpp
new file mode 100644 (file)
index 0000000..4101852
--- /dev/null
@@ -0,0 +1,26 @@
+// ------------------------------------------------
+// File : rtsp.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             RTSP protocol handling (experimental)
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "rtsp.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/rtsp.h b/c:/Git/PeerCast.root/PeerCast/core/common/rtsp.h
new file mode 100644 (file)
index 0000000..60bb71d
--- /dev/null
@@ -0,0 +1,32 @@
+// ------------------------------------------------
+// File : rtsp.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _RTSP_H
+#define _RTSP_H
+
+#include "http.h"
+
+// ---------------------------------------------
+class RTSP : public HTTP
+{
+public:
+       RTSP(Stream &s):HTTP(s){}
+};
+
+#endif
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/servent.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/servent.cpp
new file mode 100644 (file)
index 0000000..1ce8a26
--- /dev/null
@@ -0,0 +1,3163 @@
+// ------------------------------------------------
+// File : servent.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             Servents are the actual connections between clients. They do the handshaking,
+//             transfering of data and processing of GnuPackets. Each servent has one socket allocated
+//             to it on connect, it uses this to transfer all of its data.
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+// todo: make lan->yp not check firewall
+
+#include <stdlib.h>
+#include "servent.h"
+#include "sys.h"
+#include "gnutella.h"
+#include "xml.h"
+#include "html.h"
+#include "http.h"
+#include "stats.h"
+#include "servmgr.h"
+#include "peercast.h"
+#include "atom.h"
+#include "pcp.h"
+#include "version2.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+const int DIRECT_WRITE_TIMEOUT = 60;
+
+// -----------------------------------
+char *Servent::statusMsgs[]=
+{
+        "NONE",
+               "CONNECTING",
+        "PROTOCOL",
+        "HANDSHAKE",
+        "CONNECTED",
+        "CLOSING",
+               "LISTENING",
+               "TIMEOUT",
+               "REFUSED",
+               "VERIFIED",
+               "ERROR",
+               "WAIT",
+               "FREE"
+};
+
+// -----------------------------------
+char *Servent::typeMsgs[]=
+{
+               "NONE",
+        "INCOMING",
+        "SERVER",
+               "RELAY",
+               "DIRECT",
+               "COUT",
+               "CIN",
+               "PGNU"
+};
+// -----------------------------------
+bool   Servent::isPrivate() 
+{
+       Host h = getHost();
+       return servMgr->isFiltered(ServFilter::F_PRIVATE,h) || h.isLocalhost();
+}
+// -----------------------------------
+bool   Servent::isAllowed(int a) 
+{
+       Host h = getHost();
+
+       if (servMgr->isFiltered(ServFilter::F_BAN,h))
+               return false;
+
+       return (allow&a)!=0;
+}
+
+// -----------------------------------
+bool   Servent::isFiltered(int f) 
+{
+       Host h = getHost();
+       return servMgr->isFiltered(f,h);
+}
+
+int servent_count = 1;
+// -----------------------------------
+Servent::Servent(int index)
+:outPacketsPri(MAX_OUTPACKETS)
+,outPacketsNorm(MAX_OUTPACKETS)
+,seenIDs(MAX_HASH)
+,serventIndex(index)
+,sock(NULL)
+,next(NULL)
+{
+       reset();
+       servent_id = servent_count++;
+       lastSkipTime = 0;
+       lastSkipCount = 0;
+       waitPort = 0;
+}
+
+// -----------------------------------
+Servent::~Servent()
+{      
+       
+}
+// -----------------------------------
+void   Servent::kill() 
+{
+       thread.active = false;
+               
+       setStatus(S_CLOSING);
+
+       if (pcpStream)
+       {
+               PCPStream *pcp = pcpStream;
+               pcpStream = NULL;
+               pcp->kill();
+               delete pcp;
+       }
+
+       chanMgr->hitlistlock.on();
+       ChanHitList *chl = chanMgr->findHitListByID(chanID);
+       if (chl) {
+               ChanHit *chh = chl->hit;
+               ChanHit *prev = NULL;
+               while (chh) {
+                       if (chh->servent_id == this->servent_id){
+                               if ((servMgr->kickKeepTime != 0) && (chh->firewalled == 1)){
+                                       chh->numHops = 0;
+                                       chh->numListeners = 0;
+                                       chh->numRelays = 0;
+                                       prev = chh;
+                                       chh = chh->next;
+                               } else {
+                                       ChanHit *next = chh->next;
+                                       if (prev)
+                                               prev->next = next;
+                                       else
+                                               chl->hit = next;
+
+       char ip0str[64],ip1str[64];
+       chh->rhost[0].toStr(ip0str);
+       chh->rhost[1].toStr(ip1str);
+       LOG_DEBUG("Delete hit (servent_id=%d): F%dT%dR%d %s/%s",
+               chh->servent_id,chh->firewalled,chh->tracker,chh->relay,ip0str,ip1str);
+
+                                       delete chh;
+                                       chh = next;
+                               }
+                       } else {
+                               prev = chh;
+                               chh = chh->next;
+                       }
+               }
+       }
+       chanMgr->hitlistlock.off();
+
+       if (sock)
+       {
+               sock->close();
+               delete sock;
+               sock = NULL;
+       }
+
+       if (pushSock)
+       {
+               pushSock->close();
+               delete pushSock;
+               pushSock = NULL;
+       }
+
+//     thread.unlock();
+
+       if (type != T_SERVER)
+       {
+               reset();
+               setStatus(S_FREE);
+       }
+
+}
+// -----------------------------------
+void   Servent::abort() 
+{
+       thread.active = false;
+       if (sock)
+       {
+               sock->close();
+       }
+
+}
+
+// -----------------------------------
+void Servent::reset()
+{
+
+       remoteID.clear();
+
+       servPort = 0;
+
+       pcpStream = NULL;
+
+       flowControl = false;
+       networkID.clear();
+
+       chanID.clear();
+
+       outputProtocol = ChanInfo::SP_UNKNOWN;
+
+       agent.clear();
+       sock = NULL;
+       allow = ALLOW_ALL;
+       syncPos = 0;
+       addMetadata = false;
+       nsSwitchNum = 0;
+       pack.func = 255;
+       lastConnect = lastPing = lastPacket = 0;
+       loginPassword[0] = 0;
+       loginMount[0] = 0;
+       bytesPerSecond = 0;
+       priorityConnect = false;
+       pushSock = NULL;
+       sendHeader = true;
+
+       outPacketsNorm.reset();
+       outPacketsPri.reset();
+
+       seenIDs.clear();
+
+       status = S_NONE;
+       type = T_NONE;
+
+       channel_id = 0;
+}
+// -----------------------------------
+bool Servent::sendPacket(ChanPacket &pack,GnuID &cid,GnuID &sid,GnuID &did,Servent::TYPE t)
+{
+
+       if  (      (type == t) 
+                       && (isConnected())
+                       && (!cid.isSet() || chanID.isSame(cid))
+                       && (!sid.isSet() || !sid.isSame(remoteID))
+                       && (pcpStream != NULL)
+               )
+       {
+               return pcpStream->sendPacket(pack,did);
+       }
+       return false;
+}
+
+
+// -----------------------------------
+bool Servent::acceptGIV(ClientSocket *givSock)
+{
+       if (!pushSock)
+       {
+               pushSock = givSock;
+               return true;
+       }else
+               return false;
+}
+
+// -----------------------------------
+Host Servent::getHost()
+{
+       Host h(0,0);
+
+       if (sock)
+               h = sock->host;
+
+       return h;
+}
+
+// -----------------------------------
+bool Servent::outputPacket(GnuPacket &p, bool pri)
+{
+       lock.on();
+
+       bool r=false;
+       if (pri)
+               r = outPacketsPri.write(p);
+       else
+       {
+               if (servMgr->useFlowControl)
+               {
+                       int per = outPacketsNorm.percentFull();
+                       if (per > 50)
+                               flowControl = true;
+                       else if (per < 25)
+                               flowControl = false;
+               }
+
+
+               bool send=true;
+               if (flowControl)
+               {
+                       // if in flowcontrol, only allow packets with less of a hop count than already in queue
+                       if (p.hops >= outPacketsNorm.findMinHop())
+                               send = false;
+               }
+
+               if (send)
+                       r = outPacketsNorm.write(p);
+       }
+
+       lock.off();
+       return r;
+}
+
+// -----------------------------------
+bool Servent::initServer(Host &h)
+{
+       try
+       {
+               checkFree();
+
+               status = S_WAIT;
+
+               createSocket();
+
+               sock->bind(h);
+
+               thread.data = this;
+
+               thread.func = serverProc;
+
+               type = T_SERVER;
+
+               if (!sys->startThread(&thread))
+                       throw StreamException("Can`t start thread");
+
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("Bad server: %s",e.msg);
+               kill();
+               return false;
+       }
+
+       return true;
+}
+// -----------------------------------
+void Servent::checkFree()
+{
+       if (sock)
+               throw StreamException("Socket already set");
+       if (thread.active)
+               throw StreamException("Thread already active");
+}
+// -----------------------------------
+void Servent::initIncoming(ClientSocket *s, unsigned int a)
+{
+
+       try{
+
+               checkFree();
+
+               type = T_INCOMING;
+               sock = s;
+               allow = a;
+               thread.data = this;
+               thread.func = incomingProc;
+
+               setStatus(S_PROTOCOL);
+
+               char ipStr[64];
+               sock->host.toStr(ipStr);
+               LOG_DEBUG("Incoming from %s",ipStr);
+
+
+               if (!sys->startThread(&thread))
+                       throw StreamException("Can`t start thread");
+       }catch(StreamException &e)
+       {
+               //LOG_ERROR("!!FATAL!! Incoming error: %s",e.msg);
+               //servMgr->shutdownTimer = 1;   
+               kill();
+
+               LOG_ERROR("INCOMING FAILED: %s",e.msg);
+
+       }
+}
+
+// -----------------------------------
+void Servent::initOutgoing(TYPE ty)
+{
+       try 
+       {
+               checkFree();
+
+
+               type = ty;
+
+               thread.data = this;
+               thread.func = outgoingProc;
+
+               if (!sys->startThread(&thread))
+                       throw StreamException("Can`t start thread");
+
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("Unable to start outgoing: %s",e.msg);
+               kill();
+       }
+}
+
+// -----------------------------------
+void Servent::initPCP(Host &rh)
+{
+       char ipStr[64];
+       rh.toStr(ipStr);
+       try 
+       {
+               checkFree();
+
+           createSocket();
+
+               type = T_COUT;
+
+               sock->open(rh);
+
+               if (!isAllowed(ALLOW_NETWORK))
+                       throw StreamException("Servent not allowed");
+
+               thread.data = this;
+               thread.func = outgoingProc;
+
+               LOG_DEBUG("Outgoing to %s",ipStr);
+
+               if (!sys->startThread(&thread))
+                       throw StreamException("Can`t start thread");
+
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("Unable to open connection to %s - %s",ipStr,e.msg);
+               kill();
+       }
+}
+
+#if 0
+// -----------------------------------
+void   Servent::initChannelFetch(Host &host)
+{
+       type = T_STREAM;
+
+       char ipStr[64];
+       host.toStr(ipStr);
+
+       checkFree();
+        
+       createSocket();
+               
+       sock->open(host);
+
+               
+       if (!isAllowed(ALLOW_DATA))     
+               throw StreamException("Servent not allowed");
+               
+       sock->connect();
+}
+#endif
+
+// -----------------------------------
+void Servent::initGIV(Host &h, GnuID &id)
+{
+       char ipStr[64];
+       h.toStr(ipStr);
+       try 
+       {
+               checkFree();
+
+               givID = id;
+
+           createSocket();
+
+               sock->open(h);
+
+               if (!isAllowed(ALLOW_NETWORK))
+                       throw StreamException("Servent not allowed");
+               
+               sock->connect();
+
+               thread.data = this;
+               thread.func = givProc;
+
+               type = T_RELAY;
+
+               if (!sys->startThread(&thread))
+                       throw StreamException("Can`t start thread");
+
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("GIV error to %s: %s",ipStr,e.msg);
+               kill();
+       }
+}
+// -----------------------------------
+void Servent::createSocket()
+{
+       if (sock)
+               LOG_ERROR("Servent::createSocket attempt made while active");
+
+       sock = sys->createSocket();
+}
+// -----------------------------------
+void Servent::setStatus(STATUS s)
+{
+       if (s != status)
+       {
+               status = s;
+
+               if ((s == S_HANDSHAKE) || (s == S_CONNECTED) || (s == S_LISTENING))
+                       lastConnect = sys->getTime();
+       }
+
+}
+
+// -----------------------------------
+void Servent::handshakeOut()
+{
+    sock->writeLine(GNU_PEERCONN);
+
+       char str[64];
+    
+       sock->writeLineF("%s %s",HTTP_HS_AGENT,PCX_AGENT);
+    sock->writeLineF("%s %d",PCX_HS_PCP,1);
+
+       if (priorityConnect)
+           sock->writeLineF("%s %d",PCX_HS_PRIORITY,1);
+       
+       if (networkID.isSet())
+       {
+               networkID.toStr(str);
+               sock->writeLineF("%s %s",PCX_HS_NETWORKID,str);
+       }
+
+       servMgr->sessionID.toStr(str);
+       sock->writeLineF("%s %s",PCX_HS_ID,str);
+
+       
+    sock->writeLineF("%s %s",PCX_HS_OS,peercastApp->getClientTypeOS());
+       
+       sock->writeLine("");
+
+       HTTP http(*sock);
+
+       int r = http.readResponse();
+
+       if (r != 200)
+       {
+               LOG_ERROR("Expected 200, got %d",r);
+               throw StreamException("Unexpected HTTP response");
+       }
+
+
+       bool versionValid = false;
+
+       GnuID clientID;
+       clientID.clear();
+
+    while (http.nextHeader())
+    {
+               LOG_DEBUG(http.cmdLine);
+
+               char *arg = http.getArgStr();
+               if (!arg)
+                       continue;
+
+               if (http.isHeader(HTTP_HS_AGENT))
+               {
+                       agent.set(arg);
+
+                       if (strnicmp(arg,"PeerCast/",9)==0)
+                               versionValid = (stricmp(arg+9,MIN_CONNECTVER)>=0);
+               }else if (http.isHeader(PCX_HS_NETWORKID))
+                       clientID.fromStr(arg);
+    }
+
+       if (!clientID.isSame(networkID))
+               throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+       if (!versionValid)
+               throw HTTPException(HTTP_SC_UNAUTHORIZED,401);
+
+
+    sock->writeLine(GNU_OK);
+    sock->writeLine("");
+
+}
+
+
+// -----------------------------------
+void Servent::processOutChannel()
+{
+}
+
+
+// -----------------------------------
+void Servent::handshakeIn()
+{
+
+       int osType=0;
+
+       HTTP http(*sock);
+
+
+       bool versionValid = false;
+       bool diffRootVer = false;
+
+       GnuID clientID;
+       clientID.clear();
+
+    while (http.nextHeader())
+    {
+               LOG_DEBUG("%s",http.cmdLine);
+
+               char *arg = http.getArgStr();
+               if (!arg)
+                       continue;
+
+               if (http.isHeader(HTTP_HS_AGENT))
+               {
+                       agent.set(arg);
+
+                       if (strnicmp(arg,"PeerCast/",9)==0)
+                       {
+                               versionValid = (stricmp(arg+9,MIN_CONNECTVER)>=0);
+                               diffRootVer = stricmp(arg+9,MIN_ROOTVER)<0;
+                       }
+               }else if (http.isHeader(PCX_HS_NETWORKID))
+               {
+                       clientID.fromStr(arg);
+
+               }else if (http.isHeader(PCX_HS_PRIORITY))
+               {
+                       priorityConnect = atoi(arg)!=0;
+
+               }else if (http.isHeader(PCX_HS_ID))
+               {
+                       GnuID id;
+                       id.fromStr(arg);
+                       if (id.isSame(servMgr->sessionID))
+                               throw StreamException("Servent loopback");
+
+               }else if (http.isHeader(PCX_HS_OS))
+               {
+                       if (stricmp(arg,PCX_OS_LINUX)==0)
+                               osType = 1;
+                       else if (stricmp(arg,PCX_OS_WIN32)==0)
+                               osType = 2;
+                       else if (stricmp(arg,PCX_OS_MACOSX)==0)
+                               osType = 3;
+                       else if (stricmp(arg,PCX_OS_WINAMP2)==0)
+                               osType = 4;
+               }
+
+    }
+
+       if (!clientID.isSame(networkID))
+               throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+       // if this is a priority connection and all incoming connections 
+       // are full then kill an old connection to make room. Otherwise reject connection.
+       //if (!priorityConnect)
+       {
+               if (!isPrivate())
+                       if (servMgr->pubInFull())
+                               throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+       }
+
+       if (!versionValid)
+               throw HTTPException(HTTP_SC_FORBIDDEN,403);
+
+    sock->writeLine(GNU_OK);
+
+    sock->writeLineF("%s %s",HTTP_HS_AGENT,PCX_OLDAGENT);
+
+       if (networkID.isSet())
+       {
+               char idStr[64];
+               networkID.toStr(idStr);
+               sock->writeLineF("%s %s",PCX_HS_NETWORKID,idStr);
+       }
+
+       if (servMgr->isRoot)
+       {
+               sock->writeLineF("%s %d",PCX_HS_FLOWCTL,servMgr->useFlowControl?1:0);
+               sock->writeLineF("%s %d",PCX_HS_MINBCTTL,chanMgr->minBroadcastTTL);
+               sock->writeLineF("%s %d",PCX_HS_MAXBCTTL,chanMgr->maxBroadcastTTL);
+               sock->writeLineF("%s %d",PCX_HS_RELAYBC,servMgr->relayBroadcast);
+               //sock->writeLine("%s %d",PCX_HS_FULLHIT,2);
+
+
+               if (diffRootVer)
+               {
+                       sock->writeString(PCX_HS_DL);
+                       sock->writeLine(PCX_DL_URL);
+               }
+
+               sock->writeLineF("%s %s",PCX_HS_MSG,servMgr->rootMsg.cstr());
+       }
+
+
+       char hostIP[64];
+       Host h = sock->host;
+       h.IPtoStr(hostIP);
+    sock->writeLineF("%s %s",PCX_HS_REMOTEIP,hostIP);
+
+
+    sock->writeLine("");
+
+
+       while (http.nextHeader());
+}
+
+// -----------------------------------
+bool   Servent::pingHost(Host &rhost,GnuID &rsid)
+{
+       char ipstr[64];
+       rhost.toStr(ipstr);
+       LOG_DEBUG("Ping host %s: trying..",ipstr);
+       ClientSocket *s=NULL;
+       bool hostOK=false;
+       try
+       {
+               s = sys->createSocket();
+               if (!s)
+                       return false;
+               else
+               {
+
+                       s->setReadTimeout(15000);
+                       s->setWriteTimeout(15000);
+                       s->open(rhost);
+                       s->connect();
+
+                       AtomStream atom(*s);
+
+                       atom.writeInt(PCP_CONNECT,1);
+                       atom.writeParent(PCP_HELO,1);
+                               atom.writeBytes(PCP_HELO_SESSIONID,servMgr->sessionID.id,16);
+
+                       GnuID sid;
+                       sid.clear();
+
+                       int numc,numd;
+                       ID4 id = atom.read(numc,numd);
+                       if (id == PCP_OLEH)
+                       {
+                               for(int i=0; i<numc; i++)
+                               {
+                                       int c,d;
+                                       ID4 pid = atom.read(c,d);
+                                       if (pid == PCP_SESSIONID)
+                                               atom.readBytes(sid.id,16,d);
+                                       else
+                                               atom.skip(c,d);
+                               }
+                       }else
+                       {
+                               LOG_DEBUG("Ping response: %s",id.getString().str());
+                               throw StreamException("Bad ping response");
+                       }
+
+                       if (!sid.isSame(rsid))
+                               throw StreamException("SIDs don`t match");
+
+                       hostOK = true;
+                       LOG_DEBUG("Ping host %s: OK",ipstr);
+                       atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT);
+
+
+               }
+       }catch(StreamException &e)
+       {
+               LOG_DEBUG("Ping host %s: %s",ipstr,e.msg);
+       }
+       if (s)
+       {
+               s->close();
+               delete s;
+       }
+
+       if (!hostOK)
+               rhost.port = 0;
+
+       return true;
+}
+
+WLock canStreamLock;
+
+// -----------------------------------
+bool Servent::handshakeStream(ChanInfo &chanInfo)
+{
+
+       HTTP http(*sock);
+
+
+       bool gotPCP=false;
+       unsigned int reqPos=0;
+
+       nsSwitchNum=0;
+
+       while (http.nextHeader())
+       {
+               char *arg = http.getArgStr();
+               if (!arg)
+                       continue;
+
+               if (http.isHeader(PCX_HS_PCP))
+                       gotPCP = atoi(arg)!=0;
+               else if (http.isHeader(PCX_HS_POS))
+                       reqPos = atoi(arg);
+               else if (http.isHeader("icy-metadata"))
+                       addMetadata = atoi(arg) > 0;
+               else if (http.isHeader(HTTP_HS_AGENT))
+                       agent = arg;
+               else if (http.isHeader("Pragma"))
+               {
+                       char *ssc = stristr(arg,"stream-switch-count=");
+                       char *so = stristr(arg,"stream-offset");
+
+                       if (ssc || so)
+                       {
+                               nsSwitchNum=1;
+                               //nsSwitchNum = atoi(ssc+20);
+                       }
+               }
+
+               LOG_DEBUG("Stream: %s",http.cmdLine);
+       }
+
+
+       if ((!gotPCP) && (outputProtocol == ChanInfo::SP_PCP))
+               outputProtocol = ChanInfo::SP_PEERCAST;
+
+       if (outputProtocol == ChanInfo::SP_HTTP)
+       {
+               if  ( (chanInfo.srcProtocol == ChanInfo::SP_MMS)
+                         || (chanInfo.contentType == ChanInfo::T_WMA)
+                         || (chanInfo.contentType == ChanInfo::T_WMV)
+                         || (chanInfo.contentType == ChanInfo::T_ASX)
+                       )
+               outputProtocol = ChanInfo::SP_MMS;
+       }
+
+
+       bool chanFound=false;
+       bool chanReady=false;
+
+       Channel *ch = chanMgr->findChannelByID(chanInfo.id);
+       if (ch)
+       {
+               sendHeader = true;
+//             if (reqPos)
+//             {
+//                     streamPos = ch->rawData.findOldestPos(reqPos);
+//             }else
+//             {
+                       streamPos = ch->rawData.getLatestPos();
+//             }
+
+               chanID = chanInfo.id;
+               canStreamLock.on();
+               chanReady = canStream(ch);
+               if (!chanReady) type = T_INCOMING;
+               thread.active = chanReady;
+               setStatus(S_CONNECTED);
+               canStreamLock.off();
+               channel_id = ch->channel_id;
+
+               //JP-Patch add-s
+               if (servMgr->isCheckPushStream())
+               {
+                       if (chanReady == true)
+                       {
+                               Host h = getHost();
+
+                               if (!h.isLocalhost()) 
+                               {
+                                       do 
+                                       {
+                                               if (strstr(agent.cstr(),"PeerCast/0.119") != NULL) 
+                                               {                                               
+                                                       char strip[256];
+                                                       h.toStr(strip);
+                                                       LOG_ERROR("Block v0.119 Servent : %s (%s)",strip,agent.cstr());
+                                                       chanReady = false;
+                                                       break;
+                                               }
+
+/*                                             ChanHitList *hits[ChanMgr::MAX_HITLISTS];
+                                               int numHits=0;
+                                               for(int i=0; i<ChanMgr::MAX_HITLISTS; i++)
+                                               {
+                                                       ChanHitList *chl = &chanMgr->hitlists[i];
+                                                       if (chl->isUsed())
+                                                               hits[numHits++] = chl;
+                                               }
+                                               bool isfw = false;
+                                               int numRelay = 0;
+                                               for(int i=0; i<numHits; i++)
+                                               {
+                                                       ChanHitList *chl = hits[i];
+                                                       if (chl->isUsed())
+                                                       {
+                                                               for (int j=0; j<ChanHitList::MAX_HITS; j++)
+                                                               {
+                                                                       ChanHit *hit = &chl->hits[j];
+                                                                       if (hit->host.isValid() && (h.ip == hit->host.ip)) 
+                                                                       {
+                                                                               if (hit->firewalled)
+                                                                                       isfw = true;
+                                                                               numRelay = hit->numRelays;
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                               if ((isfw == true) && (numRelay == 0))
+                                               {
+                                                       char strip[256];
+                                                       h.toStr(strip);
+                                                       LOG_ERROR("Block firewalled Servent : %s",strip);
+                                                       chanReady = false;
+                                               }*/
+
+                                               ChanHitList *chl = chanMgr->findHitList(chanInfo);
+                                               ChanHit *hit = chl->hit;
+                                               while(hit){
+                                                       if (hit->host.isValid() && (h.ip == hit->host.ip))
+                                                       {
+                                                               if ((hit->firewalled) && (hit->numRelays == 0)){
+                                                                       char strip[256];
+                                                                       h.toStr(strip);
+                                                                       LOG_ERROR("Block firewalled Servent : %s",strip);
+                                                                       chanReady = false;
+                                                               }
+                                                       }
+                                                       hit = hit->next;
+                                               }
+                                       }while (0);
+                               }               
+                       }
+               }
+               //JP-Patch add-e
+       }
+
+//     LockBlock lockblock(chanMgr->hitlistlock);
+
+//     lockblock.lockon();
+       ChanHitList *chl = chanMgr->findHitList(chanInfo);
+
+       if (chl)
+       {
+               chanFound = true;
+       }
+
+
+       bool result = false;
+
+       char idStr[64];
+       chanInfo.id.toStr(idStr);
+
+       char sidStr[64];
+       servMgr->sessionID.toStr(sidStr);
+
+       Host rhost = sock->host;
+
+
+
+
+       AtomStream atom(*sock);
+
+
+
+       if (!chanFound)
+       {
+               sock->writeLine(HTTP_SC_NOTFOUND);
+           sock->writeLine("");
+               LOG_DEBUG("Sending channel not found");
+               return false;
+       }
+
+
+       if (!chanReady)
+       {
+               if (outputProtocol == ChanInfo::SP_PCP)
+               {
+
+                       char tbuf[8196];
+                       MemoryStream mem(tbuf, sizeof(tbuf));
+                       mem.writeLine(HTTP_SC_UNAVAILABLE);
+                       mem.writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XPCP);
+                       mem.writeLine("");
+                       sock->write(tbuf, mem.getPosition());
+
+                       handshakeIncomingPCP(atom,rhost,remoteID,agent);
+
+                       char ripStr[64];
+                       rhost.toStr(ripStr);
+
+                       LOG_DEBUG("Sending channel unavailable");
+
+                       ChanHitSearch chs;
+
+                       mem.rewind();
+                       AtomStream atom2(mem);
+
+                       int error = PCP_ERROR_QUIT+PCP_ERROR_UNAVAILABLE;
+
+                       chanMgr->hitlistlock.on();
+
+                       chl = chanMgr->findHitList(chanInfo);
+
+                       if (chl)
+                       {
+                               ChanHit best;
+                               
+                               // search for up to 8 other hits
+                               int cnt=0;
+                               for(int i=0; i<8; i++)
+                               {
+                                       best.init();
+
+
+                                       // find best hit this network if local IP
+                                       if (!rhost.globalIP())
+                                       {
+                                               chs.init();
+                                               chs.matchHost = servMgr->serverHost;
+                                               chs.waitDelay = 2;
+                                               chs.excludeID = remoteID;
+                                               if (chl->pickHits(chs)){
+                                                       best = chs.best[0];
+                                                       LOG_DEBUG("find best hit this network if local IP");
+                                               }
+                                       }
+
+                                       // find best hit on same network
+                                       if (!best.host.ip)
+                                       {
+                                               chs.init();
+                                               chs.matchHost = rhost;
+                                               chs.waitDelay = 2;
+                                               chs.excludeID = remoteID;
+                                               if (chl->pickHits(chs)){
+                                                       best = chs.best[0];
+                                                       LOG_DEBUG("find best hit on same network");
+                                               }
+
+                                       }
+
+                                       // find best hit on other networks
+/*                                     if (!best.host.ip)
+                                       {
+                                               chs.init();
+                                               chs.waitDelay = 2;
+                                               chs.excludeID = remoteID;
+                                               if (chl->pickHits(chs)){
+                                                       best = chs.best[0];
+                                                       LOG_DEBUG("find best hit on other networks");
+                                               }
+
+                                       }*/
+                                       
+                                       if (!best.host.ip)
+                                               break;
+
+                                       best.writeAtoms(atom2,chanInfo.id);                             
+                                       cnt++;
+                               }
+
+                               if (!best.host.ip){
+                                       char tmp[50];
+//                                     chanMgr->hitlistlock.on();
+                                       int cnt = chs.getRelayHost(servMgr->serverHost, rhost, remoteID, chl);
+//                                     chanMgr->hitlistlock.off();
+                                       for (int i = 0; i < cnt; i++){
+                                               chs.best[i].writeAtoms(atom2, chanInfo.id);
+                                               chs.best[i].host.toStr(tmp);
+                                               LOG_DEBUG("relay info: %s hops = %d", tmp, chs.best[i].numHops);
+                                               best.host.ip = chs.best[i].host.ip;
+                                       }
+                               }
+
+                               if (cnt)
+                               {
+                                       LOG_DEBUG("Sent %d channel hit(s) to %s",cnt,ripStr);
+
+                               }
+                               else if (rhost.port)
+                               {
+                                       // find firewalled host
+                                       chs.init();
+                                       chs.waitDelay = 30;
+                                       chs.useFirewalled = true;
+                                       chs.excludeID = remoteID;
+                                       if (chl->pickHits(chs))
+                                       {
+                                               best = chs.best[0];
+                                               int cnt = servMgr->broadcastPushRequest(best,rhost,chl->info.id,Servent::T_RELAY);
+                                               LOG_DEBUG("Broadcasted channel push request to %d clients for %s",cnt,ripStr);
+                                       }
+                               } 
+
+                               // if all else fails, use tracker
+                               if (!best.host.ip)
+                               {
+                                       // find best tracker on this network if local IP
+                                       if (!rhost.globalIP())
+                                       {
+                                               chs.init();
+                                               chs.matchHost = servMgr->serverHost;
+                                               chs.trackersOnly = true;
+                                               chs.excludeID = remoteID;
+                                               if (chl->pickHits(chs))
+                                                       best = chs.best[0];
+
+                                       }
+
+                                       // find local tracker
+                                       if (!best.host.ip)
+                                       {
+                                               chs.init();
+                                               chs.matchHost = rhost;
+                                               chs.trackersOnly = true;
+                                               chs.excludeID = remoteID;
+                                               if (chl->pickHits(chs))
+                                                       best = chs.best[0];
+                                       }
+
+                                       // find global tracker
+                                       if (!best.host.ip)
+                                       {
+                                               chs.init();
+                                               chs.trackersOnly = true;
+                                               chs.excludeID = remoteID;
+                                               if (chl->pickHits(chs))
+                                                       best = chs.best[0];
+                                       }
+
+                                       if (best.host.ip)
+                                       {
+                                               best.writeAtoms(atom2,chanInfo.id);                             
+                                               LOG_DEBUG("Sent 1 tracker hit to %s",ripStr);
+                                       }else if (rhost.port)
+                                       {
+                                               // find firewalled tracker
+                                               chs.init();
+                                               chs.useFirewalled = true;
+                                               chs.trackersOnly = true;
+                                               chs.excludeID = remoteID;
+                                               chs.waitDelay = 30;
+                                               if (chl->pickHits(chs))
+                                               {
+                                                       best = chs.best[0];
+                                                       int cnt = servMgr->broadcastPushRequest(best,rhost,chl->info.id,Servent::T_CIN);
+                                                       LOG_DEBUG("Broadcasted tracker push request to %d clients for %s",cnt,ripStr);
+                                               }
+                                       }
+
+                               }
+
+
+                       }
+
+                       chanMgr->hitlistlock.off();
+
+                       // return not available yet code
+                       atom2.writeInt(PCP_QUIT,error);
+                       sock->write(tbuf, mem.getPosition());
+                       result = false;
+
+                       /*
+                       char c[512];
+                       // wait disconnect from other host
+                       try{
+                               while(sock->read(c, sizeof(c))){
+                                       sys->sleep(10);
+                               }
+                       }catch(StreamException &e){
+                               LOG_DEBUG("RelayInfoWait: %s",e.msg);
+                       }
+                       */
+               }else
+               {
+                       LOG_DEBUG("Sending channel unavailable");
+                       sock->writeLine(HTTP_SC_UNAVAILABLE);
+                       sock->writeLine("");
+                       result = false;
+               }
+
+       } else {
+
+               if (chanInfo.contentType != ChanInfo::T_MP3)
+                       addMetadata=false;
+
+               if (addMetadata && (outputProtocol == ChanInfo::SP_HTTP))               // winamp mp3 metadata check
+               {
+
+                       sock->writeLine(ICY_OK);
+
+                       sock->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT);
+                       sock->writeLineF("icy-name:%s",chanInfo.name.cstr());
+                       sock->writeLineF("icy-br:%d",chanInfo.bitrate);
+                       sock->writeLineF("icy-genre:%s",chanInfo.genre.cstr());
+                       sock->writeLineF("icy-url:%s",chanInfo.url.cstr());
+                       sock->writeLineF("icy-metaint:%d",chanMgr->icyMetaInterval);
+                       sock->writeLineF("%s %s",PCX_HS_CHANNELID,idStr);
+
+                       sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MP3);
+
+               }else
+               {
+
+                       sock->writeLine(HTTP_SC_OK);
+
+                       if ((chanInfo.contentType != ChanInfo::T_ASX) && (chanInfo.contentType != ChanInfo::T_WMV) && (chanInfo.contentType != ChanInfo::T_WMA))
+                       {
+                               sock->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT);
+
+                               sock->writeLine("Accept-Ranges: none");
+
+                               sock->writeLineF("x-audiocast-name: %s",chanInfo.name.cstr());
+                               sock->writeLineF("x-audiocast-bitrate: %d",chanInfo.bitrate);
+                               sock->writeLineF("x-audiocast-genre: %s",chanInfo.genre.cstr());
+                               sock->writeLineF("x-audiocast-description: %s",chanInfo.desc.cstr());
+                               sock->writeLineF("x-audiocast-url: %s",chanInfo.url.cstr());
+                               sock->writeLineF("%s %s",PCX_HS_CHANNELID,idStr);
+                       }
+
+
+                       if (outputProtocol == ChanInfo::SP_HTTP)
+                       {
+                               switch (chanInfo.contentType)
+                               {
+                                       case ChanInfo::T_OGG:
+                                               sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XOGG);
+                                               break;
+                                       case ChanInfo::T_MP3:
+                                               sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MP3);
+                                               break;
+                                       case ChanInfo::T_MOV:
+                                               sock->writeLine("Connection: close");
+                                               sock->writeLine("Content-Length: 10000000");
+                                               sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MOV);
+                                               break;
+                                       case ChanInfo::T_MPG:
+                                               sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MPG);
+                                               break;
+                                       case ChanInfo::T_NSV:
+                                               sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_NSV);
+                                               break;
+                                       case ChanInfo::T_ASX:
+                                               sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_ASX);
+                                               break;
+                                       case ChanInfo::T_WMA:
+                                               sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_WMA);
+                                               break;
+                                       case ChanInfo::T_WMV:
+                                               sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_WMV);
+                                               break;
+                               }
+                       } else if (outputProtocol == ChanInfo::SP_MMS)
+                       {
+                               sock->writeLine("Server: Rex/9.0.0.2980");
+                               sock->writeLine("Cache-Control: no-cache");
+                               sock->writeLine("Pragma: no-cache");
+                               sock->writeLine("Pragma: client-id=3587303426");
+                               sock->writeLine("Pragma: features=\"broadcast,playlist\"");
+
+                               if (nsSwitchNum)
+                               {
+                                       sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MMS);
+                               }else
+                               {
+                                       sock->writeLine("Content-Type: application/vnd.ms.wms-hdr.asfv1");
+                                       if (ch)
+                                               sock->writeLineF("Content-Length: %d",ch->headPack.len);
+                                       sock->writeLine("Connection: Keep-Alive");
+                               }
+                       
+                       } else if (outputProtocol == ChanInfo::SP_PCP)
+                       {
+                               sock->writeLineF("%s %d",PCX_HS_POS,streamPos);
+                               sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XPCP);
+
+                       }else if (outputProtocol == ChanInfo::SP_PEERCAST)
+                       {
+                               sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XPEERCAST);
+                       }
+               }
+               sock->writeLine("");
+               result = true;
+
+               if (gotPCP)
+               {
+                       handshakeIncomingPCP(atom,rhost,remoteID,agent);
+                       atom.writeInt(PCP_OK,0);
+               }
+
+       }
+
+
+
+       return result;
+}
+
+// -----------------------------------
+void Servent::handshakeGiv(GnuID &id)
+{
+       if (id.isSet())
+       {
+               char idstr[64];
+               id.toStr(idstr);
+               sock->writeLineF("GIV /%s",idstr);
+       }else
+               sock->writeLine("GIV");
+
+       sock->writeLine("");
+}
+
+
+// -----------------------------------
+void Servent::processGnutella()
+{
+       type = T_PGNU;
+
+       //if (servMgr->isRoot && !servMgr->needConnections())
+       if (servMgr->isRoot)
+       {
+               processRoot();
+               return;
+       }
+
+
+
+       gnuStream.init(sock);
+       setStatus(S_CONNECTED);
+
+       if (!servMgr->isRoot)
+       {
+               chanMgr->broadcastRelays(this, 1, 1);
+               GnuPacket *p;
+
+               if ((p=outPacketsNorm.curr()))  
+                       gnuStream.sendPacket(*p);
+               return;
+       }
+
+       gnuStream.ping(2);
+
+//     if (type != T_LOOKUP)
+//             chanMgr->broadcastRelays(this,chanMgr->minBroadcastTTL,2);
+
+       lastPacket = lastPing = sys->getTime();
+       bool doneBigPing=false;
+
+       const unsigned int      abortTimeoutSecs = 60;          // abort connection after 60 secs of no activitiy
+       const unsigned int      packetTimeoutSecs = 30;         // ping connection after 30 secs of no activity
+
+       unsigned int currBytes=0;
+       unsigned int lastWait=0;
+
+       unsigned int lastTotalIn=0,lastTotalOut=0;
+
+       while (thread.active && sock->active())
+       {
+
+               if (sock->readReady())
+               {
+                       lastPacket = sys->getTime();
+
+                       if (gnuStream.readPacket(pack))
+                       {
+                               char ipstr[64];
+                               sock->host.toStr(ipstr);
+
+                               GnuID routeID;
+                               GnuStream::R_TYPE ret = GnuStream::R_PROCESS;
+
+                               if (pack.func != GNU_FUNC_PONG)
+                                       if (servMgr->seenPacket(pack))
+                                               ret = GnuStream::R_DUPLICATE;
+
+                               seenIDs.add(pack.id);
+
+
+                               if (ret == GnuStream::R_PROCESS)
+                               {
+                                       GnuID routeID;
+                                       ret = gnuStream.processPacket(pack,this,routeID);
+
+                                       if (flowControl && (ret == GnuStream::R_BROADCAST))
+                                               ret = GnuStream::R_DROP;
+
+                               }
+
+                               switch(ret)
+                               {
+                                       case GnuStream::R_BROADCAST:
+                                               if (servMgr->broadcast(pack,this))
+                                                       stats.add(Stats::NUMBROADCASTED);
+                                               else
+                                                       stats.add(Stats::NUMDROPPED);
+                                               break;
+                                       case GnuStream::R_ROUTE:
+                                               if (servMgr->route(pack,routeID,NULL))
+                                                       stats.add(Stats::NUMROUTED);
+                                               else
+                                                       stats.add(Stats::NUMDROPPED);
+                                               break;
+                                       case GnuStream::R_ACCEPTED:
+                                               stats.add(Stats::NUMACCEPTED);
+                                               break;
+                                       case GnuStream::R_DUPLICATE:
+                                               stats.add(Stats::NUMDUP);
+                                               break;
+                                       case GnuStream::R_DEAD:
+                                               stats.add(Stats::NUMDEAD);
+                                               break;
+                                       case GnuStream::R_DISCARD:
+                                               stats.add(Stats::NUMDISCARDED);
+                                               break;
+                                       case GnuStream::R_BADVERSION:
+                                               stats.add(Stats::NUMOLD);
+                                               break;
+                                       case GnuStream::R_DROP:
+                                               stats.add(Stats::NUMDROPPED);
+                                               break;
+                               }
+
+
+                               LOG_NETWORK("packet in: %s-%s, %d bytes, %d hops, %d ttl, from %s",GNU_FUNC_STR(pack.func),GnuStream::getRouteStr(ret),pack.len,pack.hops,pack.ttl,ipstr);
+
+
+
+                       }else{
+                               LOG_ERROR("Bad packet");
+                       }
+               }
+
+
+               GnuPacket *p;
+
+               if ((p=outPacketsPri.curr()))                           // priority packet
+               {
+                       gnuStream.sendPacket(*p);
+                       seenIDs.add(p->id);
+                       outPacketsPri.next();
+               } else if ((p=outPacketsNorm.curr()))           // or.. normal packet
+               {
+                       gnuStream.sendPacket(*p);
+                       seenIDs.add(p->id);
+                       outPacketsNorm.next();
+               }
+
+               int lpt =  sys->getTime()-lastPacket;
+
+               if (!doneBigPing)
+               {
+                       if ((sys->getTime()-lastPing) > 15)
+                       {
+                               gnuStream.ping(7);
+                               lastPing = sys->getTime();
+                               doneBigPing = true;
+                       }
+               }else{
+                       if (lpt > packetTimeoutSecs)
+                       {
+                               
+                               if ((sys->getTime()-lastPing) > packetTimeoutSecs)
+                               {
+                                       gnuStream.ping(1);
+                                       lastPing = sys->getTime();
+                               }
+
+                       }
+               }
+               if (lpt > abortTimeoutSecs)
+                       throw TimeoutException();
+
+
+               unsigned int totIn = sock->totalBytesIn-lastTotalIn;
+               unsigned int totOut = sock->totalBytesOut-lastTotalOut;
+
+               unsigned int bytes = totIn+totOut;
+
+               lastTotalIn = sock->totalBytesIn;
+               lastTotalOut = sock->totalBytesOut;
+
+               const int serventBandwidth = 1000;
+
+               int delay = sys->idleSleepTime;
+               if ((bytes) && (serventBandwidth >= 8))
+                       delay = (bytes*1000)/(serventBandwidth/8);      // set delay relative packetsize
+
+               if (delay < (int)sys->idleSleepTime)
+                       delay = sys->idleSleepTime;
+               //LOG("delay %d, in %d, out %d",delay,totIn,totOut);
+
+               sys->sleep(delay);
+       }
+
+}
+
+
+// -----------------------------------
+void Servent::processRoot()
+{
+       try 
+       {
+       
+               gnuStream.init(sock);
+               setStatus(S_CONNECTED);
+
+               gnuStream.ping(2);
+
+               unsigned int lastConnect = sys->getTime();
+
+               while (thread.active && sock->active())
+               {
+                       if (gnuStream.readPacket(pack))
+                       {
+                               char ipstr[64];
+                               sock->host.toStr(ipstr);
+                               
+                               LOG_NETWORK("packet in: %d from %s",pack.func,ipstr);
+
+
+                               if (pack.func == GNU_FUNC_PING)         // if ping then pong back some hosts and close
+                               {
+                                       
+                                       Host hl[32];
+                                       int cnt = servMgr->getNewestServents(hl,32,sock->host); 
+                                       if (cnt)
+                                       {
+                                               int start = sys->rnd() % cnt;
+                                               int max = cnt>8?8:cnt;
+
+                                               for(int i=0; i<max; i++)
+                                               {
+                                                       GnuPacket pong;
+                                                       pack.hops = 1;
+                                                       pong.initPong(hl[start],false,pack);
+                                                       gnuStream.sendPacket(pong);
+
+                                                       char ipstr[64];
+                                                       hl[start].toStr(ipstr);
+
+                                                       //LOG_NETWORK("Pong %d: %s",start+1,ipstr);
+                                                       start = (start+1) % cnt;
+                                               }
+                                               char str[64];
+                                               sock->host.toStr(str);
+                                               LOG_NETWORK("Sent %d pong(s) to %s",max,str);
+                                       }else
+                                       {
+                                               LOG_NETWORK("No Pongs to send");
+                                               //return;
+                                       }
+                               }else if (pack.func == GNU_FUNC_PONG)           // pong?
+                               {
+                                       MemoryStream pong(pack.data,pack.len);
+
+                                       int ip,port;
+                                       port = pong.readShort();
+                                       ip = pong.readLong();
+                                       ip = SWAP4(ip);
+
+
+                                       Host h(ip,port);
+                                       if ((ip) && (port) && (h.globalIP()))
+                                       {
+
+                                               LOG_NETWORK("added pong: %d.%d.%d.%d:%d",ip>>24&0xff,ip>>16&0xff,ip>>8&0xff,ip&0xff,port);
+                                               servMgr->addHost(h,ServHost::T_SERVENT,sys->getTime());
+                                       }
+                                       //return;
+                               } else if (pack.func == GNU_FUNC_HIT)
+                               {
+                                       MemoryStream data(pack.data,pack.len);
+                                       ChanHit hit;
+                                       gnuStream.readHit(data,hit,pack.hops,pack.id);
+                               }
+
+                               //if (gnuStream.packetsIn > 5)  // die if we get too many packets
+                               //      return;
+                       }
+
+                       if((sys->getTime()-lastConnect > 60))
+                               break;
+               }
+
+
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("Relay: %s",e.msg);
+       }
+
+       
+}      
+
+// -----------------------------------
+int Servent::givProc(ThreadInfo *thread)
+{
+//     thread->lock();
+       Servent *sv = (Servent*)thread->data;
+       try 
+       {
+               sv->handshakeGiv(sv->givID);
+               sv->handshakeIncoming();
+
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("GIV: %s",e.msg);
+       }
+
+       sv->kill();
+       sys->endThread(thread);
+       return 0;
+}
+
+// -----------------------------------
+void Servent::handshakeOutgoingPCP(AtomStream &atom, Host &rhost, GnuID &rid, String &agent, bool isTrusted)
+{
+
+       bool nonFW = (servMgr->getFirewall() != ServMgr::FW_ON);
+       bool testFW = (servMgr->getFirewall() == ServMgr::FW_UNKNOWN);
+
+       bool sendBCID = isTrusted && chanMgr->isBroadcasting();
+
+       char tbuf[1024];
+       MemoryStream mem(tbuf, sizeof(tbuf));
+       AtomStream atom2(mem);
+       atom2.writeParent(PCP_HELO,3 + (testFW?1:0) + (nonFW?1:0) + (sendBCID?1:0));
+               atom2.writeString(PCP_HELO_AGENT,PCX_AGENT);
+               atom2.writeInt(PCP_HELO_VERSION,PCP_CLIENT_VERSION);
+               atom2.writeBytes(PCP_HELO_SESSIONID,servMgr->sessionID.id,16);
+               if (nonFW)
+                       atom2.writeShort(PCP_HELO_PORT,servMgr->serverHost.port);
+               if (testFW)
+                       atom2.writeShort(PCP_HELO_PING,servMgr->serverHost.port);
+               if (sendBCID)
+                       atom2.writeBytes(PCP_HELO_BCID,chanMgr->broadcastID.id,16);
+       atom.io.write(tbuf, mem.getPosition());
+
+
+       LOG_DEBUG("PCP outgoing waiting for OLEH..");
+
+       int numc,numd;
+       ID4 id = atom.read(numc,numd);
+       if (id != PCP_OLEH)
+       {
+               LOG_DEBUG("PCP outgoing reply: %s",id.getString().str());
+               atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_BADRESPONSE);
+               throw StreamException("Got unexpected PCP response");
+       }
+
+
+
+       char arg[64];
+
+       GnuID clientID;
+       clientID.clear();
+       rid.clear();
+       int version=0;
+       int disable=0;
+
+       Host thisHost;
+
+       // read OLEH response
+       for(int i=0; i<numc; i++)
+       {
+               int c,dlen;
+               ID4 id = atom.read(c,dlen);
+
+               if (id == PCP_HELO_AGENT)
+               {
+                       atom.readString(arg,sizeof(arg),dlen);
+                       agent.set(arg);
+
+               }else if (id == PCP_HELO_REMOTEIP)
+               {
+                       thisHost.ip = atom.readInt();
+
+               }else if (id == PCP_HELO_PORT)
+               {
+                       thisHost.port = atom.readShort();
+
+               }else if (id == PCP_HELO_VERSION)
+               {
+                       version = atom.readInt();
+
+               }else if (id == PCP_HELO_DISABLE)
+               {
+                       disable = atom.readInt();
+
+               }else if (id == PCP_HELO_SESSIONID)
+               {
+                       atom.readBytes(rid.id,16);
+                       if (rid.isSame(servMgr->sessionID))
+                               throw StreamException("Servent loopback");
+
+               }else
+               {
+                       LOG_DEBUG("PCP handshake skip: %s",id.getString().str());
+                       atom.skip(c,dlen);
+               }
+
+    }
+
+
+       // update server ip/firewall status
+       if (isTrusted)
+       {
+               if (thisHost.isValid())
+               {
+                       if ((servMgr->serverHost.ip != thisHost.ip) && (servMgr->forceIP.isEmpty()))
+                       {
+                               char ipstr[64];
+                               thisHost.toStr(ipstr);
+                               LOG_DEBUG("Got new ip: %s",ipstr);
+                               servMgr->serverHost.ip = thisHost.ip;
+                       }
+
+                       if (servMgr->getFirewall() == ServMgr::FW_UNKNOWN)
+                       {
+                               if (thisHost.port && thisHost.globalIP())
+                                       servMgr->setFirewall(ServMgr::FW_OFF);
+                               else
+                                       servMgr->setFirewall(ServMgr::FW_ON);
+                       }
+               }
+
+               if (disable == 1)
+               {
+                       LOG_ERROR("client disabled: %d",disable);
+                       servMgr->isDisabled = true;             
+               }else
+               {
+                       servMgr->isDisabled = false;            
+               }
+       }
+
+
+
+       if (!rid.isSet())
+       {
+               atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_NOTIDENTIFIED);
+               throw StreamException("Remote host not identified");
+       }
+
+       LOG_DEBUG("PCP Outgoing handshake complete.");
+
+}
+
+// -----------------------------------
+void Servent::handshakeIncomingPCP(AtomStream &atom, Host &rhost, GnuID &rid, String &agent)
+{
+       int numc,numd;
+       ID4 id = atom.read(numc,numd);
+
+
+       if (id != PCP_HELO)
+       {
+               LOG_DEBUG("PCP incoming reply: %s",id.getString().str());
+               atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_BADRESPONSE);
+               throw StreamException("Got unexpected PCP response");
+       }
+
+       char arg[64];
+
+       ID4 osType;
+
+       int version=0;
+
+       int pingPort=0;
+
+       GnuID bcID;
+       GnuID clientID;
+
+       bcID.clear();
+       clientID.clear();
+
+       rhost.port = 0;
+
+       for(int i=0; i<numc; i++)
+       {
+
+               int c,dlen;
+               ID4 id = atom.read(c,dlen);
+
+               if (id == PCP_HELO_AGENT)
+               {
+                       atom.readString(arg,sizeof(arg),dlen);
+                       agent.set(arg);
+
+               }else if (id == PCP_HELO_VERSION)
+               {
+                       version = atom.readInt();
+
+               }else if (id == PCP_HELO_SESSIONID)
+               {
+                       atom.readBytes(rid.id,16);
+                       if (rid.isSame(servMgr->sessionID))
+                               throw StreamException("Servent loopback");
+
+               }else if (id == PCP_HELO_BCID)
+               {
+                       atom.readBytes(bcID.id,16);
+
+               }else if (id == PCP_HELO_OSTYPE)
+               {
+                       osType = atom.readInt();
+               }else if (id == PCP_HELO_PORT)
+               {
+                       rhost.port = atom.readShort();
+               }else if (id == PCP_HELO_PING)
+               {
+                       pingPort = atom.readShort();
+               }else
+               {
+                       LOG_DEBUG("PCP handshake skip: %s",id.getString().str());
+                       atom.skip(c,dlen);
+               }
+
+    }
+
+       if (version)
+               LOG_DEBUG("Incoming PCP is %s : v%d", agent.cstr(),version);
+
+
+       if (!rhost.globalIP() && servMgr->serverHost.globalIP())
+               rhost.ip = servMgr->serverHost.ip;
+
+       if (pingPort)
+       {
+               char ripStr[64];
+               rhost.toStr(ripStr);
+               LOG_DEBUG("Incoming firewalled test request: %s ", ripStr);
+               rhost.port = pingPort;
+               if (!rhost.globalIP() || !pingHost(rhost,rid))
+                       rhost.port = 0;
+       }
+
+       if (servMgr->isRoot)
+       {
+               if (bcID.isSet())
+               {
+                       if (bcID.getFlags() & 1)        // private
+                       {
+                               BCID *bcid = servMgr->findValidBCID(bcID);
+                               if (!bcid || (bcid && !bcid->valid))
+                               {
+                                       atom.writeParent(PCP_OLEH,1);
+                                       atom.writeInt(PCP_HELO_DISABLE,1);
+                                       throw StreamException("Client is banned");
+                               }
+                       }
+               }
+       }
+
+
+       char tbuf[1024];
+       MemoryStream mem(tbuf, sizeof(tbuf));
+       AtomStream atom2(mem);
+       atom2.writeParent(PCP_OLEH,5);
+               atom2.writeString(PCP_HELO_AGENT,PCX_AGENT);
+               atom2.writeBytes(PCP_HELO_SESSIONID,servMgr->sessionID.id,16);
+               atom2.writeInt(PCP_HELO_VERSION,PCP_CLIENT_VERSION);
+               atom2.writeInt(PCP_HELO_REMOTEIP,rhost.ip);
+               atom2.writeShort(PCP_HELO_PORT,rhost.port);
+
+       if (version)
+       {
+               if (version < PCP_CLIENT_MINVERSION)
+               {
+                       atom2.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_BADAGENT);
+                       atom.io.write(tbuf, mem.getPosition());
+                       throw StreamException("Agent is not valid");
+               }
+       }
+
+       if (!rid.isSet())
+       {
+               atom2.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_NOTIDENTIFIED);
+               atom.io.write(tbuf, mem.getPosition());
+               throw StreamException("Remote host not identified");
+       }
+
+
+
+       if (servMgr->isRoot)
+       {
+               servMgr->writeRootAtoms(atom2,false);
+       }
+
+       atom.io.write(tbuf, mem.getPosition());
+
+       LOG_DEBUG("PCP Incoming handshake complete.");
+
+}
+
+// -----------------------------------
+void Servent::processIncomingPCP(bool suggestOthers)
+{
+       PCPStream::readVersion(*sock);
+
+
+       AtomStream atom(*sock);
+       Host rhost = sock->host;
+
+       handshakeIncomingPCP(atom,rhost,remoteID,agent);
+
+
+       bool alreadyConnected = (servMgr->findConnection(Servent::T_COUT,remoteID)!=NULL)
+                                                       || (servMgr->findConnection(Servent::T_CIN,remoteID)!=NULL);
+       bool unavailable = servMgr->controlInFull();
+       bool offair = !servMgr->isRoot && !chanMgr->isBroadcasting();
+
+       char rstr[64];
+       rhost.toStr(rstr);
+
+       if (unavailable || alreadyConnected || offair)
+       {
+               int error;
+
+               if (alreadyConnected)
+                       error = PCP_ERROR_QUIT+PCP_ERROR_ALREADYCONNECTED;
+               else if (unavailable)
+                       error = PCP_ERROR_QUIT+PCP_ERROR_UNAVAILABLE;
+               else if (offair)
+                       error = PCP_ERROR_QUIT+PCP_ERROR_OFFAIR;
+               else 
+                       error = PCP_ERROR_QUIT;
+
+
+               if (suggestOthers)
+               {
+
+                       ChanHit best;
+                       ChanHitSearch chs;
+
+                       int cnt=0;
+                       for(int i=0; i<8; i++)
+                       {
+                               best.init();
+
+                               // find best hit on this network                        
+                               if (!rhost.globalIP())
+                               {
+                                       chs.init();
+                                       chs.matchHost = servMgr->serverHost;
+                                       chs.waitDelay = 2;
+                                       chs.excludeID = remoteID;
+                                       chs.trackersOnly = true;
+                                       chs.useBusyControls = false;
+                                       if (chanMgr->pickHits(chs))
+                                               best = chs.best[0];
+                               }
+
+                               // find best hit on same network                        
+                               if (!best.host.ip)
+                               {
+                                       chs.init();
+                                       chs.matchHost = rhost;
+                                       chs.waitDelay = 2;
+                                       chs.excludeID = remoteID;
+                                       chs.trackersOnly = true;
+                                       chs.useBusyControls = false;
+                                       if (chanMgr->pickHits(chs))
+                                               best = chs.best[0];
+                               }
+
+                               // else find best hit on other networks
+                               if (!best.host.ip)
+                               {
+                                       chs.init();
+                                       chs.waitDelay = 2;
+                                       chs.excludeID = remoteID;
+                                       chs.trackersOnly = true;
+                                       chs.useBusyControls = false;
+                                       if (chanMgr->pickHits(chs))
+                                               best = chs.best[0];
+                               }
+
+                               if (!best.host.ip)
+                                       break;
+                               
+                               GnuID noID;
+                               noID.clear();
+                               best.writeAtoms(atom,noID);
+                               cnt++;
+                       }
+                       if (cnt)
+                       {
+                               LOG_DEBUG("Sent %d tracker(s) to %s",cnt,rstr);
+                       }
+                       else if (rhost.port)
+                       {
+                               // send push request to best firewalled tracker on other network
+                               chs.init();
+                               chs.waitDelay = 30;
+                               chs.excludeID = remoteID;
+                               chs.trackersOnly = true;
+                               chs.useFirewalled = true;
+                               chs.useBusyControls = false;
+                               if (chanMgr->pickHits(chs))
+                               {
+                                       best = chs.best[0];
+                                       GnuID noID;
+                                       noID.clear();
+                                       int cnt = servMgr->broadcastPushRequest(best,rhost,noID,Servent::T_CIN);
+                                       LOG_DEBUG("Broadcasted tracker push request to %d clients for %s",cnt,rstr);
+                               }
+                       }else
+                       {
+                               LOG_DEBUG("No available trackers");
+                       }
+               }
+
+
+               LOG_ERROR("Sending QUIT to incoming: %d",error);
+
+               atom.writeInt(PCP_QUIT,error);
+               return;         
+       }
+       
+
+       type = T_CIN;
+       setStatus(S_CONNECTED);
+
+       atom.writeInt(PCP_OK,0);
+
+       // ask for update
+       atom.writeParent(PCP_ROOT,1);
+               atom.writeParent(PCP_ROOT_UPDATE,0);
+
+       pcpStream = new PCPStream(remoteID);
+
+       int error = 0;
+       BroadcastState bcs;
+       while (!error && thread.active && !sock->eof())
+       {
+               error = pcpStream->readPacket(*sock,bcs);
+               sys->sleepIdle();
+
+               if (!servMgr->isRoot && !chanMgr->isBroadcasting())
+                       error = PCP_ERROR_OFFAIR;
+               if (peercastInst->isQuitting)
+                       error = PCP_ERROR_SHUTDOWN;
+       }
+
+       pcpStream->flush(*sock);
+
+       error += PCP_ERROR_QUIT;
+       atom.writeInt(PCP_QUIT,error);
+
+       LOG_DEBUG("PCP Incoming to %s closed: %d",rstr,error);
+
+}
+
+// -----------------------------------
+int Servent::outgoingProc(ThreadInfo *thread)
+{
+//     thread->lock();
+       LOG_DEBUG("COUT started");
+
+       Servent *sv = (Servent*)thread->data;
+               
+       GnuID noID;
+       noID.clear();
+       sv->pcpStream = new PCPStream(noID);
+
+       while (sv->thread.active)
+       {
+               sv->setStatus(S_WAIT);
+
+               if (chanMgr->isBroadcasting() && servMgr->autoServe)
+               {
+                       ChanHit bestHit;
+                       ChanHitSearch chs;
+                       char ipStr[64];
+
+                       do
+                       {
+                               bestHit.init();
+
+                               if (servMgr->rootHost.isEmpty())
+                                       break;
+
+                               if (sv->pushSock)
+                               {
+                                       sv->sock = sv->pushSock;
+                                       sv->pushSock = NULL;
+                                       bestHit.host = sv->sock->host;
+                                       break;
+                               }
+
+                               GnuID noID;
+                               noID.clear();
+                               ChanHitList *chl = chanMgr->findHitListByID(noID);
+                               if (chl)
+                               {
+                                       // find local tracker
+                                       chs.init();
+                                       chs.matchHost = servMgr->serverHost;
+                                       chs.waitDelay = MIN_TRACKER_RETRY;
+                                       chs.excludeID = servMgr->sessionID;
+                                       chs.trackersOnly = true;
+                                       if (!chl->pickHits(chs))
+                                       {
+                                               // else find global tracker
+                                               chs.init();
+                                               chs.waitDelay = MIN_TRACKER_RETRY;
+                                               chs.excludeID = servMgr->sessionID;
+                                               chs.trackersOnly = true;
+                                               chl->pickHits(chs);
+                                       }
+
+                                       if (chs.numResults)
+                                       {
+                                               bestHit = chs.best[0];
+                                       }
+                               }
+
+
+                               unsigned int ctime = sys->getTime();
+
+                               if ((!bestHit.host.ip) && ((ctime-chanMgr->lastYPConnect) > MIN_YP_RETRY))
+                               {
+                                       bestHit.host.fromStrName(servMgr->rootHost.cstr(),DEFAULT_PORT);
+                                       bestHit.yp = true;
+                                       chanMgr->lastYPConnect = ctime;
+                               }
+                               sys->sleepIdle();
+
+                       }while (!bestHit.host.ip && (sv->thread.active));
+
+
+                       if (!bestHit.host.ip)           // give up
+                       {
+                               LOG_ERROR("COUT giving up");
+                               break;
+                       }
+
+
+                       bestHit.host.toStr(ipStr);
+
+                       int error=0;
+                       try 
+                       {
+
+                               LOG_DEBUG("COUT to %s: Connecting..",ipStr);
+
+                               if (!sv->sock)
+                               {
+                                       sv->setStatus(S_CONNECTING);
+                                       sv->sock = sys->createSocket();
+                                       if (!sv->sock)
+                                               throw StreamException("Unable to create socket");
+                                       sv->sock->open(bestHit.host);
+                                       sv->sock->connect();
+
+                               }
+
+                               sv->sock->setReadTimeout(30000);
+                               AtomStream atom(*sv->sock);
+
+                               sv->setStatus(S_HANDSHAKE);
+
+                               Host rhost = sv->sock->host;
+                               atom.writeInt(PCP_CONNECT,1);
+                               handshakeOutgoingPCP(atom,rhost,sv->remoteID,sv->agent,bestHit.yp);
+
+                               sv->setStatus(S_CONNECTED);
+
+                               LOG_DEBUG("COUT to %s: OK",ipStr);
+
+                               sv->pcpStream->init(sv->remoteID);
+
+                               BroadcastState bcs;
+                               bcs.servent_id = sv->servent_id;
+                               error = 0;
+                               while (!error && sv->thread.active && !sv->sock->eof() && servMgr->autoServe)
+                               {
+                                       error = sv->pcpStream->readPacket(*sv->sock,bcs);
+
+                                       sys->sleepIdle();
+
+                                       if (!chanMgr->isBroadcasting())
+                                               error = PCP_ERROR_OFFAIR;
+                                       if (peercastInst->isQuitting)
+                                               error = PCP_ERROR_SHUTDOWN;
+
+                                       if (sv->pcpStream->nextRootPacket)
+                                               if (sys->getTime() > (sv->pcpStream->nextRootPacket+30))
+                                                       error = PCP_ERROR_NOROOT;
+                               }
+                               sv->setStatus(S_CLOSING);
+
+                               sv->pcpStream->flush(*sv->sock);
+
+                               error += PCP_ERROR_QUIT;
+                               atom.writeInt(PCP_QUIT,error);
+
+                               LOG_ERROR("COUT to %s closed: %d",ipStr,error);
+
+                       }catch(TimeoutException &e)
+                       {
+                               LOG_ERROR("COUT to %s: timeout (%s)",ipStr,e.msg);
+                               sv->setStatus(S_TIMEOUT);
+                       }catch(StreamException &e)
+                       {
+                               LOG_ERROR("COUT to %s: %s",ipStr,e.msg);
+                               sv->setStatus(S_ERROR);
+                       }
+
+                       try
+                       {
+                               if (sv->sock)
+                               {
+                                       sv->sock->close();
+                                       delete sv->sock;
+                                       sv->sock = NULL;
+                               }
+
+                       }catch(StreamException &) {}
+
+                       // don`t discard this hit if we caused the disconnect (stopped broadcasting)
+                       if (error != (PCP_ERROR_QUIT+PCP_ERROR_OFFAIR))
+                               chanMgr->deadHit(bestHit);
+
+               }
+
+               sys->sleepIdle();
+       }
+
+       sv->kill();
+       sys->endThread(thread);
+       LOG_DEBUG("COUT ended");
+       return 0;
+}
+// -----------------------------------
+int Servent::incomingProc(ThreadInfo *thread)
+{
+//     thread->lock();
+
+       Servent *sv = (Servent*)thread->data;
+       
+       char ipStr[64];
+       sv->sock->host.toStr(ipStr);
+
+       try 
+       {
+               sv->handshakeIncoming();
+       }catch(HTTPException &e)
+       {
+               try
+               {
+                       sv->sock->writeLine(e.msg);
+                       if (e.code == 401)
+                               sv->sock->writeLine("WWW-Authenticate: Basic realm=\"PeerCast\"");
+                       sv->sock->writeLine("");
+               }catch(StreamException &){}
+               LOG_ERROR("Incoming from %s: %s",ipStr,e.msg);
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("Incoming from %s: %s",ipStr,e.msg);
+       }
+
+
+       sv->kill();
+       sys->endThread(thread);
+       return 0;
+}
+// -----------------------------------
+void Servent::processServent()
+{
+       setStatus(S_HANDSHAKE);
+
+       handshakeIn();
+
+       if (!sock)
+               throw StreamException("Servent has no socket");
+
+       processGnutella();
+}
+
+// -----------------------------------
+void Servent::processStream(bool doneHandshake,ChanInfo &chanInfo)
+{      
+       if (!doneHandshake)
+       {
+               setStatus(S_HANDSHAKE);
+
+               if (!handshakeStream(chanInfo))
+                       return;
+       }
+
+       if (chanInfo.id.isSet())
+       {
+
+               chanID = chanInfo.id;
+
+               LOG_CHANNEL("Sending channel: %s ",ChanInfo::getProtocolStr(outputProtocol));
+
+               if (!waitForChannelHeader(chanInfo))
+                       throw StreamException("Channel not ready");
+
+               servMgr->totalStreams++;
+
+               Host host = sock->host;
+               host.port = 0;  // force to 0 so we ignore the incoming port
+
+               Channel *ch = chanMgr->findChannelByID(chanID);
+               if (!ch)
+                       throw StreamException("Channel not found");
+
+               if (outputProtocol == ChanInfo::SP_HTTP)
+               {
+                       if ((addMetadata) && (chanMgr->icyMetaInterval))
+                               sendRawMetaChannel(chanMgr->icyMetaInterval);
+                       else 
+                               sendRawChannel(true,true);
+
+               }else if (outputProtocol == ChanInfo::SP_MMS)
+               {
+                       if (nsSwitchNum)
+                       {
+                               sendRawChannel(true,true);
+                       }else
+                       {
+                               sendRawChannel(true,false);
+                       }
+
+               }else if (outputProtocol  == ChanInfo::SP_PCP)
+               {
+                       sendPCPChannel();
+
+               } else if (outputProtocol  == ChanInfo::SP_PEERCAST)
+               {
+                       sendPeercastChannel();
+               }
+       }
+
+       setStatus(S_CLOSING);
+}
+
+// -----------------------------------------
+#if 0
+// debug
+               FileStream file;
+               file.openReadOnly("c://test.mp3");
+
+               LOG_DEBUG("raw file read");
+               char buf[4000];
+               int cnt=0;
+               while (!file.eof())
+               {
+                       LOG_DEBUG("send %d",cnt++);
+                       file.read(buf,sizeof(buf));
+                       sock->write(buf,sizeof(buf));
+
+               }
+               file.close();
+               LOG_DEBUG("raw file sent");
+
+       return;
+// debug
+#endif
+// -----------------------------------
+bool Servent::waitForChannelHeader(ChanInfo &info)
+{
+       for(int i=0; i<30*10; i++)
+       {
+               Channel *ch = chanMgr->findChannelByID(info.id);
+               if (!ch)
+                       return false;
+
+               if (ch->isPlaying() && (ch->rawData.writePos>0))
+                       return true;
+
+               if (!thread.active || !sock->active())
+                       break;
+               sys->sleep(100);
+       }
+       return false;
+}
+// -----------------------------------
+void Servent::sendRawChannel(bool sendHead, bool sendData)
+{
+       try
+       {
+
+               sock->setWriteTimeout(DIRECT_WRITE_TIMEOUT*1000);
+
+               Channel *ch = chanMgr->findChannelByID(chanID);
+               if (!ch)
+                       throw StreamException("Channel not found");
+
+               setStatus(S_CONNECTED);
+
+               LOG_DEBUG("Starting Raw stream of %s at %d",ch->info.name.cstr(),streamPos);
+
+               if (sendHead)
+               {
+                       ch->headPack.writeRaw(*sock);
+                       streamPos = ch->headPack.pos + ch->headPack.len;
+                       LOG_DEBUG("Sent %d bytes header ",ch->headPack.len);
+               }
+
+               if (sendData)
+               {
+
+                       unsigned int streamIndex = ch->streamIndex;
+                       unsigned int connectTime = sys->getTime();
+                       unsigned int lastWriteTime = connectTime;
+
+                       while ((thread.active) && sock->active())
+                       {
+                               ch = chanMgr->findChannelByID(chanID);
+
+                               if (ch)
+                               {
+
+                                       if (streamIndex != ch->streamIndex)
+                                       {
+                                               streamIndex = ch->streamIndex;
+                                               streamPos = ch->headPack.pos;
+                                               LOG_DEBUG("sendRaw got new stream index");
+                                       }
+
+                                       ChanPacket rawPack;
+                                       if (ch->rawData.findPacket(streamPos,rawPack))
+                                       {
+                                               if (syncPos != rawPack.sync)
+                                                       LOG_ERROR("Send skip: %d",rawPack.sync-syncPos);
+                                               syncPos = rawPack.sync+1;
+
+                                               if ((rawPack.type == ChanPacket::T_DATA) || (rawPack.type == ChanPacket::T_HEAD))
+                                               {
+                                                       rawPack.writeRaw(*sock);
+                                                       lastWriteTime = sys->getTime();
+                                               }
+
+                                               if (rawPack.pos < streamPos)
+                                                       LOG_DEBUG("raw: skip back %d",rawPack.pos-streamPos);
+                                               streamPos = rawPack.pos+rawPack.len;
+                                       } else if (sock->readReady()) {
+                                               char c;
+                                               int error = sock->readUpto(&c, 1);
+                                               if (error == 0) sock->close();
+                                       }
+                               }
+
+                               if ((sys->getTime()-lastWriteTime) > DIRECT_WRITE_TIMEOUT)
+                                       throw TimeoutException();
+
+                               sys->sleepIdle();
+                       }
+               }
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("Stream channel: %s",e.msg);
+       }
+}
+
+#if 0
+// -----------------------------------
+void Servent::sendRawMultiChannel(bool sendHead, bool sendData)
+{
+       try
+       {
+               unsigned int chanStreamIndex[ChanMgr::MAX_CHANNELS];
+               unsigned int chanStreamPos[ChanMgr::MAX_CHANNELS];
+               GnuID chanIDs[ChanMgr::MAX_CHANNELS];
+               int numChanIDs=0;
+               for(int i=0; i<ChanMgr::MAX_CHANNELS; i++)
+               {
+                       Channel *ch = &chanMgr->channels[i];
+                       if (ch->isPlaying())
+                               chanIDs[numChanIDs++]=ch->info.id;
+               }
+
+
+
+               setStatus(S_CONNECTED);
+
+
+               if (sendHead)
+               {
+                       for(int i=0; i<numChanIDs; i++)
+                       {
+                               Channel *ch = chanMgr->findChannelByID(chanIDs[i]);
+                               if (ch)
+                               {
+                                       LOG_DEBUG("Starting RawMulti stream: %s",ch->info.name.cstr());
+                                       ch->headPack.writeRaw(*sock);
+                                       chanStreamPos[i] = ch->headPack.pos + ch->headPack.len;
+                                       chanStreamIndex[i] = ch->streamIndex;
+                                       LOG_DEBUG("Sent %d bytes header",ch->headPack.len);
+
+                               }
+                       }
+               }
+
+               if (sendData)
+               {
+
+                       unsigned int connectTime=sys->getTime();
+
+                       while ((thread.active) && sock->active())
+                       {
+
+                               for(int i=1; i<numChanIDs; i++)
+                               {
+                                       Channel *ch = chanMgr->findChannelByID(chanIDs[i]);
+                                       if (ch)
+                                       {
+                                               if (chanStreamIndex[i] != ch->streamIndex)
+                                               {
+                                                       chanStreamIndex[i] = ch->streamIndex;
+                                                       chanStreamPos[i] = ch->headPack.pos;
+                                                       LOG_DEBUG("sendRawMulti got new stream index for chan %d",i);
+                                               }
+
+                                               ChanPacket rawPack;
+                                               if (ch->rawData.findPacket(chanStreamPos[i],rawPack))
+                                               {
+                                                       if ((rawPack.type == ChanPacket::T_DATA) || (rawPack.type == ChanPacket::T_HEAD))
+                                                               rawPack.writeRaw(*sock);
+
+
+                                                       if (rawPack.pos < chanStreamPos[i])
+                                                               LOG_DEBUG("raw: skip back %d",rawPack.pos-chanStreamPos[i]);
+                                                       chanStreamPos[i] = rawPack.pos+rawPack.len;
+
+
+                                                       //LOG("raw at %d: %d %d",streamPos,ch->rawData.getStreamPos(ch->rawData.firstPos),ch->rawData.getStreamPos(ch->rawData.lastPos));
+                                               }                                               
+                                       }
+                                       break;
+                               }
+                               
+
+                               sys->sleepIdle();
+                       }
+               }
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("Stream channel: %s",e.msg);
+       }
+}
+#endif
+
+// -----------------------------------
+void Servent::sendRawMetaChannel(int interval)
+{
+
+       try
+       {
+               Channel *ch = chanMgr->findChannelByID(chanID);
+               if (!ch)
+                       throw StreamException("Channel not found");
+
+               sock->setWriteTimeout(DIRECT_WRITE_TIMEOUT*1000);
+
+               setStatus(S_CONNECTED);
+
+               LOG_DEBUG("Starting Raw Meta stream of %s (metaint: %d) at %d",ch->info.name.cstr(),interval,streamPos);
+
+
+               String lastTitle,lastURL;
+
+               int             lastMsgTime=sys->getTime();
+               bool    showMsg=true;
+
+               char buf[16384];
+               int bufPos=0;
+
+               if ((interval > sizeof(buf)) || (interval < 1))
+                       throw StreamException("Bad ICY Meta Interval value");
+
+               unsigned int connectTime = sys->getTime();
+               unsigned int lastWriteTime = connectTime;
+
+               streamPos = 0;          // raw meta channel has no header (its MP3)
+
+               while ((thread.active) && sock->active())
+               {
+                       ch = chanMgr->findChannelByID(chanID);
+
+                       if (ch)
+                       {
+
+                               ChanPacket rawPack;
+                               if (ch->rawData.findPacket(streamPos,rawPack))
+                               {
+
+                                       if (syncPos != rawPack.sync)
+                                               LOG_ERROR("Send skip: %d",rawPack.sync-syncPos);
+                                       syncPos = rawPack.sync+1;
+
+                                       MemoryStream mem(rawPack.data,rawPack.len);
+
+                                       if (rawPack.type == ChanPacket::T_DATA)
+                                       {
+
+                                               int len = rawPack.len;
+                                               char *p = rawPack.data;
+                                               while (len)
+                                               {
+                                                       int rl = len;
+                                                       if ((bufPos+rl) > interval)
+                                                               rl = interval-bufPos;
+                                                       memcpy(&buf[bufPos],p,rl);
+                                                       bufPos+=rl;
+                                                       p+=rl;
+                                                       len-=rl;
+
+                                                       if (bufPos >= interval)
+                                                       {
+                                                               bufPos = 0;     
+                                                               sock->write(buf,interval);
+                                                               lastWriteTime = sys->getTime();
+
+                                                               if (chanMgr->broadcastMsgInterval)
+                                                                       if ((sys->getTime()-lastMsgTime) >= chanMgr->broadcastMsgInterval)
+                                                                       {
+                                                                               showMsg ^= true;
+                                                                               lastMsgTime = sys->getTime();
+                                                                       }
+
+                                                               String *metaTitle = &ch->info.track.title;
+                                                               if (!ch->info.comment.isEmpty() && (showMsg))
+                                                                       metaTitle = &ch->info.comment;
+
+
+                                                               if (!metaTitle->isSame(lastTitle) || !ch->info.url.isSame(lastURL))
+                                                               {
+
+                                                                       char tmp[1024];
+                                                                       String title,url;
+
+                                                                       title = *metaTitle;
+                                                                       url = ch->info.url;
+
+                                                                       title.convertTo(String::T_META);
+                                                                       url.convertTo(String::T_META);
+
+                                                                       sprintf(tmp,"StreamTitle='%s';StreamUrl='%s';\0",title.cstr(),url.cstr());
+                                                                       int len = ((strlen(tmp) + 15+1) / 16);
+                                                                       sock->writeChar(len);
+                                                                       sock->write(tmp,len*16);
+
+                                                                       lastTitle = *metaTitle;
+                                                                       lastURL = ch->info.url;
+
+                                                                       LOG_DEBUG("StreamTitle: %s, StreamURL: %s",lastTitle.cstr(),lastURL.cstr());
+
+                                                               }else
+                                                               {
+                                                                       sock->writeChar(0);                                     
+                                                               }
+
+                                                       }
+                                               }
+                                       }
+                                       streamPos = rawPack.pos + rawPack.len;
+                               }
+                       }
+                       if ((sys->getTime()-lastWriteTime) > DIRECT_WRITE_TIMEOUT)
+                               throw TimeoutException();
+
+                       sys->sleepIdle();
+
+               }
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("Stream channel: %s",e.msg);
+       }
+}
+// -----------------------------------
+void Servent::sendPeercastChannel()
+{
+       try
+       {
+               setStatus(S_CONNECTED);
+
+               Channel *ch = chanMgr->findChannelByID(chanID);
+               if (!ch)
+                       throw StreamException("Channel not found");
+
+               LOG_DEBUG("Starting PeerCast stream: %s",ch->info.name.cstr());
+
+               sock->writeTag("PCST");
+
+               ChanPacket pack;
+
+               ch->headPack.writePeercast(*sock);
+
+               pack.init(ChanPacket::T_META,ch->insertMeta.data,ch->insertMeta.len,ch->streamPos);
+               pack.writePeercast(*sock);
+       
+               streamPos = 0;
+               unsigned int syncPos=0;
+               while ((thread.active) && sock->active())
+               {
+                       ch = chanMgr->findChannelByID(chanID);
+                       if (ch)
+                       {
+
+                               ChanPacket rawPack;
+                               if (ch->rawData.findPacket(streamPos,rawPack))
+                               {
+                                       if ((rawPack.type == ChanPacket::T_DATA) || (rawPack.type == ChanPacket::T_HEAD))
+                                       {
+                                               sock->writeTag("SYNC");
+                                               sock->writeShort(4);
+                                               sock->writeShort(0);
+                                               sock->write(&syncPos,4);
+                                               syncPos++;
+
+                                               rawPack.writePeercast(*sock);
+                                       }
+                                       streamPos = rawPack.pos + rawPack.len;
+                               }
+                       }
+                       sys->sleepIdle();
+               }
+
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("Stream channel: %s",e.msg);
+       }
+}
+
+//WLock canStreamLock;
+
+// -----------------------------------
+void Servent::sendPCPChannel()
+{
+       bool skipCheck = false;
+
+       Channel *ch = chanMgr->findChannelByID(chanID);
+       if (!ch)
+               throw StreamException("Channel not found");
+
+       AtomStream atom(*sock);
+
+       pcpStream = new PCPStream(remoteID);
+       int error=0;
+
+       try
+       {
+
+               LOG_DEBUG("Starting PCP stream of channel at %d",streamPos);
+
+
+//             setStatus(S_CONNECTED);
+
+               //canStreamLock.on();
+               //thread.active = canStream(ch);
+               //setStatus(S_CONNECTED);
+               //canStreamLock.off();
+
+               lastSkipTime = 0;
+               lastSkipCount = 0;
+               waitPort = 0;
+
+               if (thread.active){
+                       atom.writeParent(PCP_CHAN,3 + ((sendHeader)?1:0));
+                               atom.writeBytes(PCP_CHAN_ID,chanID.id,16);
+                               ch->info.writeInfoAtoms(atom);
+                               ch->info.writeTrackAtoms(atom);
+                               if (sendHeader)
+                               {
+                                       atom.writeParent(PCP_CHAN_PKT,3);
+                                               atom.writeID4(PCP_CHAN_PKT_TYPE,PCP_CHAN_PKT_HEAD);
+                                               atom.writeInt(PCP_CHAN_PKT_POS,ch->headPack.pos);
+                                               atom.writeBytes(PCP_CHAN_PKT_DATA,ch->headPack.data,ch->headPack.len);
+
+                                       streamPos = ch->headPack.pos+ch->headPack.len;
+                                       LOG_DEBUG("Sent %d bytes header",ch->headPack.len);
+                               }
+               }
+
+               unsigned int streamIndex = ch->streamIndex;
+
+               ChanPacket rawPack;
+               char pbuf[ChanPacket::MAX_DATALEN*3];
+               MemoryStream mems(pbuf,sizeof(pbuf));
+               AtomStream atom2(mems);
+
+               while (thread.active)
+               {
+
+                       Channel *ch = chanMgr->findChannelByID(chanID);
+
+                       if (ch)
+                       {
+
+                               if (streamIndex != ch->streamIndex)
+                               {
+                                       streamIndex = ch->streamIndex;
+                                       streamPos = ch->headPack.pos;
+                                       LOG_DEBUG("sendPCPStream got new stream index");                                                
+                               }
+
+                               mems.rewind();
+
+                               if (ch->rawData.findPacket(streamPos,rawPack))
+                               {
+                                       if ((streamPos < rawPack.pos) && !rawPack.skip){
+                                               if (skipCheck){
+                                                       char tmp[32];
+                                                       getHost().IPtoStr(tmp);
+                                                       LOG_NETWORK("##### send skipping ##### %d (%d, %d) -> %s", (rawPack.pos - streamPos), streamPos, rawPack.pos, tmp);
+
+                                                       if (sys->getTime() == lastSkipTime) {
+                                                               LOG_DEBUG("##### skip all buffer");
+                                                               streamPos = ch->rawData.getLatestPos();
+                                                               continue;
+                                                       }
+
+                                                       lastSkipTime = sys->getTime();
+                                                       lastSkipCount++;
+                                               } else {
+                                                       skipCheck = true;
+                                               }
+                                       }
+
+                                       if (rawPack.type == ChanPacket::T_HEAD)
+                                       {
+                                               atom2.writeParent(PCP_CHAN,2);
+                                                       atom2.writeBytes(PCP_CHAN_ID,chanID.id,16);
+                                                       atom2.writeParent(PCP_CHAN_PKT,3);
+                                                               atom2.writeID4(PCP_CHAN_PKT_TYPE,PCP_CHAN_PKT_HEAD);
+                                                               atom2.writeInt(PCP_CHAN_PKT_POS,rawPack.pos);
+                                                               atom2.writeBytes(PCP_CHAN_PKT_DATA,rawPack.data,rawPack.len);
+
+                                               sock->write(pbuf, mems.getPosition());
+                                       }else if (rawPack.type == ChanPacket::T_DATA)
+                                       {
+                                               atom2.writeParent(PCP_CHAN,2);
+                                                       atom2.writeBytes(PCP_CHAN_ID,chanID.id,16);
+                                                       atom2.writeParent(PCP_CHAN_PKT,3);
+                                                               atom2.writeID4(PCP_CHAN_PKT_TYPE,PCP_CHAN_PKT_DATA);
+                                                               atom2.writeInt(PCP_CHAN_PKT_POS,rawPack.pos);
+                                                               atom2.writeBytes(PCP_CHAN_PKT_DATA,rawPack.data,rawPack.len);
+
+#ifdef WIN32
+                                               sock->bufferingWrite(pbuf, mems.getPosition());
+                                               lastSkipTime = sock->bufList.lastSkipTime;
+                                               lastSkipCount = sock->bufList.skipCount;
+#else
+                                               sock->write(pbuf, mems.getPosition());
+#endif
+                                       }
+
+                                       if (rawPack.pos < streamPos)
+                                               LOG_DEBUG("pcp: skip back %d",rawPack.pos-streamPos);
+
+                                       //LOG_DEBUG("Sending %d-%d (%d,%d,%d)",rawPack.pos,rawPack.pos+rawPack.len,ch->streamPos,ch->rawData.getLatestPos(),ch->rawData.getOldestPos());
+
+                                       streamPos = rawPack.pos+rawPack.len;
+                               }
+                       } else {
+                               pcpStream->flush(*sock);
+                               throw StreamException("Channel not found");
+                       }
+
+#ifdef WIN32
+                       sock->bufferingWrite(NULL, 0);
+                       lastSkipTime = sock->bufList.lastSkipTime;
+                       lastSkipCount = sock->bufList.skipCount;
+#endif
+                       BroadcastState bcs;
+                       bcs.servent_id = servent_id;
+//                     error = pcpStream->readPacket(*sock,bcs);
+                       do {
+                               error = pcpStream->readPacket(*sock,bcs);
+                               if (error)
+                                       throw StreamException("PCP exception");
+                       } while (sock->readReady() || pcpStream->outData.numPending());
+
+                       sys->sleepIdle();
+
+               }
+
+               LOG_DEBUG("PCP channel stream closed normally.");
+
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("Stream channel: %s",e.msg);
+       }
+
+       try
+       {
+               atom.writeInt(PCP_QUIT,error);
+       }catch(StreamException &) {}
+
+}
+
+// -----------------------------------
+int Servent::serverProc(ThreadInfo *thread)
+{
+//     thread->lock();
+
+
+       Servent *sv = (Servent*)thread->data;
+
+       try 
+       {
+               if (!sv->sock)
+                       throw StreamException("Server has no socket");
+
+               sv->setStatus(S_LISTENING);
+
+
+               char servIP[64];
+               sv->sock->host.toStr(servIP);
+
+               if (servMgr->isRoot)
+                       LOG_DEBUG("Root Server started: %s",servIP);
+               else
+                       LOG_DEBUG("Server started: %s",servIP);
+               
+
+               while ((thread->active) && (sv->sock->active()))
+               {
+                       if (servMgr->numActiveOnPort(sv->sock->host.port) < servMgr->maxServIn)
+                       {
+                               ClientSocket *cs = sv->sock->accept();
+                               if (cs)
+                               {       
+                                       LOG_DEBUG("accepted incoming");
+                                       Servent *ns = servMgr->allocServent();
+                                       if (ns)
+                                       {
+                                               servMgr->lastIncoming = sys->getTime();
+                                               ns->servPort = sv->sock->host.port;
+                                               ns->networkID = servMgr->networkID;
+                                               ns->initIncoming(cs,sv->allow);
+                                       }else
+                                               LOG_ERROR("Out of servents");
+                               }
+                       }
+                       sys->sleep(100);
+               }
+       }catch(StreamException &e)
+       {
+               LOG_ERROR("Server Error: %s:%d",e.msg,e.err);
+       }
+
+       
+       LOG_DEBUG("Server stopped");
+
+       sv->kill();
+       sys->endThread(thread);
+       return 0;
+}
+// -----------------------------------
+bool   Servent::writeVariable(Stream &s, const String &var)
+{
+       char buf[1024];
+
+       if (var == "type")
+               strcpy(buf,getTypeStr());
+       else if (var == "status")
+               strcpy(buf,getStatusStr());
+       else if (var == "address")
+       {
+               if (servMgr->enableGetName) //JP-EX s
+               {
+                       getHost().toStr(buf);
+                       char h_ip[64];
+                       Host h = getHost();
+                       h.toStr(h_ip);
+
+/*                     ChanHitList *hits[ChanMgr::MAX_HITLISTS];
+                       int numHits=0;
+                       for(int i=0; i<ChanMgr::MAX_HITLISTS; i++)
+                       {
+                               ChanHitList *chl = &chanMgr->hitlists[i];
+                               if (chl->isUsed())
+                                       hits[numHits++] = chl;
+                       }
+                       bool ishit,isfw;
+                       ishit = isfw = false;
+                       int numRelay = 0;
+                       if (numHits) 
+                       {
+                               for(int k=0; k<numHits; k++)
+                               {
+                                       ChanHitList *chl = hits[k];
+                                       if (chl->isUsed())
+                                       {
+                                               for (int j=0; j<ChanHitList::MAX_HITS; j++)
+                                               {
+                                                       ChanHit *hit = &chl->hits[j];
+                                                       if (hit->host.isValid() && (h.ip == hit->host.ip))
+                                                       {
+                                                               ishit = true;
+                                                               if (hit->firewalled)
+                                                                       isfw = true;
+                                                               numRelay += hit->numRelays;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       strcpy(buf,"");
+                       if (ishit == true)
+                       {
+                               if (isfw == true)
+                               {
+                                       if (numRelay== 0)
+                                               strcat(buf,"<font color=red>");
+                                       else 
+                                               strcat(buf,"<font color=orange>");
+                               }
+                               else
+                                       strcat(buf,"<font color=green>");
+                       }
+                       strcat(buf,h_ip);
+                       char h_name[128];
+                       if (ClientSocket::getHostname(h_name,h.ip))
+                       {
+                               strcat(buf,"[");
+                               strcat(buf,h_name);
+                               strcat(buf,"]");
+                       }
+                       if (ishit == true) 
+                       {
+                               strcat(buf,"</font>");
+                       }
+               } //JP-EX e*/
+
+
+                       bool isfw = false;
+                       bool isRelay = true;
+                       int numRelay = 0;
+                       ChanHitList *chl = chanMgr->findHitListByID(chanID);
+                       if (chl){
+                               ChanHit *hit = chl->hit;
+                               while(hit){
+                                       if (hit->host.isValid() && (h.ip == hit->host.ip)){
+                                               isfw = hit->firewalled;
+                                               isRelay = hit->relay;
+                                               numRelay = hit->numRelays;
+                                               break;
+                                       }
+                                       hit = hit->next;
+                               }
+                       }
+                       strcpy(buf, "");
+                       if (isfw){
+                               if (numRelay == 0){
+                                       strcat(buf,"<font color=red>");
+                               } else {
+                                       strcat(buf,"<font color=orange>");
+                               }
+                       } else {
+                               if (!isRelay){
+                                       if (numRelay==0){
+                                               strcpy(buf,"<font color=purple>");
+                                       } else {
+                                               strcpy(buf,"<font color=blue>");
+                                       }
+                               } else {
+                                       strcpy(buf,"<font color=green>");
+                               }
+                       }
+                       strcat(buf,h_ip);
+                       char h_name[128];
+                       if (ClientSocket::getHostname(h_name,h.ip))
+                       {
+                               strcat(buf,"[");
+                               strcat(buf,h_name);
+                               strcat(buf,"]");
+                       }
+                       strcat(buf,"</font>");
+               }
+               else 
+                       getHost().toStr(buf);
+       }
+       else if (var == "agent")
+               strcpy(buf,agent.cstr());
+       else if (var == "bitrate")
+       {
+               if (sock)
+               {
+                       unsigned int tot = sock->bytesInPerSec+sock->bytesOutPerSec;
+                       sprintf(buf,"%.1f",BYTES_TO_KBPS(tot));
+               }else
+                       strcpy(buf,"0");
+       }else if (var == "uptime")
+       {
+               String uptime;
+               if (lastConnect)
+                       uptime.setFromStopwatch(sys->getTime()-lastConnect);
+               else
+                       uptime.set("-");
+               strcpy(buf,uptime.cstr());
+       }else if (var.startsWith("gnet."))
+       {
+
+               float ctime = (float)(sys->getTime()-lastConnect);
+               if (var == "gnet.packetsIn")
+                       sprintf(buf,"%d",gnuStream.packetsIn);
+               else if (var == "gnet.packetsInPerSec")
+                       sprintf(buf,"%.1f",ctime>0?((float)gnuStream.packetsIn)/ctime:0);
+               else if (var == "gnet.packetsOut")
+                       sprintf(buf,"%d",gnuStream.packetsOut);
+               else if (var == "gnet.packetsOutPerSec")
+                       sprintf(buf,"%.1f",ctime>0?((float)gnuStream.packetsOut)/ctime:0);
+               else if (var == "gnet.normQueue")
+                       sprintf(buf,"%d",outPacketsNorm.numPending());
+               else if (var == "gnet.priQueue")
+                       sprintf(buf,"%d",outPacketsPri.numPending());
+               else if (var == "gnet.flowControl")
+                       sprintf(buf,"%d",flowControl?1:0);
+               else if (var == "gnet.routeTime")
+               {
+                       int nr = seenIDs.numUsed();
+                       unsigned int tim = sys->getTime()-seenIDs.getOldest();
+               
+                       String tstr;
+                       tstr.setFromStopwatch(tim);
+
+                       if (nr)
+                               strcpy(buf,tstr.cstr());
+                       else
+                               strcpy(buf,"-");
+               }
+               else
+                       return false;
+
+       }else
+               return false;
+
+       s.writeString(buf);
+
+       return true;
+}
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/servent.h b/c:/Git/PeerCast.root/PeerCast/core/common/servent.h
new file mode 100644 (file)
index 0000000..b1c2241
--- /dev/null
@@ -0,0 +1,298 @@
+// ------------------------------------------------
+// File : servent.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+#ifndef _SERVENT_H
+#define _SERVENT_H
+
+// ----------------------------------
+#include "socket.h"
+#include "sys.h"
+#include "gnutella.h"
+#include "channel.h"
+#include "http.h"
+#include "rtsp.h"
+#include "pcp.h"
+
+class HTML;
+
+class AtomStream;
+
+// ----------------------------------
+// Servent handles the actual connection between clients
+class Servent
+{
+public:
+
+       enum 
+       {
+               MAX_HASH = 500,                 // max. amount of packet hashes Servents can store
+               MAX_OUTPACKETS = 32             // max. output packets per queue (normal/priority)
+       };
+
+    enum TYPE                                  
+    {
+               T_NONE,                                 // Not allocated
+        T_INCOMING,                            // Unknown incoming
+        T_SERVER,                              // The main server 
+               T_RELAY,                                // Outgoing relay
+               T_DIRECT,                               // Outgoing direct connection
+               T_COUT,                                 // PCP out connection
+               T_CIN,                                  // PCP in connection
+               T_PGNU                                  // old protocol connection              
+    };
+
+    enum STATUS
+    {
+        S_NONE,
+        S_CONNECTING,
+        S_PROTOCOL,
+        S_HANDSHAKE,
+        S_CONNECTED,
+        S_CLOSING,
+               S_LISTENING,
+               S_TIMEOUT,
+               S_REFUSED,
+               S_VERIFIED,
+               S_ERROR,
+               S_WAIT,
+               S_FREE
+    };
+
+       enum PROTOCOL
+       {
+               P_UNKNOWN,
+               P_GNUTELLA06,
+               P_PCP
+       };
+
+
+       enum SORT
+       {
+               SORT_NAME = 0,
+               SORT_BITRATE,
+               SORT_LISTENERS,
+               SORT_HOSTS,
+               SORT_TYPE,
+               SORT_GENRE
+       };
+
+       enum ALLOW
+       {
+               ALLOW_HTML              = 0x01,
+               ALLOW_BROADCAST = 0x02,
+               ALLOW_NETWORK   = 0x04,
+               ALLOW_DIRECT    = 0x08,
+               ALLOW_ALL               = 0xff
+       };
+
+       Servent(int);
+       ~Servent();
+
+       void    reset();
+    bool       initServer(Host &);
+    void       initIncoming(ClientSocket *,unsigned int);
+    void       initOutgoing(TYPE);
+       void    initGIV(Host &, GnuID &);
+       void    initPCP(Host &);
+
+       void    checkFree();
+
+
+
+
+       //      funcs for handling status/type
+       void    setStatus(STATUS);
+       static char *   getTypeStr(Servent::TYPE t) {return typeMsgs[t];}
+       char *  getTypeStr() {return getTypeStr(type);}
+       char *  getStatusStr() {return statusMsgs[status];}
+       int             getOutput();
+       void    addBytes(unsigned int);
+       bool    isOlderThan(Servent *s)
+       {
+               if (s)
+               {
+                       unsigned int t = sys->getTime();
+                       return ((t-lastConnect) > (t-s->lastConnect));
+               }else
+                       return true;
+       }
+
+
+
+       // static funcs that do the actual work in the servent thread
+       static  THREAD_PROC             serverProc(ThreadInfo *);
+       static  THREAD_PROC             outgoingProc(ThreadInfo *);
+       static  THREAD_PROC             incomingProc(ThreadInfo *);
+       static  THREAD_PROC             givProc(ThreadInfo *);
+       static  THREAD_PROC             pcpProc(ThreadInfo *);
+       static  THREAD_PROC             fetchProc(ThreadInfo *);
+
+       static bool     pingHost(Host &,GnuID &);
+
+       bool    getLocalURL(char *);
+       bool    getLocalTypeURL(char *, ChanInfo::TYPE);
+
+       // various types of handshaking are needed
+       void    handshakePLS(ChanHitList **, int, bool);
+       void    handshakePLS(ChanInfo &, bool);
+
+       void    handshakeHTML(char *);
+       void    handshakeXML();
+       void    handshakeCMD(char *);
+       bool    handshakeAuth(HTTP &,const char *,bool);
+       void    handshakeIn();
+       void    handshakeOut();
+
+
+       void    processOutPCP();
+       void    processOutChannel();
+
+       bool    handshakeStream(ChanInfo &);
+       void    handshakeGiv(GnuID &);
+
+       void    handshakeICY(Channel::SRC_TYPE,bool);
+       void    handshakeIncoming();
+       void    handshakePOST();
+       void    handshakeRTSP(RTSP &);
+       void    handshakeHTTP(HTTP &,bool);
+
+       void    handshakeRemoteFile(const char *);
+       void    handshakeLocalFile(const char *);
+
+       static void     handshakeOutgoingPCP(AtomStream &,Host &,GnuID &,String &,bool);
+       static void     handshakeIncomingPCP(AtomStream &,Host &,GnuID &,String &);
+
+       void    processIncomingPCP(bool);
+
+       bool    waitForChannelHeader(ChanInfo &);
+       ChanInfo        findChannel(char *str,ChanInfo &);
+
+       bool    writeVariable(Stream &, const String &);
+
+
+       // the "mainloop" of servents 
+       void    processGnutella();
+       void    processRoot();
+       void    processServent();
+       void    processStream(bool,ChanInfo &);
+       void    processPCP(bool,bool);
+
+       bool    procAtoms(AtomStream &);
+       void    procRootAtoms(AtomStream &,int);
+       void    procHeloAtoms(AtomStream &,int,bool);
+       void    procGetAtoms(AtomStream &,int);
+
+       void    triggerChannel(char *,ChanInfo::PROTOCOL,bool);
+       void    sendPeercastChannel();
+       void    sendRawChannel(bool,bool);
+//     void    sendRawMultiChannel(bool,bool);
+       void    sendRawMetaChannel(int);
+       void    sendPCPChannel();
+       void    checkPCPComms(Channel *, AtomStream &);
+
+       static void     readICYHeader(HTTP &, ChanInfo &, char *);
+       bool    canStream(Channel *);
+
+       bool    isConnected() {return status == S_CONNECTED;}
+       bool    isListening() {return status == S_LISTENING;}
+
+       bool    isAllowed(int);
+       bool    isFiltered(int);
+
+       // connection handling funcs
+       void    createSocket();
+       void    kill();
+       void    abort();
+       bool    isPrivate();
+       bool    isLocal();
+
+
+       Host    getHost();
+
+       bool    outputPacket(GnuPacket &,bool);
+       bool    hasSeenPacket(GnuPacket &p) {return seenIDs.contains(p.id);}
+       bool    acceptGIV(ClientSocket *);
+       bool    sendPacket(ChanPacket &,GnuID &,GnuID &,GnuID &,Servent::TYPE);
+
+
+       TYPE type;
+       STATUS status;
+
+       static char *statusMsgs[],*typeMsgs[];
+       GnuStream gnuStream;
+       GnuPacket pack;
+       unsigned int    lastConnect,lastPing,lastPacket;
+       String  agent;
+
+       GnuIDList       seenIDs;
+       GnuID   networkID;
+       int             serventIndex;
+
+       GnuID   remoteID;
+
+       GnuID   chanID;
+
+       GnuID   givID;
+
+       ThreadInfo      thread;
+
+
+       char    loginPassword[64];
+       char    loginMount[64];
+
+       bool    priorityConnect;
+       bool    addMetadata;
+       int             nsSwitchNum;
+
+       unsigned        int allow;
+
+    ClientSocket *sock,*pushSock;
+
+       WLock   lock;
+
+       bool    sendHeader;
+       unsigned int syncPos,streamPos;
+       int             servPort;
+
+       ChanInfo::PROTOCOL      outputProtocol;
+
+       GnuPacketBuffer outPacketsNorm,outPacketsPri;
+
+       unsigned int bytesPerSecond;
+       bool    flowControl;
+
+       Servent *next;
+
+       PCPStream *pcpStream;
+       Cookie  cookie;
+
+       int servent_id;
+       unsigned int lastSkipTime;
+       unsigned int lastSkipCount;
+       unsigned int waitPort;
+
+       int channel_id;
+};
+
+extern char *nextCGIarg(char *cp, char *cmd, char *arg);
+
+
+#endif
+
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/servhs.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/servhs.cpp
new file mode 100644 (file)
index 0000000..8e352bf
--- /dev/null
@@ -0,0 +1,1954 @@
+// ------------------------------------------------
+// File : servhs.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             Servent handshaking, TODO: should be in its own class
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+#include <stdlib.h>
+#include "servent.h"
+#include "servmgr.h"
+#include "html.h"
+#include "stats.h"
+#include "peercast.h"
+#include "pcp.h"
+#include "version2.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// -----------------------------------
+static void termArgs(char *str)
+{
+       if (str)
+       {
+               int slen = strlen(str);
+               for(int i=0; i<slen; i++)
+                       if (str[i]=='&') str[i] = 0;
+       }
+}
+// -----------------------------------
+char *nextCGIarg(char *cp, char *cmd, char *arg)
+{
+       if (!*cp)
+               return NULL;
+
+       int cnt=0;
+
+       // fetch command
+       while (*cp)
+       {
+               char c = *cp++;
+               if (c == '=')
+                       break;
+               else
+                       *cmd++ = c;
+
+               cnt++;
+               if (cnt >= (MAX_CGI_LEN-1))
+                       break;
+       }
+       *cmd = 0;
+
+       cnt=0;
+       // fetch arg
+       while (*cp)
+       {
+               char c = *cp++;
+               if (c == '&')
+                       break;
+               else
+                       *arg++ = c;
+
+               cnt++;
+               if (cnt >= (MAX_CGI_LEN-1))
+                       break;
+       }
+       *arg = 0;
+
+       return cp;
+}
+// -----------------------------------
+bool getCGIargBOOL(char *a)
+{
+       return (strcmp(a,"1")==0);
+}
+// -----------------------------------
+int getCGIargINT(char *a)
+{
+       return atoi(a);
+}
+
+// -----------------------------------
+void Servent::handshakeHTTP(HTTP &http, bool isHTTP)
+{
+       char *in = http.cmdLine;
+
+       if (http.isRequest("GET /"))
+       {
+               char *fn = in+4;
+
+               char *pt = strstr(fn,HTTP_PROTO1);
+               if (pt)
+                       pt[-1] = 0;
+
+               if (strncmp(fn,"/admin?",7)==0)
+               {
+                       if (!isAllowed(ALLOW_HTML))
+                               throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+
+                       LOG_DEBUG("Admin client");
+                       handshakeCMD(fn+7);
+
+               }else if (strncmp(fn,"/http/",6)==0)
+               {
+                       String dirName = fn+6;
+
+                       if (!isAllowed(ALLOW_HTML))
+                               throw HTTPException(HTTP_SC_UNAVAILABLE,503);                   
+
+                       if (!handshakeAuth(http,fn,false))
+                               throw HTTPException(HTTP_SC_UNAUTHORIZED,401);                  
+
+
+                       handshakeRemoteFile(dirName);
+
+
+               }else if (strncmp(fn,"/html/",6)==0)
+               {
+                       String dirName = fn+1;
+
+                       if (!isAllowed(ALLOW_HTML))
+                               throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+                       if (handshakeAuth(http,fn,true))
+                               handshakeLocalFile(dirName);
+
+
+               }else if (strncmp(fn,"/admin/?",8)==0)
+               {
+                       if (!isAllowed(ALLOW_HTML))
+                               throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+                       LOG_DEBUG("Admin client");
+                       handshakeCMD(fn+8);
+
+               }else if (strncmp(fn,"/admin.cgi",10)==0)
+               {
+                       if (!isAllowed(ALLOW_BROADCAST))
+                               throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+                       char *pwdArg = getCGIarg(fn,"pass=");
+                       char *songArg = getCGIarg(fn,"song=");
+                       char *mountArg = getCGIarg(fn,"mount=");
+                       char *urlArg = getCGIarg(fn,"url=");
+
+                       if (pwdArg && songArg)
+                       {
+                               int i;
+                               int slen = strlen(fn);
+                               for(i=0; i<slen; i++)
+                                       if (fn[i]=='&') fn[i] = 0;
+
+                               Channel *c=chanMgr->channel;
+                               while (c)
+                               {
+                                       if ((c->status == Channel::S_BROADCASTING) &&
+                                          (c->info.contentType == ChanInfo::T_MP3) )
+                                       {
+                                               // if we have a mount point then check for it, otherwise update all channels.
+                                               bool match=true;
+
+                                               if (mountArg)
+                                                       match = strcmp(c->mount,mountArg)==0;
+
+                                               if (match)
+                                               {
+                                                       ChanInfo newInfo = c->info;
+                                                       newInfo.track.title.set(songArg,String::T_ESC);
+                                                       newInfo.track.title.convertTo(String::T_UNICODE);
+
+                                                       if (urlArg)
+                                                               if (urlArg[0])
+                                                                       newInfo.track.contact.set(urlArg,String::T_ESC);
+                                                       LOG_CHANNEL("Channel Shoutcast update: %s",songArg);
+                                                       c->updateInfo(newInfo);
+                                               }
+                                       }
+                                       c=c->next;
+                               }
+                       }
+
+               }else if (strncmp(fn,"/pls/",5)==0)
+               {
+
+                       if (!sock->host.isLocalhost())
+                               if (!isAllowed(ALLOW_DIRECT) || !isFiltered(ServFilter::F_DIRECT))
+                                       throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+                       
+                       ChanInfo info;
+                       if (servMgr->getChannel(fn+5,info,isPrivate()))
+                               handshakePLS(info,false);
+                       else
+                               throw HTTPException(HTTP_SC_NOTFOUND,404);
+
+               }else if (strncmp(fn,"/stream/",8)==0)
+               {
+
+                       if (!sock->host.isLocalhost())
+                               if (!isAllowed(ALLOW_DIRECT) || !isFiltered(ServFilter::F_DIRECT))
+                                       throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+                       triggerChannel(fn+8,ChanInfo::SP_HTTP,isPrivate());
+
+                       
+               }else if (strncmp(fn,"/channel/",9)==0)
+               {
+
+                       if (!sock->host.isLocalhost())
+                               if (!isAllowed(ALLOW_NETWORK) || !isFiltered(ServFilter::F_NETWORK))
+                                       throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+                       triggerChannel(fn+9,ChanInfo::SP_PCP,false);
+
+               }else 
+               {
+                       while (http.nextHeader());
+                       http.writeLine(HTTP_SC_FOUND);
+                       http.writeLineF("Location: /%s/index.html",servMgr->htmlPath);
+                       http.writeLine("");
+               }
+       }
+       else if (http.isRequest("POST /"))
+       {
+               char *fn = in+5;
+
+               char *pt = strstr(fn,HTTP_PROTO1);
+               if (pt)
+                       pt[-1] = 0;
+
+               if (strncmp(fn,"/pls/",5)==0)
+               {
+
+                       if (!sock->host.isLocalhost())
+                               if (!isAllowed(ALLOW_DIRECT) || !isFiltered(ServFilter::F_DIRECT))
+                                       throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+                       
+                       ChanInfo info;
+                       if (servMgr->getChannel(fn+5,info,isPrivate()))
+                               handshakePLS(info,false);
+                       else
+                               throw HTTPException(HTTP_SC_NOTFOUND,404);
+
+               }else if (strncmp(fn,"/stream/",8)==0)
+               {
+
+                       if (!sock->host.isLocalhost())
+                               if (!isAllowed(ALLOW_DIRECT) || !isFiltered(ServFilter::F_DIRECT))
+                                       throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+                       triggerChannel(fn+8,ChanInfo::SP_HTTP,isPrivate());
+
+               }else if (strncmp(fn,"/admin",7)==0)
+               {
+                       if (!isAllowed(ALLOW_HTML))
+                               throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+
+                       LOG_DEBUG("Admin client");
+                       while(http.nextHeader()){
+                               LOG_DEBUG("%s",http.cmdLine);
+                       }
+                       char buf[8192];
+                       if (sock->readLine(buf, sizeof(buf)) != 0){
+                               handshakeCMD(buf);
+                       }
+
+               }else 
+               {
+                       while (http.nextHeader());
+                       http.writeLine(HTTP_SC_FOUND);
+                       http.writeLineF("Location: /%s/index.html",servMgr->htmlPath);
+                       http.writeLine("");
+               }
+       }else if (http.isRequest("GIV"))
+       {
+               HTTP http(*sock);
+       
+               while (http.nextHeader()) ;
+
+               if (!isAllowed(ALLOW_NETWORK))
+                       throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+               GnuID id;
+               id.clear();
+
+               char *idstr = strstr(in,"/");
+               if (idstr)
+                       id.fromStr(idstr+1);
+
+               char ipstr[64];
+               sock->host.toStr(ipstr);
+
+               if (id.isSet())
+               {
+                       // at the moment we don`t really care where the GIV came from, so just give to chan. no. if its waiting.
+                       Channel *ch = chanMgr->findChannelByID(id);
+
+                       if (!ch)
+                               throw HTTPException(HTTP_SC_NOTFOUND,404);
+
+                       if (!ch->acceptGIV(sock))
+                               throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+               
+                       LOG_DEBUG("Accepted GIV channel %s from: %s",idstr,ipstr);
+
+                       sock=NULL;                                      // release this servent but dont close socket.  
+               }else 
+               {
+
+                       if (!servMgr->acceptGIV(sock))
+                               throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+                       LOG_DEBUG("Accepted GIV PCP from: %s",ipstr);
+                       sock=NULL;                                      // release this servent but dont close socket.  
+               }
+
+       }else if (http.isRequest(PCX_PCP_CONNECT))
+       {
+
+               if (!isAllowed(ALLOW_NETWORK) || !isFiltered(ServFilter::F_NETWORK))
+                       throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+               
+               processIncomingPCP(true);
+
+       }else if (http.isRequest("PEERCAST CONNECT"))
+       {
+               if (!isAllowed(ALLOW_NETWORK) || !isFiltered(ServFilter::F_NETWORK))
+                       throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+               LOG_DEBUG("PEERCAST client");
+               processServent();
+
+       }else if (http.isRequest("SOURCE"))
+       {
+               if (!isAllowed(ALLOW_BROADCAST))
+                       throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+               char *mount = NULL;
+
+               char *ps;
+               if (ps=strstr(in,"ICE/1.0"))
+               {
+                       mount = in+7;
+                       *ps = 0;
+                       LOG_DEBUG("ICE 1.0 client to %s",mount?mount:"unknown");
+               }else{
+                       mount = in+strlen(in);
+                       while (*--mount)
+                               if (*mount == '/')
+                               {
+                                       mount[-1] = 0; // password preceeds
+                                       break;
+                               }
+                       strcpy(loginPassword,in+7);
+                       
+                       LOG_DEBUG("ICY client: %s %s",loginPassword,mount?mount:"unknown");
+               }
+
+               if (mount)
+                       strcpy(loginMount,mount);
+
+               handshakeICY(Channel::SRC_ICECAST,isHTTP);
+               sock = NULL;    // socket is taken over by channel, so don`t close it
+
+       }else if (http.isRequest(servMgr->password))
+       {
+               if (!isAllowed(ALLOW_BROADCAST))
+                       throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+               strcpy(loginPassword,servMgr->password);        // pwd already checked
+
+               sock->writeLine("OK2");
+               sock->writeLine("icy-caps:11");
+               sock->writeLine("");
+               LOG_DEBUG("ShoutCast client");
+
+               handshakeICY(Channel::SRC_SHOUTCAST,isHTTP);
+               sock = NULL;    // socket is taken over by channel, so don`t close it
+
+       }else
+       {
+               throw HTTPException(HTTP_SC_BADREQUEST,400);
+       }
+
+}
+// -----------------------------------
+bool Servent::canStream(Channel *ch)
+{
+       if (ch==NULL)
+               return false;
+
+       if (servMgr->isDisabled)
+               return false;
+
+       if (!isPrivate())
+       {
+               Channel *c = chanMgr->channel;
+               int noRelay = 0;
+               unsigned int needRate = 0;
+               unsigned int allRate = 0;
+               while(c){
+                       if (c->isPlaying()){
+                               allRate += c->info.bitrate * c->localRelays();
+                               if ((c != ch) && (c->localRelays() == 0)){
+                                       if(!isIndexTxt(c))      // for PCRaw (relay)
+                                               noRelay++;
+                                       needRate+=c->info.bitrate;
+                               }
+                       }
+                       c = c->next;
+               }
+               int diff = servMgr->maxRelays - servMgr->numStreams(Servent::T_RELAY,false);
+               if (ch->localRelays()){
+                       if (noRelay > diff){
+                               noRelay = diff;
+                       }
+               } else {
+                       noRelay = 0;
+                       needRate = 0;
+               }
+
+               // for PCRaw (relay) start.
+               bool force_off = true;
+
+               if(isIndexTxt(ch))
+                       force_off = false;
+               // for PCRaw (relay) end.
+
+               LOG_DEBUG("Relay check: Max=%d Now=%d Need=%d ch=%d",
+                       servMgr->maxBitrateOut, allRate, needRate, ch->info.bitrate);
+               if  (   !ch->isPlaying()
+                               || ch->isFull()
+//                             || servMgr->bitrateFull(needRate+ch->getBitrate())
+                               || (allRate + needRate + ch->info.bitrate > servMgr->maxBitrateOut)
+                               || ((type == T_RELAY) && servMgr->relaysFull() && force_off)    // for PCRaw (relay) (force_off)
+                               || ((type == T_RELAY) && (((servMgr->numStreams(Servent::T_RELAY,false) + noRelay) >= servMgr->maxRelays)) && force_off)        // for PCRaw (relay) (force_off)
+                               || ((type == T_DIRECT) && servMgr->directFull())
+               ){
+                       LOG_DEBUG("Relay check: NG");
+                       return false;
+               }
+       }
+
+       LOG_DEBUG("Relay check: OK");
+       return true;
+}
+// -----------------------------------
+void Servent::handshakeIncoming()
+{
+
+       setStatus(S_HANDSHAKE);
+
+       char buf[2048];
+       sock->readLine(buf,sizeof(buf));
+
+       char sb[64];
+       sock->host.toStr(sb);
+
+
+       if (stristr(buf,RTSP_PROTO1))
+       {
+               LOG_DEBUG("RTSP from %s '%s'",sb,buf);
+               RTSP rtsp(*sock);
+               rtsp.initRequest(buf);
+               handshakeRTSP(rtsp);
+       }else if (stristr(buf,HTTP_PROTO1))
+       {
+               LOG_DEBUG("HTTP from %s '%s'",sb,buf);
+               HTTP http(*sock);
+               http.initRequest(buf);
+               handshakeHTTP(http,true);
+       }else
+       {
+               LOG_DEBUG("Connect from %s '%s'",sb,buf);
+               HTTP http(*sock);
+               http.initRequest(buf);
+               handshakeHTTP(http,false);
+       }
+
+}
+// -----------------------------------
+void Servent::triggerChannel(char *str, ChanInfo::PROTOCOL proto,bool relay)   
+{
+
+       ChanInfo info;
+//     WLockBlock lb(&(chanMgr->channellock));
+
+//     LOG_DEBUG("----------triggerChannel LOCK ON");
+//     lb.on();
+       servMgr->getChannel(str,info,relay);
+//     LOG_DEBUG("==========triggerChannel LOCK OFF");
+//     lb.off();
+
+       if (proto == ChanInfo::SP_PCP)
+               type = T_RELAY;
+       else
+               type = T_DIRECT;
+
+       outputProtocol = proto;
+
+       processStream(false,info);
+
+}
+// -----------------------------------
+void writePLSHeader(Stream &s, PlayList::TYPE type)
+{
+       s.writeLine(HTTP_SC_OK);
+       s.writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT);
+
+       const char *content;
+       switch(type)
+       {
+               case PlayList::T_PLS:
+                       content = MIME_XM3U;
+                       break;
+               case PlayList::T_ASX:
+                       content = MIME_ASX;
+                       break;
+               case PlayList::T_RAM:
+                       content = MIME_RAM;
+                       break;
+               default:
+                       content = MIME_TEXT;
+                       break;
+       }
+       s.writeLineF("%s %s",HTTP_HS_CONTENT,content);
+    s.writeLine("Content-Disposition: inline");
+    s.writeLine("Cache-Control: private" );
+       s.writeLineF("%s %s",HTTP_HS_CONNECTION,"close");
+
+       s.writeLine("");
+}
+
+// -----------------------------------
+void Servent::handshakePLS(ChanInfo &info, bool doneHandshake)
+{
+       char url[256];
+
+       char in[128];
+
+       if (!doneHandshake)
+               while (sock->readLine(in,128));
+
+
+       if (getLocalTypeURL(url,info.contentType))
+       {
+
+               PlayList::TYPE type;
+
+               if ((info.contentType == ChanInfo::T_WMA) || (info.contentType == ChanInfo::T_WMV))
+                       type = PlayList::T_ASX;
+               else if (info.contentType == ChanInfo::T_OGM)
+                       type = PlayList::T_RAM;
+               else
+                       type = PlayList::T_PLS;
+
+               writePLSHeader(*sock,type);
+
+               PlayList *pls;
+
+               pls = new PlayList(type,1);
+
+               pls->addChannel(url,info);
+
+               pls->write(*sock);
+
+               delete pls;
+       }
+}
+// -----------------------------------
+void Servent::handshakePLS(ChanHitList **cl, int num, bool doneHandshake)
+{
+       char url[256];
+       char in[128];
+
+       if (!doneHandshake)
+               while (sock->readLine(in,128));
+
+       if (getLocalURL(url))
+       {
+               writePLSHeader(*sock,PlayList::T_SCPLS);
+
+               PlayList *pls;
+
+               pls = new PlayList(PlayList::T_SCPLS,num);
+
+               for(int i=0; i<num; i++)
+                       pls->addChannel(url,cl[i]->info);
+
+               pls->write(*sock);
+
+               delete pls;
+       }
+}
+// -----------------------------------
+bool Servent::getLocalURL(char *str)
+{
+       if (!sock)
+               throw StreamException("Not connected");
+
+
+       char ipStr[64];
+
+       Host h;
+       
+       if (sock->host.localIP())
+               h = sock->getLocalHost();
+       else
+               h = servMgr->serverHost;
+
+       h.port = servMgr->serverHost.port;
+
+       h.toStr(ipStr);
+
+       sprintf(str,"http://%s",ipStr);                 
+       return true;
+}
+
+// -----------------------------------
+bool Servent::getLocalTypeURL(char *str, ChanInfo::TYPE type)
+{
+       if (!sock)
+               throw StreamException("Not connected");
+
+
+       char ipStr[64];
+
+       Host h;
+       
+       if (sock->host.localIP())
+               h = sock->getLocalHost();
+       else
+               h = servMgr->serverHost;
+
+       h.port = servMgr->serverHost.port;
+
+       h.toStr(ipStr);
+       switch(type) {
+               case ChanInfo::T_WMA:
+               case ChanInfo::T_WMV:
+                       sprintf(str,"mms://%s",ipStr);  
+                       break;
+               default:
+                       sprintf(str,"http://%s",ipStr); 
+       }
+       return true;
+}
+// -----------------------------------
+// Warning: testing RTSP/RTP stuff below.
+// .. moved over to seperate app now.
+// -----------------------------------
+void Servent::handshakePOST()
+{
+       char tmp[1024];
+    while (sock->readLine(tmp,sizeof(tmp)))
+               LOG_DEBUG("POST: %s",tmp);
+
+       throw HTTPException(HTTP_SC_BADREQUEST,400);
+}
+
+
+// -----------------------------------
+void Servent::handshakeRTSP(RTSP &rtsp)
+{
+       throw HTTPException(HTTP_SC_BADREQUEST,400);
+}
+// -----------------------------------
+bool Servent::handshakeAuth(HTTP &http,const char *args,bool local)
+{
+       char user[1024],pass[1024];
+       user[0] = pass[0] = 0;
+
+       char *pwd  = getCGIarg(args, "pass=");
+
+       if ((pwd) && strlen(servMgr->password))
+       {
+               String tmp = pwd;
+               char *as = strstr(tmp.cstr(),"&");
+               if (as) *as = 0;
+               if (strcmp(tmp,servMgr->password)==0)
+               {
+                   while (http.nextHeader());
+                       return true;
+               }
+       }
+
+       Cookie gotCookie;
+       cookie.clear();
+
+    while (http.nextHeader())
+       {
+               char *arg = http.getArgStr();
+               if (!arg)
+                       continue;
+
+               switch (servMgr->authType)
+               {
+                       case ServMgr::AUTH_HTTPBASIC:
+                               if (http.isHeader("Authorization"))
+                                       http.getAuthUserPass(user,pass);
+                               break;
+                       case ServMgr::AUTH_COOKIE:
+                               if (http.isHeader("Cookie"))
+                               {
+                                       LOG_DEBUG("Got cookie: %s",arg);
+                                       char *idp=arg;
+                                       while ((idp = strstr(idp,"id=")))
+                                       {
+                                               idp+=3;
+                                               gotCookie.set(idp,sock->host.ip);
+                                               if (servMgr->cookieList.contains(gotCookie))
+                                               {
+                                                       LOG_DEBUG("Cookie found");
+                                                       cookie = gotCookie;
+                                                       break;
+                                               }
+
+                                       }
+                               }
+                               break;
+               }
+       }
+
+       if (sock->host.isLocalhost())
+               return true;
+
+
+       switch (servMgr->authType)
+       {
+               case ServMgr::AUTH_HTTPBASIC:
+                               
+                       if ((strcmp(pass,servMgr->password)==0) && strlen(servMgr->password))
+                               return true;
+                       break;
+               case ServMgr::AUTH_COOKIE:
+                       if (servMgr->cookieList.contains(cookie))
+                               return true;
+                       break;
+       }
+
+
+
+       if (servMgr->authType == ServMgr::AUTH_HTTPBASIC)
+       {
+               http.writeLine(HTTP_SC_UNAUTHORIZED);
+               http.writeLine("WWW-Authenticate: Basic realm=\"PeerCast Admin\"");
+       }else if (servMgr->authType == ServMgr::AUTH_COOKIE)
+       {
+               String file = servMgr->htmlPath;
+               file.append("/login.html");
+               if (local)
+                       handshakeLocalFile(file);
+               else
+                       handshakeRemoteFile(file);
+       }
+       
+
+       return false;
+}
+
+// -----------------------------------
+void Servent::handshakeCMD(char *cmd)
+{
+       char result[MAX_CGI_LEN];
+       char arg[MAX_CGI_LEN];
+       char curr[MAX_CGI_LEN];
+
+       char    jumpStr[128];
+       char    *jumpArg=NULL;
+       bool    retHTML=true;
+       strcpy(result,"OK");
+
+       HTTP http(*sock);
+       HTML html("",*sock);
+
+
+       if (!handshakeAuth(http,cmd,true))
+               return;
+
+       try
+       {
+               if (cmpCGIarg(cmd,"cmd=","redirect"))
+               {
+                       char *j = getCGIarg(cmd,"url=");
+                       if (j)
+                       {
+                               termArgs(cmd);
+                               String url;
+                               url.set(j,String::T_ESC);
+                               url.convertTo(String::T_ASCII);
+
+                               if (!url.contains("http://"))
+                                       url.prepend("http://");
+
+                               html.setRefreshURL(url.cstr());
+                               html.startHTML();
+                                       html.addHead();
+                                       html.startBody();
+                                               html.startTagEnd("h3","Please wait...");
+                                       html.end();
+                               html.end();
+
+                       }
+               }else{
+
+                       if (cmpCGIarg(cmd,"cmd=","viewxml"))
+                       {
+
+                               handshakeXML();
+                               retHTML = false;
+                       }else if (cmpCGIarg(cmd,"cmd=","clearlog"))
+                       {
+                               sys->logBuf->clear();
+                               sprintf(jumpStr,"/%s/viewlog.html",servMgr->htmlPath);                                  
+                               jumpArg = jumpStr;
+
+                       }else if (cmpCGIarg(cmd,"cmd=","save"))
+                       {
+
+                               peercastInst->saveSettings();
+
+                               sprintf(jumpStr,"/%s/settings.html",servMgr->htmlPath);                                 
+                               jumpArg = jumpStr;
+                       }else if (cmpCGIarg(cmd,"cmd=","reg"))
+                       {
+                               char idstr[128];
+                               chanMgr->broadcastID.toStr(idstr);
+                               sprintf(jumpStr,"http://www.peercast.org/register/?id=%s",idstr);                                       
+                               jumpArg = jumpStr;
+                       }else if (cmpCGIarg(cmd,"cmd=","edit_bcid"))
+                       {
+                               char *cp = cmd;
+                               GnuID id;
+                               BCID *bcid;
+                               while (cp=nextCGIarg(cp,curr,arg))
+                               {
+                                       if (strcmp(curr,"id")==0)
+                                               id.fromStr(arg);
+                                       else if (strcmp(curr,"del")==0)
+                                               servMgr->removeValidBCID(id);
+                                       else if (strcmp(curr,"valid")==0)
+                                       {
+                                               bcid = servMgr->findValidBCID(id);
+                                               if (bcid)
+                                                       bcid->valid = getCGIargBOOL(arg);
+                                       }
+                               }
+                               peercastInst->saveSettings();
+                               sprintf(jumpStr,"/%s/bcid.html",servMgr->htmlPath);                                     
+                               jumpArg = jumpStr;
+
+                       }else if (cmpCGIarg(cmd,"cmd=","add_bcid"))
+                       {
+                               BCID *bcid = new BCID();
+
+                               char *cp = cmd;
+                               bool result=false;
+                               while (cp=nextCGIarg(cp,curr,arg))
+                               {
+                                       if (strcmp(curr,"id")==0)
+                                               bcid->id.fromStr(arg);
+                                       else if (strcmp(curr,"name")==0)
+                                               bcid->name.set(arg);
+                                       else if (strcmp(curr,"email")==0)
+                                               bcid->email.set(arg);
+                                       else if (strcmp(curr,"url")==0)
+                                               bcid->url.set(arg);
+                                       else if (strcmp(curr,"valid")==0)
+                                               bcid->valid = getCGIargBOOL(arg);
+                                       else if (strcmp(curr,"result")==0)
+                                               result = true;
+
+                               }
+       
+                               LOG_DEBUG("Adding BCID : %s",bcid->name.cstr());                        
+                               servMgr->addValidBCID(bcid);
+                               peercastInst->saveSettings();
+                               if (result)
+                               {
+                                       http.writeLine(HTTP_SC_OK);
+                                       http.writeLine("");
+                                       http.writeString("OK");
+                               }else
+                               {
+                                       sprintf(jumpStr,"/%s/bcid.html",servMgr->htmlPath);                                     
+                                       jumpArg = jumpStr;
+                               }
+
+
+                       }else if (cmpCGIarg(cmd,"cmd=","apply"))
+                       {       
+                               //servMgr->numFilters = 0;
+                               ServFilter *currFilter=servMgr->filters;
+                               bool beginfilt = false;
+
+                               bool brRoot=false;
+                               bool getUpd=false;
+                               int showLog=0;
+                               int allowServer1=0;
+                               int allowServer2=0;
+                               int newPort=servMgr->serverHost.port;
+                               int enableGetName = 0;
+                               int allowConnectPCST = 0;
+
+                               char *cp = cmd;
+                               while (cp=nextCGIarg(cp,curr,arg))
+                               {
+                                       // server
+                                       if (strcmp(curr,"serveractive")==0)
+                                               servMgr->autoServe = getCGIargBOOL(arg);
+                                       else if (strcmp(curr,"port")==0)
+                                               newPort = getCGIargINT(arg);
+                                       else if (strcmp(curr,"icymeta")==0)
+                                       {
+                                               int iv = getCGIargINT(arg);
+                                               if (iv < 0) iv = 0;
+                                               else if (iv > 16384) iv = 16384;
+
+                                               chanMgr->icyMetaInterval = iv;
+
+                                       }else if (strcmp(curr,"passnew")==0)
+                                               strcpy(servMgr->password,arg);
+                                       else if (strcmp(curr,"root")==0)
+                                               servMgr->isRoot = getCGIargBOOL(arg);
+                                       else if (strcmp(curr,"brroot")==0)
+                                               brRoot = getCGIargBOOL(arg);
+                                       else if (strcmp(curr,"getupd")==0)
+                                               getUpd = getCGIargBOOL(arg);
+                                       else if (strcmp(curr,"huint")==0)
+                                               chanMgr->setUpdateInterval(getCGIargINT(arg));
+                                       else if (strcmp(curr,"forceip")==0)
+                                               servMgr->forceIP = arg;
+                                       else if (strcmp(curr,"htmlPath")==0)
+                                       {
+                                               strcpy(servMgr->htmlPath,"html/");
+                                               strcat(servMgr->htmlPath,arg);
+                                       }else if (strcmp(curr,"djmsg")==0)
+                                       {
+                                               String msg;
+                                               msg.set(arg,String::T_ESC);
+                                               msg.convertTo(String::T_UNICODE);
+                                               chanMgr->setBroadcastMsg(msg);
+                                       }
+                                       else if (strcmp(curr,"pcmsg")==0)
+                                       {
+                                               servMgr->rootMsg.set(arg,String::T_ESC);
+                                               servMgr->rootMsg.convertTo(String::T_UNICODE);
+                                       }else if (strcmp(curr,"minpgnu")==0)
+                                               servMgr->minGnuIncoming = atoi(arg);
+                                       else if (strcmp(curr,"maxpgnu")==0)
+                                               servMgr->maxGnuIncoming = atoi(arg);
+                                       
+
+
+                                       // connections
+                                       else if (strcmp(curr,"maxcin")==0)
+                                               servMgr->maxControl = getCGIargINT(arg);
+
+                                       else if (strcmp(curr,"maxup")==0)
+                                               servMgr->maxBitrateOut = getCGIargINT(arg);
+                                       else if (strcmp(curr,"maxrelays")==0)
+                                               servMgr->setMaxRelays(getCGIargINT(arg));
+                                       else if (strcmp(curr,"maxdirect")==0)
+                                               servMgr->maxDirect = getCGIargINT(arg);
+                                       else if (strcmp(curr,"maxrelaypc")==0)
+                                               chanMgr->maxRelaysPerChannel = getCGIargINT(arg);
+                                       else if (strncmp(curr,"filt_",5)==0)
+                                       {
+                                               if (!beginfilt) {
+                                                       servMgr->numFilters = 0;
+                                                       beginfilt = true;
+                                               }
+                                               char *fs = curr+5;
+                                               {
+                                                       if (strncmp(fs,"ip",2)==0)              // ip must be first
+                                                       {
+                                                               currFilter = &servMgr->filters[servMgr->numFilters];
+                                                               currFilter->init();     
+                                                               currFilter->host.fromStrIP(arg,DEFAULT_PORT);
+                                                               if ((currFilter->host.ip) && (servMgr->numFilters < (ServMgr::MAX_FILTERS-1)))
+                                                               {
+                                                                       servMgr->numFilters++;
+                                                                       servMgr->filters[servMgr->numFilters].init();   // clear new entry
+                                                               }
+
+                                                       }else if (strncmp(fs,"bn",2)==0)
+                                                               currFilter->flags |= ServFilter::F_BAN;
+                                                       else if (strncmp(fs,"pr",2)==0)
+                                                               currFilter->flags |= ServFilter::F_PRIVATE;
+                                                       else if (strncmp(fs,"nw",2)==0)
+                                                               currFilter->flags |= ServFilter::F_NETWORK;
+                                                       else if (strncmp(fs,"di",2)==0)
+                                                               currFilter->flags |= ServFilter::F_DIRECT;
+                                               }
+                                       }
+
+                                       // client
+                                       else if (strcmp(curr,"clientactive")==0)
+                                               servMgr->autoConnect = getCGIargBOOL(arg);
+                                       else if (strcmp(curr,"yp")==0)
+                                       {
+                                               if (!PCP_FORCE_YP)
+                                               {
+                                                       String str(arg,String::T_ESC);
+                                                       str.convertTo(String::T_ASCII);
+                                                       servMgr->rootHost = str;
+                                               }
+                                       }
+                                       else if (strcmp(curr,"yp2")==0)
+                                       {
+                                               if (!PCP_FORCE_YP)
+                                               {
+                                                       String str(arg,String::T_ESC);
+                                                       str.convertTo(String::T_ASCII);
+                                                       servMgr->rootHost2 = str;
+                                               }
+                                       }
+                                       else if (strcmp(curr,"deadhitage")==0)
+                                               chanMgr->deadHitAge = getCGIargINT(arg);
+                                       else if (strcmp(curr,"refresh")==0)
+                                               servMgr->refreshHTML = getCGIargINT(arg);
+                                       else if (strcmp(curr,"auth")==0)
+                                       {
+                                               if (strcmp(arg,"cookie")==0)
+                                                       servMgr->authType = ServMgr::AUTH_COOKIE;
+                                               else if (strcmp(arg,"http")==0)
+                                                       servMgr->authType = ServMgr::AUTH_HTTPBASIC;
+
+                                       }else if (strcmp(curr,"expire")==0)
+                                       {
+                                               if (strcmp(arg,"session")==0)
+                                                       servMgr->cookieList.neverExpire = false;
+                                               else if (strcmp(arg,"never")==0)
+                                                       servMgr->cookieList.neverExpire = true;
+                                       }
+
+                                       else if (strcmp(curr,"logDebug")==0)
+                                               showLog |= atoi(arg)?(1<<LogBuffer::T_DEBUG):0;
+                                       else if (strcmp(curr,"logErrors")==0)
+                                               showLog |= atoi(arg)?(1<<LogBuffer::T_ERROR):0;
+                                       else if (strcmp(curr,"logNetwork")==0)
+                                               showLog |= atoi(arg)?(1<<LogBuffer::T_NETWORK):0;
+                                       else if (strcmp(curr,"logChannel")==0)
+                                               showLog |= atoi(arg)?(1<<LogBuffer::T_CHANNEL):0;
+
+                                       else if (strcmp(curr,"allowHTML1")==0)
+                                               allowServer1 |= atoi(arg)?(ALLOW_HTML):0;
+                                       else if (strcmp(curr,"allowNetwork1")==0)
+                                               allowServer1 |= atoi(arg)?(ALLOW_NETWORK):0;
+                                       else if (strcmp(curr,"allowBroadcast1")==0)
+                                               allowServer1 |= atoi(arg)?(ALLOW_BROADCAST):0;
+                                       else if (strcmp(curr,"allowDirect1")==0)
+                                               allowServer1 |= atoi(arg)?(ALLOW_DIRECT):0;
+
+                                       else if (strcmp(curr,"allowHTML2")==0)
+                                               allowServer2 |= atoi(arg)?(ALLOW_HTML):0;
+                                       else if (strcmp(curr,"allowBroadcast2")==0)
+                                               allowServer2 |= atoi(arg)?(ALLOW_BROADCAST):0;
+
+                                       // JP-EX
+                                       else if (strcmp(curr, "autoRelayKeep") ==0)
+                                                       servMgr->autoRelayKeep = getCGIargINT(arg);
+                                       else if (strcmp(curr, "autoMaxRelaySetting") ==0)
+                                                       servMgr->autoMaxRelaySetting = getCGIargINT(arg);
+                                       else if (strcmp(curr, "autoBumpSkipCount") ==0)
+                                                       servMgr->autoBumpSkipCount = getCGIargINT(arg);
+                                       else if (strcmp(curr, "kickPushStartRelays") ==0)
+                                                       servMgr->kickPushStartRelays = getCGIargINT(arg);
+                                       else if (strcmp(curr, "kickPushInterval") ==0)
+                                                       servMgr->kickPushInterval = getCGIargINT(arg);
+                                       else if (strcmp(curr, "allowConnectPCST") ==0)
+                                               allowConnectPCST = atoi(arg) ? 1 : 0;
+                                       else if (strcmp(curr, "enableGetName") ==0)
+                                               enableGetName = atoi(arg)? 1 : 0;
+                                       else if (strcmp(curr, "autoPort0Kick") ==0)
+                                               servMgr->autoPort0Kick = getCGIargBOOL(arg);
+                                       else if (strcmp(curr, "allowOnlyVP") ==0)
+                                               servMgr->allowOnlyVP = getCGIargBOOL(arg);
+                                       else if (strcmp(curr, "kickKeepTime") ==0)
+                                               servMgr->kickKeepTime = getCGIargINT(arg);
+
+                                       else if (strcmp(curr, "maxRelaysIndexTxt") ==0)         // for PCRaw (relay)
+                                               servMgr->maxRelaysIndexTxt = getCGIargINT(arg);
+                               }
+
+
+
+                               servMgr->showLog = showLog;
+                               servMgr->allowServer1 = allowServer1;
+                               servMgr->allowServer2 = allowServer2;
+                               servMgr->enableGetName = enableGetName;
+                               servMgr->allowConnectPCST = allowConnectPCST;
+                               if (!(servMgr->allowServer1 & ALLOW_HTML) && !(servMgr->allowServer2 & ALLOW_HTML))
+                                       servMgr->allowServer1 |= ALLOW_HTML;
+
+                               if (servMgr->serverHost.port != newPort)
+                               {
+                                       Host lh(ClientSocket::getIP(NULL),newPort);
+                                       char ipstr[64];
+                                       lh.toStr(ipstr);
+                                       sprintf(jumpStr,"http://%s/%s/settings.html",ipstr,servMgr->htmlPath);                                  
+
+                                       servMgr->serverHost.port = newPort;
+                                       servMgr->restartServer=true;
+                                       //html.setRefresh(3);
+                                       //html.setRefreshURL(jumpStr);
+                                       //html.startHTML();
+                                       //html.addHead();
+                                       //      html.startBody();
+                                       //              html.startTagEnd("h1","Please wait...");
+                                       //      html.end();
+                                       //html.end();
+
+                                       
+
+                                       //char ipstr[64];
+                                       //servMgr->serverHost.toStr(ipstr);
+                                       //sprintf(jumpStr,"/%s/settings.html",ipstr,servMgr->htmlPath);                                 
+                                       jumpArg = jumpStr;
+
+                               }else
+                               {
+                                       sprintf(jumpStr,"/%s/settings.html",servMgr->htmlPath);                                 
+                                       jumpArg = jumpStr;
+                               }
+
+                               peercastInst->saveSettings();
+
+                               peercastApp->updateSettings();
+
+                               if ((servMgr->isRoot) && (brRoot))
+                                       servMgr->broadcastRootSettings(getUpd);
+
+
+
+                               
+
+                       }else if (cmpCGIarg(cmd,"cmd=","fetch"))
+                       {
+
+                               ChanInfo info;
+                               String curl;
+
+                               char *cp = cmd;
+                               while (cp=nextCGIarg(cp,curr,arg))
+                               {
+                                       if (strcmp(curr,"url")==0)
+                                       {
+                                               curl.set(arg,String::T_ESC);
+                                               curl.convertTo(String::T_UNICODE);
+                                       }else if (strcmp(curr,"name")==0)
+                                       {
+                                               info.name.set(arg,String::T_ESC);
+                                               info.name.convertTo(String::T_UNICODE);
+                                       }else if (strcmp(curr,"desc")==0)
+                                       {
+                                               info.desc.set(arg,String::T_ESC);
+                                               info.desc.convertTo(String::T_UNICODE);
+                                       }else if (strcmp(curr,"genre")==0)
+                                       {
+                                               info.genre.set(arg,String::T_ESC);
+                                               info.genre.convertTo(String::T_UNICODE);
+                                       }else if (strcmp(curr,"contact")==0)
+                                       {
+                                               info.url.set(arg,String::T_ESC);
+                                               info.url.convertTo(String::T_UNICODE);
+                                       }else if (strcmp(curr,"bitrate")==0)
+                                       {
+                                               info.bitrate = atoi(arg);
+                                       }else if (strcmp(curr,"type")==0)
+                                       {
+                                               info.contentType = ChanInfo::getTypeFromStr(arg);
+                                       }
+
+                               }
+                               
+                               info.bcID = chanMgr->broadcastID;
+
+                               Channel *c = chanMgr->createChannel(info,NULL);
+                               if (c)
+                                       c->startURL(curl.cstr());
+
+
+                               sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath);                                   
+                               jumpArg = jumpStr;
+
+                       }else if (cmpCGIarg(cmd,"cmd=","stopserv"))
+                       {
+
+                               char *cp = cmd;
+                               while (cp=nextCGIarg(cp,curr,arg))
+                               {
+                                       if (strcmp(curr,"index")==0)
+                                       {
+                                               Servent *s = servMgr->findServentByIndex(atoi(arg));
+                                               if (s)
+                                                       s->abort();
+                                       }
+                               }
+                               sprintf(jumpStr,"/%s/connections.html",servMgr->htmlPath);                                      
+                               jumpArg = jumpStr;
+
+
+                       }else if (cmpCGIarg(cmd,"cmd=","hitlist"))
+                       {                       
+                                       
+                               bool stayConnected=hasCGIarg(cmd,"relay");
+
+                               int index = 0;
+                               ChanHitList *chl = chanMgr->hitlist;                            
+                               while (chl)
+                               {
+                                       if (chl->isUsed())
+                                       {
+                                               char tmp[64];
+                                               sprintf(tmp,"c%d=",index);
+                                               if (cmpCGIarg(cmd,tmp,"1"))
+                                               {
+                                                       Channel *c;
+                                                       if (!(c=chanMgr->findChannelByID(chl->info.id)))
+                                                       {
+                                                               c = chanMgr->createChannel(chl->info,NULL);
+                                                               if (!c)
+                                                                       throw StreamException("out of channels");
+                                                               c->stayConnected = stayConnected;
+                                                               c->startGet();
+                                                       }
+                                               }
+                                       }
+                                       chl = chl->next;
+                                       index++;
+                               }
+
+                               char *findArg = getCGIarg(cmd,"keywords=");
+
+                               if (hasCGIarg(cmd,"relay"))
+                               {
+                                       sys->sleep(500);
+                                       sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath);                                   
+                                       jumpArg = jumpStr;
+                               }
+                       }else if (cmpCGIarg(cmd,"cmd=","clear"))
+                       {
+                               char *cp = cmd;
+                               while (cp=nextCGIarg(cp,curr,arg))
+                               {
+                                       if (strcmp(curr,"hostcache")==0)
+                                               servMgr->clearHostCache(ServHost::T_SERVENT);
+                                       else if (strcmp(curr,"hitlists")==0)
+                                               chanMgr->clearHitLists();
+                                       else if (strcmp(curr,"packets")==0)
+                                       {
+                                               stats.clearRange(Stats::PACKETSSTART,Stats::PACKETSEND);
+                                               servMgr->numVersions = 0;
+                                       }
+                               }
+
+                               sprintf(jumpStr,"/%s/index.html",servMgr->htmlPath);                                    
+                               jumpArg = jumpStr;
+
+                       }else if (cmpCGIarg(cmd,"cmd=","upgrade"))
+                       {
+                               if (servMgr->downloadURL[0])
+                               {
+                                       sprintf(jumpStr,"/admin?cmd=redirect&url=%s",servMgr->downloadURL);
+                                       jumpArg = jumpStr;
+                               }
+
+
+
+
+                       }else if (cmpCGIarg(cmd,"cmd=","connect"))
+                       {                       
+                                       
+
+                               Servent *s = servMgr->servents;
+                               {
+                                       char tmp[64];
+                                       sprintf(tmp,"c%d=",s->serventIndex);
+                                       if (cmpCGIarg(cmd,tmp,"1"))
+                                       {
+                                               if (hasCGIarg(cmd,"stop"))
+                                                       s->thread.active = false;
+                                       }
+                                       s=s->next;
+                               }
+                               sprintf(jumpStr,"/%s/connections.html",servMgr->htmlPath);                                      
+                               jumpArg = jumpStr;
+
+                       }else if (cmpCGIarg(cmd,"cmd=","shutdown"))
+                       {
+                               servMgr->shutdownTimer = 1;
+
+                       }else if (cmpCGIarg(cmd,"cmd=","stop"))
+                       {
+                               GnuID id;
+                               char *cp = cmd;
+                               while (cp=nextCGIarg(cp,curr,arg))
+                               {
+                                       if (strcmp(curr,"id")==0)
+                                               id.fromStr(arg);
+                               }
+
+                               Channel *c = chanMgr->findChannelByID(id);
+                               if (c){
+                                       c->thread.active = false;
+                                       c->thread.finish = true;
+                               }
+
+                               sys->sleep(500);
+                               sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath);                                   
+                               jumpArg = jumpStr;
+
+                       }else if (cmpCGIarg(cmd,"cmd=","bump"))
+                       {
+                               GnuID id;
+                               char *cp = cmd;
+                               while (cp=nextCGIarg(cp,curr,arg))
+                               {
+                                       if (strcmp(curr,"id")==0)
+                                               id.fromStr(arg);
+                               }
+
+                               Channel *c = chanMgr->findChannelByID(id);
+                               if (c)
+                                       c->bump = true;
+
+                               sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath);                                   
+                               jumpArg = jumpStr;
+
+                       }else if (cmpCGIarg(cmd,"cmd=","keep"))
+                       {
+                               GnuID id;
+                               char *cp = cmd;
+                               while (cp=nextCGIarg(cp,curr,arg))
+                               {
+                                       if (strcmp(curr,"id")==0)
+                                               id.fromStr(arg);
+                               }
+
+                               Channel *c = chanMgr->findChannelByID(id);
+                               if (c)
+                               { //JP-Patch
+                                       //c->stayConnected = true;
+                                       if (!c->stayConnected)
+                                       {
+                                               //if (servMgr->getFirewall() == ServMgr::FW_OFF)
+                                               c->stayConnected = true;
+                                       }
+                                       else
+                                               c->stayConnected = false;
+                               } //JP-Patch
+
+                               sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath);                                   
+                               jumpArg = jumpStr;
+
+                       }else if (cmpCGIarg(cmd,"cmd=","relay"))
+                       {
+                               ChanInfo info;
+                               char *cp = cmd;
+                               while (cp=nextCGIarg(cp,curr,arg))
+                               {
+                                       if (strcmp(curr,"id")==0)
+                                               info.id.fromStr(arg);
+                               }
+
+
+                               if (!chanMgr->findChannelByID(info.id))
+                               {
+
+                                       ChanHitList *chl = chanMgr->findHitList(info);
+                                       if (!chl)
+                                               throw StreamException("channel not found");
+
+
+                                       Channel *c = chanMgr->createChannel(chl->info,NULL);
+                                       if (!c)
+                                               throw StreamException("out of channels");
+
+                                       c->stayConnected = true;
+                                       c->startGet();
+                               }
+
+                               sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath);                                   
+                               jumpArg = jumpStr;
+
+
+                       }else if (cmpCGIarg(cmd,"net=","add"))
+                       {
+                               
+                               GnuID id;
+                               id.clear();
+                               while (cmd=nextCGIarg(cmd,curr,arg))
+                               {
+                                       if (strcmp(curr,"ip")==0)
+                                       {
+                                               Host h;
+                                               h.fromStrIP(arg,DEFAULT_PORT);
+                                               if (servMgr->addOutgoing(h,id,true))
+                                                       LOG_NETWORK("Added connection: %s",arg);
+
+                                       }else if (strcmp(curr,"id")==0)
+                                       {
+                                               id.fromStr(arg);
+                                       }
+
+                               }
+
+                       }else if (cmpCGIarg(cmd,"cmd=","logout"))
+                       {
+                               jumpArg = "/";
+                               servMgr->cookieList.remove(cookie);
+
+                       }else if (cmpCGIarg(cmd,"cmd=","login"))
+                       {
+                               GnuID id;
+                               char idstr[64];
+                               id.generate();
+                               id.toStr(idstr);
+
+                               cookie.set(idstr,sock->host.ip);
+                               servMgr->cookieList.add(cookie);        
+
+                               http.writeLine(HTTP_SC_FOUND);
+                               if (servMgr->cookieList.neverExpire)
+                                       http.writeLineF("%s id=%s; path=/; expires=\"Mon, 01-Jan-3000 00:00:00 GMT\";",HTTP_HS_SETCOOKIE,idstr);
+                               else
+                                       http.writeLineF("%s id=%s; path=/;",HTTP_HS_SETCOOKIE,idstr);
+                               http.writeLineF("Location: /%s/index.html",servMgr->htmlPath);
+                               http.writeLine("");
+
+                       }else if (cmpCGIarg(cmd,"cmd=","setmeta"))
+                       {
+                               char *cp = cmd;
+                               while (cp=nextCGIarg(cp,curr,arg))
+                               {
+                                       if (strcmp(curr,"name")==0)
+                                       {
+/*                                             String chname;
+                                               chname.set(arg,String::T_ESC);
+                                               chname.convertTo(String::T_ASCII);
+                                               for(int i=0; i<ChanMgr::MAX_CHANNELS; i++)
+                                               {
+                                                       Channel *c = &chanMgr->channels[i];
+                                                       if ((c->isActive()) && (c->status == Channel::S_BROADCASTING) && (strcmp(c->info.name.cstr(),chname.cstr())==0)) 
+                                                       {       
+                                                               ChanInfo newInfo = c->info;
+
+                                                               while (cmd=nextCGIarg(cmd,curr,arg))
+                                                               {
+                                                                       String chmeta;
+                                                                       chmeta.set(arg,String::T_ESC);
+                                                                       chmeta.convertTo(String::T_ASCII);
+                                                                       if (strcmp(curr,"desc")==0)
+                                                                               newInfo.desc = chmeta.cstr();
+                                                                       else if (strcmp(curr,"url")==0)
+                                                                               newInfo.url = chmeta.cstr();
+                                                                       else if (strcmp(curr,"genre")==0)
+                                                                               newInfo.genre = chmeta.cstr();
+                                                                       else if (strcmp(curr,"comment")==0)
+                                                                               newInfo.comment = chmeta.cstr();
+                                                                       else if (strcmp(curr,"t_contact")==0)
+                                                                               newInfo.track.contact = chmeta.cstr();
+                                                                       else if (strcmp(curr,"t_title")==0)
+                                                                               newInfo.track.title = chmeta.cstr();
+                                                                       else if (strcmp(curr,"t_artist")==0)
+                                                                               newInfo.track.artist = chmeta.cstr();
+                                                                       else if (strcmp(curr,"t_album")==0)
+                                                                               newInfo.track.album = chmeta.cstr();
+                                                                       else if (strcmp(curr,"t_genre")==0)
+                                                                               newInfo.track.genre = chmeta.cstr();
+                                                               }
+                                                               c->updateInfo(newInfo);
+                                                               char idstr[64];
+                                                               newInfo.id.toStr(idstr);
+                                                               sprintf(jumpStr,"/%s/relayinfo.html?id=%s",servMgr->htmlPath,idstr);
+                                                               jumpArg = jumpStr;
+                                                               break;
+                                                       }
+                                               }*/
+                                               String chname;
+                                               chname.set(arg,String::T_ESC);
+                                               chname.convertTo(String::T_ASCII);
+
+                                               Channel *c = chanMgr->findChannelByName(chname.cstr());
+                                               if (c && (c->isActive()) && (c->status == Channel::S_BROADCASTING)){
+                                                       ChanInfo newInfo = c->info;
+                                                       while (cmd=nextCGIarg(cmd,curr,arg))
+                                                       {
+                                                               String chmeta;
+                                                               chmeta.set(arg,String::T_ESC);
+                                                               chmeta.convertTo(String::T_ASCII);
+                                                               if (strcmp(curr,"desc")==0)
+                                                                       newInfo.desc = chmeta.cstr();
+                                                               else if (strcmp(curr,"url")==0)
+                                                                       newInfo.url = chmeta.cstr();
+                                                               else if (strcmp(curr,"genre")==0)
+                                                                       newInfo.genre = chmeta.cstr();
+                                                               else if (strcmp(curr,"comment")==0)
+                                                                       newInfo.comment = chmeta.cstr();
+                                                               else if (strcmp(curr,"t_contact")==0)
+                                                                       newInfo.track.contact = chmeta.cstr();
+                                                               else if (strcmp(curr,"t_title")==0)
+                                                                       newInfo.track.title = chmeta.cstr();
+                                                               else if (strcmp(curr,"t_artist")==0)
+                                                                       newInfo.track.artist = chmeta.cstr();
+                                                               else if (strcmp(curr,"t_album")==0)
+                                                                       newInfo.track.album = chmeta.cstr();
+                                                               else if (strcmp(curr,"t_genre")==0)
+                                                                       newInfo.track.genre = chmeta.cstr();
+                                                       }
+                                                       c->updateInfo(newInfo);
+                                                       char idstr[64];
+                                                       newInfo.id.toStr(idstr);
+                                                       sprintf(jumpStr,"/%s/relayinfo.html?id=%s",servMgr->htmlPath,idstr);
+                                                       jumpArg = jumpStr;
+                                               }
+                                       }
+                               }
+                               if (!jumpArg)
+                               {
+                                       jumpArg = "/";
+                               }
+                
+                       }else{
+
+                               sprintf(jumpStr,"/%s/index.html",servMgr->htmlPath);                                    
+                               jumpArg = jumpStr;
+                       }
+               }
+
+       }catch(StreamException &e)
+       {
+               html.startTagEnd("h1","ERROR - %s",e.msg);
+               LOG_ERROR("html: %s",e.msg);
+       }
+
+
+       if (retHTML)
+       {
+               if (jumpArg)
+               {
+                       String jmp(jumpArg,String::T_HTML);
+                       jmp.convertTo(String::T_ASCII);
+                       html.locateTo(jmp.cstr());
+               }
+       }
+
+
+}
+// -----------------------------------
+static XML::Node *createChannelXML(Channel *c)
+{
+       XML::Node *n = c->info.createChannelXML();
+       n->add(c->createRelayXML(true));
+       n->add(c->info.createTrackXML());
+//     n->add(c->info.createServentXML());
+       return n;
+}
+// -----------------------------------
+static XML::Node *createChannelXML(ChanHitList *chl)
+{
+       XML::Node *n = chl->info.createChannelXML();
+       n->add(chl->createXML());
+       n->add(chl->info.createTrackXML());
+//     n->add(chl->info.createServentXML());
+       return n;
+}
+// -----------------------------------
+void Servent::handshakeXML()
+{
+       int i;
+                               
+
+
+       XML xml;
+
+       XML::Node *rn = new XML::Node("peercast");
+       xml.setRoot(rn);
+
+
+       rn->add(new XML::Node("servent uptime=\"%d\"",servMgr->getUptime()));
+
+       rn->add(new XML::Node("bandwidth out=\"%d\" in=\"%d\"",
+               stats.getPerSecond(Stats::BYTESOUT)-stats.getPerSecond(Stats::LOCALBYTESOUT),
+               stats.getPerSecond(Stats::BYTESIN)-stats.getPerSecond(Stats::LOCALBYTESIN)
+               ));
+
+       rn->add(new XML::Node("connections total=\"%d\" relays=\"%d\" direct=\"%d\"",servMgr->totalConnected(),servMgr->numStreams(Servent::T_RELAY,true),servMgr->numStreams(Servent::T_DIRECT,true)));
+
+       XML::Node *an = new XML::Node("channels_relayed total=\"%d\"",chanMgr->numChannels());
+       rn->add(an);
+
+       Channel *c = chanMgr->channel;
+       while (c)
+       {
+               if (c->isActive())
+                       an->add(createChannelXML(c));
+               c=c->next;
+       }
+
+
+       // add public channels
+       {
+               XML::Node *fn = new XML::Node("channels_found total=\"%d\"",chanMgr->numHitLists());
+               rn->add(fn);
+
+               ChanHitList *chl = chanMgr->hitlist;
+               while (chl)
+               {
+                       if (chl->isUsed())
+                               fn->add(createChannelXML(chl));
+                       chl = chl->next;
+               }
+       }
+
+
+#if 0
+       if (servMgr->isRoot)
+       {
+               // add private channels
+               {
+                       XML::Node *pn = new XML::Node("priv_channels");
+                       rn->add(pn);
+
+                       ChanHitList *chl = chanMgr->hitlist;
+                       while (chl)
+                       {
+                               if (chl->isUsed())
+                                       if (chl->info.isPrivate())
+                                               pn->add(createChannelXML(chl));
+                               chl = chl->next;
+                       }
+               }
+       }
+#endif
+
+       XML::Node *hc = new XML::Node("host_cache");
+       for(i=0; i<ServMgr::MAX_HOSTCACHE; i++)
+       {
+               ServHost *sh = &servMgr->hostCache[i];
+               if (sh->type != ServHost::T_NONE)
+               {
+                       char ipstr[64];
+                       sh->host.toStr(ipstr);
+
+                       hc->add(new XML::Node("host ip=\"%s\" type=\"%s\" time=\"%d\"",ipstr,ServHost::getTypeStr(sh->type),sh->time));
+
+               }
+       }
+       rn->add(hc);
+
+
+    sock->writeLine(HTTP_SC_OK);
+       sock->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT);
+    sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XML);
+       sock->writeLine("Connection: close");
+
+    sock->writeLine("");
+
+       xml.write(*sock);
+
+}
+// -----------------------------------
+void Servent::readICYHeader(HTTP &http, ChanInfo &info, char *pwd)
+{
+       char *arg = http.getArgStr();
+       if (!arg) return;
+
+       if (http.isHeader("x-audiocast-name") || http.isHeader("icy-name") || http.isHeader("ice-name"))
+       {
+               info.name.set(arg,String::T_ASCII);
+               info.name.convertTo(String::T_UNICODE);
+
+       }else if (http.isHeader("x-audiocast-url") || http.isHeader("icy-url") || http.isHeader("ice-url"))
+               info.url.set(arg,String::T_ASCII);
+       else if (http.isHeader("x-audiocast-bitrate") || (http.isHeader("icy-br")) || http.isHeader("ice-bitrate") || http.isHeader("icy-bitrate"))
+               info.bitrate = atoi(arg);
+       else if (http.isHeader("x-audiocast-genre") || http.isHeader("ice-genre") || http.isHeader("icy-genre"))
+       {
+               info.genre.set(arg,String::T_ASCII);
+               info.genre.convertTo(String::T_UNICODE);
+
+       }else if (http.isHeader("x-audiocast-description") || http.isHeader("ice-description"))
+       {
+               info.desc.set(arg,String::T_ASCII);
+               info.desc.convertTo(String::T_UNICODE);
+
+       }else if (http.isHeader("Authorization"))
+               http.getAuthUserPass(NULL,pwd);
+       else if (http.isHeader(PCX_HS_CHANNELID))
+               info.id.fromStr(arg);
+       else if (http.isHeader("ice-password"))
+       {
+               if (pwd)
+                       if (strlen(arg) < 64)
+                               strcpy(pwd,arg);
+       }else if (http.isHeader("content-type"))
+       {
+               if (stristr(arg,MIME_OGG))
+                       info.contentType = ChanInfo::T_OGG;
+               else if (stristr(arg,MIME_XOGG))
+                       info.contentType = ChanInfo::T_OGG;
+
+               else if (stristr(arg,MIME_MP3))
+                       info.contentType = ChanInfo::T_MP3;
+               else if (stristr(arg,MIME_XMP3))
+                       info.contentType = ChanInfo::T_MP3;
+
+               else if (stristr(arg,MIME_WMA))
+                       info.contentType = ChanInfo::T_WMA;
+               else if (stristr(arg,MIME_WMV))
+                       info.contentType = ChanInfo::T_WMV;
+               else if (stristr(arg,MIME_ASX))
+                       info.contentType = ChanInfo::T_ASX;
+
+               else if (stristr(arg,MIME_NSV))
+                       info.contentType = ChanInfo::T_NSV;
+               else if (stristr(arg,MIME_RAW))
+                       info.contentType = ChanInfo::T_RAW;
+
+               else if (stristr(arg,MIME_MMS))
+                       info.srcProtocol = ChanInfo::SP_MMS;
+               else if (stristr(arg,MIME_XPCP))
+                       info.srcProtocol = ChanInfo::SP_PCP;
+               else if (stristr(arg,MIME_XPEERCAST))
+                       info.srcProtocol = ChanInfo::SP_PEERCAST;
+
+               else if (stristr(arg,MIME_XSCPLS))
+                       info.contentType = ChanInfo::T_PLS;
+               else if (stristr(arg,MIME_PLS))
+                       info.contentType = ChanInfo::T_PLS;
+               else if (stristr(arg,MIME_XPLS))
+                       info.contentType = ChanInfo::T_PLS;
+               else if (stristr(arg,MIME_M3U))
+                       info.contentType = ChanInfo::T_PLS;
+               else if (stristr(arg,MIME_MPEGURL))
+                       info.contentType = ChanInfo::T_PLS;
+               else if (stristr(arg,MIME_TEXT))
+                       info.contentType = ChanInfo::T_PLS;
+
+
+       }
+
+}
+
+// -----------------------------------
+void Servent::handshakeICY(Channel::SRC_TYPE type, bool isHTTP)
+{
+       ChanInfo info;
+
+       HTTP http(*sock);
+
+       // default to mp3 for shoutcast DSP (doesn`t send content-type)
+       if (type == Channel::SRC_SHOUTCAST)
+               info.contentType = ChanInfo::T_MP3;
+
+       while (http.nextHeader())
+       {
+               LOG_DEBUG("ICY %s",http.cmdLine);
+               readICYHeader(http,info,loginPassword);
+       }
+
+
+               
+       // check password before anything else, if needed
+       if (strcmp(servMgr->password,loginPassword)!=0)
+       {
+               if (!sock->host.isLocalhost() || strlen(loginPassword))
+                       throw HTTPException(HTTP_SC_UNAUTHORIZED,401);
+       }
+
+               
+       // we need a valid IP address before we start
+       servMgr->checkFirewall();
+
+
+       // attach channel ID to name, channel ID is also encoded with IP address 
+       // to help prevent channel hijacking. 
+
+
+       info.id = chanMgr->broadcastID;
+       info.id.encode(NULL,info.name.cstr(),loginMount,info.bitrate);
+
+       LOG_DEBUG("Incoming source: %s : %s",info.name.cstr(),ChanInfo::getTypeStr(info.contentType));
+
+
+       if (isHTTP)
+               sock->writeStringF("%s\n\n",HTTP_SC_OK);
+       else
+               sock->writeLine("OK");
+
+       Channel *c = chanMgr->findChannelByID(info.id);
+       if (c)
+       {
+               LOG_CHANNEL("ICY channel already active, closing old one");
+               c->thread.shutdown();
+       }
+
+
+       info.comment = chanMgr->broadcastMsg;
+       info.bcID = chanMgr->broadcastID;
+
+       c = chanMgr->createChannel(info,loginMount);
+       if (!c)
+               throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+       c->startICY(sock,type);
+}
+
+
+// -----------------------------------
+void Servent::handshakeLocalFile(const char *fn)
+{
+       HTTP http(*sock);
+       String fileName;
+       
+       if (servMgr->getModulePath) //JP-EX
+       {
+               peercastApp->getDirectory();
+               fileName = servMgr->modulePath;
+       }else
+               fileName = peercastApp->getPath();
+       
+       fileName.append(fn);
+
+       LOG_DEBUG("Writing HTML file: %s",fileName.cstr());
+
+       HTML html("",*sock);
+
+       char *args = strstr(fileName.cstr(),"?");
+       if (args)
+               *args++=0;
+
+       if (fileName.contains(".htm"))
+       {
+               html.writeOK(MIME_HTML);
+               html.writeTemplate(fileName.cstr(),args);
+
+       }else if (fileName.contains(".css"))
+       {
+               html.writeOK(MIME_CSS);
+               html.writeRawFile(fileName.cstr());
+       }else if (fileName.contains(".jpg"))
+       {
+               html.writeOK(MIME_JPEG);
+               html.writeRawFile(fileName.cstr());
+       }else if (fileName.contains(".gif"))
+       {
+               html.writeOK(MIME_GIF);
+               html.writeRawFile(fileName.cstr());
+       }else if (fileName.contains(".png"))
+       {
+               html.writeOK(MIME_PNG);
+               html.writeRawFile(fileName.cstr());
+       }
+}
+
+// -----------------------------------
+void Servent::handshakeRemoteFile(const char *dirName)
+{
+       ClientSocket *rsock = sys->createSocket();
+       if (!rsock)
+               throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+
+       const char *hostName = "www.peercast.org";      // hardwired for "security"
+
+       Host host;
+       host.fromStrName(hostName,80);
+
+
+       rsock->open(host);
+       rsock->connect();
+
+       HTTP rhttp(*rsock);
+
+       rhttp.writeLineF("GET /%s HTTP/1.0",dirName);
+       rhttp.writeLineF("%s %s",HTTP_HS_HOST,hostName);
+       rhttp.writeLineF("%s %s",HTTP_HS_CONNECTION,"close");
+       rhttp.writeLineF("%s %s",HTTP_HS_ACCEPT,"*/*");
+       rhttp.writeLine("");
+
+       String contentType;
+       bool isTemplate = false;
+       while (rhttp.nextHeader())
+       {
+               char *arg = rhttp.getArgStr();
+               if (arg) 
+               {
+                       if (rhttp.isHeader("content-type"))
+                               contentType = arg;
+               }
+       }
+
+       MemoryStream mem(100*1024);
+       while (!rsock->eof())
+       {
+               int len=0;
+               char buf[4096];
+               len = rsock->readUpto(buf,sizeof(buf));
+               if (len==0)
+                       break;
+               else
+                       mem.write(buf,len);
+
+       }
+       rsock->close();
+
+       int fileLen = mem.getPosition();
+       mem.len = fileLen;
+       mem.rewind();
+
+
+       if (contentType.contains(MIME_HTML))
+               isTemplate = true;
+
+       sock->writeLine(HTTP_SC_OK);
+       sock->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT);
+       sock->writeLineF("%s %s",HTTP_HS_CACHE,"no-cache");
+       sock->writeLineF("%s %s",HTTP_HS_CONNECTION,"close");
+       sock->writeLineF("%s %s",HTTP_HS_CONTENT,contentType.cstr());
+
+       sock->writeLine("");
+
+       if (isTemplate)
+       {
+               HTML html("",*sock);
+               html.readTemplate(mem,sock,0);
+       }else
+               sock->write(mem.buf,fileLen);
+
+       mem.free2();
+}
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/servmgr.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/servmgr.cpp
new file mode 100644 (file)
index 0000000..7f72944
--- /dev/null
@@ -0,0 +1,2608 @@
+// ------------------------------------------------
+// File : servmgr.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             Management class for handling multiple servent connections.
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include <stdlib.h>
+#include "servent.h"
+#include "servmgr.h"
+#include "inifile.h"
+#include "stats.h"
+#include "peercast.h"
+#include "pcp.h"
+#include "atom.h"
+#include "version2.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+ThreadInfo ServMgr::serverThread,ServMgr::idleThread;
+
+// -----------------------------------
+ServMgr::ServMgr()
+{
+       validBCID = NULL;
+
+       authType = AUTH_COOKIE;
+       cookieList.init();
+
+       serventNum = 0;
+
+       startTime = sys->getTime();
+
+       allowServer1 = Servent::ALLOW_ALL;
+       allowServer2 = Servent::ALLOW_BROADCAST;
+
+       clearHostCache(ServHost::T_NONE);
+       password[0]=0;
+
+       allowGnutella = false;
+       useFlowControl = true;
+
+       maxServIn = 50;
+       minGnuIncoming = 10;
+       maxGnuIncoming = 20;
+
+       lastIncoming = 0;
+
+       maxBitrateOut = 540; //JP-Patch 0-> 540
+       maxRelays = MIN_RELAYS;
+       maxDirect = 0;
+       refreshHTML = 1800;
+
+       networkID.clear();
+
+       notifyMask = 0xffff;
+
+       tryoutDelay = 10;
+       numVersions = 0;
+
+       sessionID.generate();
+
+       isDisabled = false;
+       isRoot = false;
+
+       forceIP.clear();
+
+       strcpy(connectHost,"connect1.peercast.org");
+       strcpy(htmlPath,"html/ja");
+
+       rootHost = "yp.peercast.org";
+       rootHost2 = "";
+
+       serverHost.fromStrIP("127.0.0.1",DEFAULT_PORT);
+
+       firewalled = FW_UNKNOWN;                
+       allowDirect = true;
+       autoConnect = true;
+       forceLookup = true;
+       autoServe = true;
+       forceNormal = false;
+
+       maxControl = 3;
+
+       queryTTL = 7;
+
+       totalStreams = 0;
+       firewallTimeout = 30;
+       pauseLog = false;
+       showLog = 0;
+
+       shutdownTimer = 0;
+
+       downloadURL[0] = 0;
+       rootMsg.clear();
+
+
+       restartServer=false;
+
+       setFilterDefaults();
+
+       servents = NULL;
+
+       modulePath[0] = 0; //JP-EX
+       kickPushStartRelays = 1; //JP-EX
+       kickPushInterval = 60; //JP-EX
+       kickPushTime = 0; //JP-EX
+       autoRelayKeep = 2; //JP-EX
+       autoMaxRelaySetting = 0; //JP-EX
+       autoBumpSkipCount = 50; //JP-EX
+       enableGetName = 1; //JP-EX
+       allowConnectPCST = 0; //JP-EX
+       getModulePath = true; //JP-EX
+       clearPLS = false; //JP-EX
+       writeLogFile = false; //JP-EX
+
+       autoPort0Kick = false;
+       allowOnlyVP = false;
+       kickKeepTime = 0;
+       vpDebug = false;
+       saveIniChannel = true;
+       saveGuiPos = false;
+       keepDownstreams = true;
+
+       chanLog="";
+
+       maxRelaysIndexTxt = 1;  // for PCRaw (relay)
+}
+// -----------------------------------
+BCID *ServMgr::findValidBCID(int index)
+{
+       int cnt = 0;
+       BCID *bcid = validBCID;
+       while (bcid)
+       {
+               if (cnt == index)
+                       return bcid;
+               cnt++;
+               bcid=bcid->next;
+       }
+       return 0;
+}
+// -----------------------------------
+BCID *ServMgr::findValidBCID(GnuID &id)
+{
+       BCID *bcid = validBCID;
+       while (bcid)
+       {
+               if (bcid->id.isSame(id))
+                       return bcid;
+               bcid=bcid->next;
+       }
+       return 0;
+}
+// -----------------------------------
+void ServMgr::removeValidBCID(GnuID &id)
+{
+       BCID *bcid = validBCID,*prev=0;
+       while (bcid)
+       {
+               if (bcid->id.isSame(id))
+               {
+                       if (prev)
+                               prev->next = bcid->next;
+                       else
+                               validBCID = bcid->next;
+                       return;
+               }
+               prev = bcid;
+               bcid=bcid->next;
+       }
+}
+// -----------------------------------
+void ServMgr::addValidBCID(BCID *bcid)
+{
+       removeValidBCID(bcid->id);
+
+       bcid->next = validBCID;
+       validBCID = bcid;
+}
+
+// -----------------------------------
+void   ServMgr::connectBroadcaster()
+{
+       if (!rootHost.isEmpty())
+       {
+               if (!numUsed(Servent::T_COUT))
+               {
+                       Servent *sv = allocServent();
+                       if (sv)
+                       {
+                               sv->initOutgoing(Servent::T_COUT);
+                               sys->sleep(3000);
+                       }
+               }
+       }
+}
+// -----------------------------------
+void   ServMgr::addVersion(unsigned int ver)
+{
+       for(int i=0; i<numVersions; i++)
+               if (clientVersions[i] == ver)
+               {
+                       clientCounts[i]++;
+                       return;
+               }
+
+       if (numVersions < MAX_VERSIONS)
+       {
+               clientVersions[numVersions] = ver;
+               clientCounts[numVersions] = 1;
+               numVersions++;
+       }
+}
+
+// -----------------------------------
+void ServMgr::setFilterDefaults()
+{
+       numFilters = 0;
+
+       filters[numFilters].host.fromStrIP("255.255.255.255",0);
+//     filters[numFilters].flags = ServFilter::F_NETWORK|ServFilter::F_DIRECT;
+       filters[numFilters].flags = ServFilter::F_NETWORK;
+
+       numFilters++;
+
+}
+
+// -----------------------------------
+void   ServMgr::setPassiveSearch(unsigned int t)
+{
+//     if ((t > 0) && (t < 60))
+//             t = 60;
+//     passiveSearch = t;
+}
+// -----------------------------------
+bool ServMgr::seenHost(Host &h, ServHost::TYPE type,unsigned int time)
+{
+       time = sys->getTime()-time;
+
+       for(int i=0; i<MAX_HOSTCACHE; i++)
+               if (hostCache[i].type == type)
+                       if (hostCache[i].host.ip == h.ip)
+                               if (hostCache[i].time >= time)
+                                       return true;
+       return false;
+}
+
+// -----------------------------------
+void ServMgr::addHost(Host &h, ServHost::TYPE type, unsigned int time)
+{
+       int i;
+       if (!h.isValid())
+               return;
+
+       ServHost *sh=NULL;
+
+       for(i=0; i<MAX_HOSTCACHE; i++)
+               if (hostCache[i].type == type)
+                       if (hostCache[i].host.isSame(h))
+                       {
+                               sh = &hostCache[i];
+                               break;
+                       }
+
+       char str[64];
+       h.toStr(str);
+
+       if (!sh)
+               LOG_DEBUG("New host: %s - %s",str,ServHost::getTypeStr(type));
+       else
+               LOG_DEBUG("Old host: %s - %s",str,ServHost::getTypeStr(type));
+
+       h.value = 0;    // make sure dead count is zero
+       if (!sh)
+       {
+
+
+               // find empty slot
+               for(i=0; i<MAX_HOSTCACHE; i++)
+                       if (hostCache[i].type == ServHost::T_NONE)
+                       {
+                               sh = &hostCache[i];
+                               break;
+                       }
+
+               // otherwise, find oldest host and replace
+               if (!sh)
+                       for(i=0; i<MAX_HOSTCACHE; i++)
+                               if (hostCache[i].type != ServHost::T_NONE)
+                               {
+                                       if (sh)
+                                       {
+                                               if (hostCache[i].time < sh->time)
+                                                       sh = &hostCache[i];
+                                       }else{
+                                               sh = &hostCache[i];
+                                       }
+                               }
+       }
+
+       if (sh)
+               sh->init(h,type,time);
+}
+
+// -----------------------------------
+void ServMgr::deadHost(Host &h,ServHost::TYPE t)
+{
+       for(int i=0; i<MAX_HOSTCACHE; i++)
+               if (hostCache[i].type == t)
+                       if (hostCache[i].host.ip == h.ip)
+                               if (hostCache[i].host.port == h.port)
+                                       hostCache[i].init();
+}
+// -----------------------------------
+void ServMgr::clearHostCache(ServHost::TYPE type)
+{
+       for(int i=0; i<MAX_HOSTCACHE; i++)
+               if ((hostCache[i].type == type) || (type == ServHost::T_NONE))
+                       hostCache[i].init();
+}
+       
+// -----------------------------------
+unsigned int ServMgr::numHosts(ServHost::TYPE type)
+{
+       unsigned int cnt = 0;
+       for(int i=0; i<MAX_HOSTCACHE; i++)
+               if ((hostCache[i].type == type) || (type == ServHost::T_NONE))
+                       cnt++;
+       return cnt;
+}
+// -----------------------------------
+int ServMgr::getNewestServents(Host *hl,int max,Host &rh)
+{
+       int cnt=0;
+       for(int i=0; i<max; i++)
+       {
+               // find newest host not in list
+               ServHost *sh=NULL;
+               for(int j=0; j<MAX_HOSTCACHE; j++)
+               {
+                       // find newest servent
+                       if (hostCache[j].type == ServHost::T_SERVENT)
+                               if (!(rh.globalIP() && !hostCache[j].host.globalIP()))
+                               {
+                                       // and not in list already
+                                       bool found=false;
+                                       for(int k=0; k<cnt; k++)
+                                               if (hl[k].isSame(hostCache[j].host))
+                                               {
+                                                       found=true; 
+                                                       break;
+                                               }
+
+                                       if (!found)
+                                       {
+                                               if (!sh)
+                                               {
+                                                       sh = &hostCache[j];
+                                               }else{
+                                                       if (hostCache[j].time > sh->time)
+                                                               sh = &hostCache[j];
+                                               }
+                                       }
+                               }
+               }
+
+               // add to list
+               if (sh)
+                       hl[cnt++]=sh->host;
+       }
+       
+       return cnt;
+}
+// -----------------------------------
+ServHost ServMgr::getOutgoingServent(GnuID &netid)
+{
+       ServHost host;
+
+       Host lh(ClientSocket::getIP(NULL),0);
+
+       // find newest host not in list
+       ServHost *sh=NULL;
+       for(int j=0; j<MAX_HOSTCACHE; j++)
+       {
+               ServHost *hc=&hostCache[j];
+               // find newest servent not already connected.
+               if (hc->type == ServHost::T_SERVENT)
+               {
+                       if (!((lh.globalIP() && !hc->host.globalIP()) || lh.isSame(hc->host)))
+                       {
+#if 0
+                               if (!findServent(Servent::T_OUTGOING,hc->host,netid))
+                               {
+                                       if (!sh)
+                                       {
+                                               sh = hc;
+                                       }else{
+                                               if (hc->time > sh->time)
+                                                       sh = hc;
+                                       }
+                               }
+#endif
+                       }
+               }
+       }
+
+       if (sh)
+               host = *sh;
+
+       return host;
+}
+// -----------------------------------
+Servent *ServMgr::findOldestServent(Servent::TYPE type, bool priv)
+{
+       Servent *oldest=NULL;
+
+       Servent *s = servents;
+       while (s)
+       {
+               if (s->type == type)
+                       if (s->thread.active)
+                               if (s->isOlderThan(oldest))
+                                       if (s->isPrivate() == priv)
+                                               oldest = s;
+               s=s->next;
+       }
+       return oldest;
+}
+// -----------------------------------
+Servent *ServMgr::findServent(Servent::TYPE type, Host &host, GnuID &netid)
+{
+       lock.on();
+       Servent *s = servents;
+       while (s)
+       {
+               if (s->type == type)
+               {
+                       Host h = s->getHost();
+                       if (h.isSame(host) && s->networkID.isSame(netid))
+                       {
+                               lock.off();
+                               return s;
+                       }
+               }
+               s=s->next;
+       }
+       lock.off();
+       return NULL;
+
+}
+
+// -----------------------------------
+Servent *ServMgr::findServent(unsigned int ip, unsigned short port, GnuID &netid)
+{
+       lock.on();
+       Servent *s = servents;
+       while (s)
+       {
+               if (s->type != Servent::T_NONE)
+               {
+                       Host h = s->getHost();
+                       if ((h.ip == ip) && (h.port == port) && (s->networkID.isSame(netid)))
+                       {
+                               lock.off();
+                               return s;
+                       }
+               }
+               s=s->next;
+       }
+       lock.off();
+       return NULL;
+
+}
+
+// -----------------------------------
+Servent *ServMgr::findServent(Servent::TYPE t)
+{
+       Servent *s = servents;
+       while (s)
+       {
+               if (s->type == t)
+                       return s;
+               s=s->next;
+       }
+       return NULL;
+}
+// -----------------------------------
+Servent *ServMgr::findServentByIndex(int id)
+{
+       Servent *s = servents;
+       int cnt=0;
+       while (s)
+       {
+               if (cnt == id)
+                       return s;
+                       cnt++;
+               s=s->next;
+       }
+       return NULL;
+}
+
+// -----------------------------------
+Servent *ServMgr::findServentByServentID(int id)
+{
+       Servent *s = servents;
+       while (s)
+       {
+               if (id == s->servent_id){
+                       return s;
+               }
+               s=s->next;
+       }
+       return NULL;
+}
+
+// -----------------------------------
+Servent *ServMgr::allocServent()
+{
+       lock.on();
+
+       Servent *s = servents;
+       while (s)
+       {
+               if (s->status == Servent::S_FREE)
+                       break;
+               s=s->next;
+       }
+
+       if (!s)
+       {
+               s = new Servent(++serventNum);
+               s->next = servents;
+               servents = s;
+
+               LOG_DEBUG("allocated servent %d",serventNum);
+       }else
+               LOG_DEBUG("reused servent %d",s->serventIndex);
+
+
+       s->reset();
+
+       lock.off();
+
+       return s;
+}
+// --------------------------------------------------
+void   ServMgr::closeConnections(Servent::TYPE type)
+{
+       Servent *sv = servents;
+       while (sv)
+       {
+               if (sv->isConnected())
+                       if (sv->type == type)
+                               sv->thread.active = false;
+               sv=sv->next;
+       }
+}
+
+// -----------------------------------
+unsigned int ServMgr::numConnected(int type,bool priv,unsigned int uptime)
+{
+       unsigned int cnt=0;
+
+       unsigned int ctime=sys->getTime();
+       Servent *s = servents;
+       while (s)
+       {
+               if (s->thread.active)
+                       if (s->isConnected())
+                               if (s->type == type)
+                                       if (s->isPrivate()==priv)
+                                               if ((ctime-s->lastConnect) >= uptime)
+                                                       cnt++;
+
+               s=s->next;
+       }
+       return cnt;
+}
+// -----------------------------------
+unsigned int ServMgr::numConnected()
+{
+       unsigned int cnt=0;
+
+       Servent *s = servents;
+       while (s)
+       {
+               if (s->thread.active)
+                       if (s->isConnected())
+                               cnt++;
+
+               s=s->next;
+       }
+       return cnt;
+}
+// -----------------------------------
+unsigned int ServMgr::numServents()
+{
+       unsigned int cnt=0;
+
+       Servent *s = servents;
+       while (s)
+       {
+               cnt++;
+               s=s->next;
+       }
+       return cnt;
+}
+
+// -----------------------------------
+unsigned int ServMgr::numUsed(int type)
+{
+       unsigned int cnt=0;
+
+       Servent *s = servents;
+       while (s)
+       {
+               if (s->type == type)
+                       cnt++;
+               s=s->next;
+       }
+       return cnt;
+}
+// -----------------------------------
+unsigned int ServMgr::numActiveOnPort(int port)
+{
+       unsigned int cnt=0;
+
+       Servent *s = servents;
+       while (s)
+       {
+               if (s->thread.active && s->sock && (s->servPort == port))
+                       cnt++;
+               s=s->next;
+       }
+       return cnt;
+}
+// -----------------------------------
+unsigned int ServMgr::numActive(Servent::TYPE tp)
+{
+       unsigned int cnt=0;
+
+       Servent *s = servents;
+       while (s)
+       {
+               if (s->thread.active && s->sock && (s->type == tp))
+                       cnt++;
+               s=s->next;
+       }
+       return cnt;
+}
+
+// -----------------------------------
+unsigned int ServMgr::totalOutput(bool all)
+{
+       unsigned int tot = 0;
+       Servent *s = servents;
+       while (s)
+       {
+               if (s->isConnected())
+                       if (all || !s->isPrivate())
+                               if (s->sock)
+                                       tot += s->sock->bytesOutPerSec;
+               s=s->next;
+       }
+
+       return tot;
+}
+
+// -----------------------------------
+unsigned int ServMgr::totalInput(bool all)
+{
+       unsigned int tot = 0;
+       Servent *s = servents;
+       while (s)
+       {
+               if (s->isConnected())
+                       if (all || !s->isPrivate())
+                               if (s->sock)
+                                       tot += s->sock->bytesInPerSec;
+               s=s->next;
+       }
+
+       return tot;
+}
+
+// -----------------------------------
+unsigned int ServMgr::numOutgoing()
+{
+       int cnt=0;
+
+       Servent *s = servents;
+       while (s)
+       {
+//             if ((s->type == Servent::T_INCOMING) ||
+//                 (s->type == Servent::T_OUTGOING)) 
+//                     cnt++;
+               s=s->next;
+       }
+       return cnt;
+}
+
+// -----------------------------------
+bool ServMgr::seenPacket(GnuPacket &p)
+{
+       Servent *s = servents;
+       while (s)
+       {
+               if (s->isConnected())
+                       if (s->seenIDs.contains(p.id))
+                               return true;
+               s=s->next;
+       }
+       return false;
+}
+
+// -----------------------------------
+void ServMgr::quit()
+{
+       LOG_DEBUG("ServMgr is quitting..");
+
+       serverThread.shutdown();
+
+       idleThread.shutdown();
+
+       Servent *s = servents;
+       while (s)
+       {
+               try
+               {
+                       if (s->thread.active)
+                       {
+                               s->thread.shutdown();
+                       }
+
+               }catch(StreamException &)
+               {
+               }
+               s=s->next;
+       }
+}
+
+// -----------------------------------
+int ServMgr::broadcast(GnuPacket &pack,Servent *src)
+{
+       int cnt=0;
+       if (pack.ttl)
+       {
+               Servent *s = servents;
+               while (s)
+               {
+
+                       if (s != src)
+                               if (s->isConnected())
+                                       if (s->type == Servent::T_PGNU)
+                                               if (!s->seenIDs.contains(pack.id))
+                                               {
+
+                                                       if (src)
+                                                               if (!src->networkID.isSame(s->networkID))
+                                                                       continue;
+
+                                                       if (s->outputPacket(pack,false))
+                                                               cnt++;
+                                               }
+                       s=s->next;
+               }
+       }
+
+       LOG_NETWORK("broadcast: %s (%d) to %d servents",GNU_FUNC_STR(pack.func),pack.ttl,cnt);
+
+       return cnt;
+}
+// -----------------------------------
+int ServMgr::route(GnuPacket &pack, GnuID &routeID, Servent *src)
+{
+       int cnt=0;
+       if (pack.ttl)
+       {
+               Servent *s = servents;
+               while (s)
+               {
+                       if (s != src)
+                               if (s->isConnected())
+                                       if (s->type == Servent::T_PGNU)
+                                               if (!s->seenIDs.contains(pack.id))
+                                                       if (s->seenIDs.contains(routeID))
+                                                       {
+                                                               if (src)
+                                                                       if (!src->networkID.isSame(s->networkID))
+                                                                               continue;
+
+                                                               if (s->outputPacket(pack,true))
+                                                                       cnt++;
+                                                       }
+                       s=s->next;
+               }
+
+       }
+
+       LOG_NETWORK("route: %s (%d) to %d servents",GNU_FUNC_STR(pack.func),pack.ttl,cnt);
+       return cnt;
+}
+// -----------------------------------
+bool ServMgr::checkForceIP()
+{
+       if (!forceIP.isEmpty())
+       {
+               unsigned int newIP = ClientSocket::getIP(forceIP.cstr());
+               if (serverHost.ip != newIP)
+               {
+                       serverHost.ip = newIP;
+                       char ipstr[64];
+                       serverHost.IPtoStr(ipstr);
+                       LOG_DEBUG("Server IP changed to %s",ipstr);
+                       return true;
+               }
+       }
+       return false;
+}
+
+// -----------------------------------
+void ServMgr::checkFirewall()
+{
+       if ((getFirewall() == FW_UNKNOWN) && !servMgr->rootHost.isEmpty())
+       {
+
+               LOG_DEBUG("Checking firewall..");
+               Host host;
+               host.fromStrName(servMgr->rootHost.cstr(),DEFAULT_PORT);
+
+               ClientSocket *sock = sys->createSocket();
+               if (!sock)
+                       throw StreamException("Unable to create socket");
+               sock->setReadTimeout(30000);
+               sock->open(host);
+               sock->connect();
+
+               AtomStream atom(*sock);
+
+               atom.writeInt(PCP_CONNECT,1);
+
+               GnuID remoteID;
+               String agent;
+               Servent::handshakeOutgoingPCP(atom,sock->host,remoteID,agent,true);
+
+               atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT);
+
+               sock->close();
+               delete sock;
+       }
+}
+
+// -----------------------------------
+void ServMgr::setFirewall(FW_STATE state)
+{
+       if (firewalled != state)
+       {
+               char *str;
+               switch (state)
+               {
+                       case FW_ON:
+                               str = "ON";
+                               break;
+                       case FW_OFF:
+                               str = "OFF";
+                               break;
+                       case FW_UNKNOWN:
+                       default:
+                               str = "UNKNOWN";
+                               break;
+               }
+
+               LOG_DEBUG("Firewall is set to %s",str);
+               firewalled = state;
+       }
+}
+// -----------------------------------
+bool ServMgr::isFiltered(int fl, Host &h)
+{
+       for(int i=0; i<numFilters; i++)
+               if (filters[i].flags & fl)
+                       if (h.isMemberOf(filters[i].host))
+                               return true;
+
+       return false;
+}
+
+#if 0
+// -----------------------------------
+bool ServMgr::canServeHost(Host &h)
+{
+       if (server)
+       {
+               Host sh = server->getHost();
+
+               if (sh.globalIP() || (sh.localIP() && h.localIP()))
+                       return true;            
+       }
+       return false;
+}
+#endif
+
+// --------------------------------------------------
+void writeServerSettings(IniFile &iniFile, unsigned int a)
+{
+       iniFile.writeBoolValue("allowHTML",a & Servent::ALLOW_HTML);
+       iniFile.writeBoolValue("allowBroadcast",a & Servent::ALLOW_BROADCAST);
+       iniFile.writeBoolValue("allowNetwork",a & Servent::ALLOW_NETWORK);
+       iniFile.writeBoolValue("allowDirect",a & Servent::ALLOW_DIRECT);
+}
+// --------------------------------------------------
+void writeFilterSettings(IniFile &iniFile, ServFilter &f)
+{
+       char ipstr[64];
+       f.host.IPtoStr(ipstr);
+       iniFile.writeStrValue("ip",ipstr);
+       iniFile.writeBoolValue("private",f.flags & ServFilter::F_PRIVATE);
+       iniFile.writeBoolValue("ban",f.flags & ServFilter::F_BAN);
+       iniFile.writeBoolValue("network",f.flags & ServFilter::F_NETWORK);
+       iniFile.writeBoolValue("direct",f.flags & ServFilter::F_DIRECT);
+}
+
+// --------------------------------------------------
+static void  writeServHost(IniFile &iniFile, ServHost &sh)
+{
+       iniFile.writeSection("Host");
+
+       char ipStr[64];
+       sh.host.toStr(ipStr);
+       iniFile.writeStrValue("type",ServHost::getTypeStr(sh.type));
+       iniFile.writeStrValue("address",ipStr);
+       iniFile.writeIntValue("time",sh.time);
+
+       iniFile.writeLine("[End]");
+}
+
+#ifdef WIN32
+extern bool guiFlg;
+extern WINDOWPLACEMENT winPlace;
+extern HWND guiWnd;
+#endif
+
+// --------------------------------------------------
+void ServMgr::saveSettings(const char *fn)
+{
+       IniFile iniFile;
+       if (!iniFile.openWriteReplace(fn))
+       {
+               LOG_ERROR("Unable to open ini file");
+       }else{
+               LOG_DEBUG("Saving settings to:  %s",fn);
+
+               char idStr[64];
+
+               iniFile.writeSection("Server");
+               iniFile.writeIntValue("serverPort",servMgr->serverHost.port);
+               iniFile.writeBoolValue("autoServe",servMgr->autoServe);
+               iniFile.writeStrValue("forceIP",servMgr->forceIP);
+               iniFile.writeBoolValue("isRoot",servMgr->isRoot);
+               iniFile.writeIntValue("maxBitrateOut",servMgr->maxBitrateOut);
+               iniFile.writeIntValue("maxRelays",servMgr->maxRelays);
+               iniFile.writeIntValue("maxDirect",servMgr->maxDirect);
+               iniFile.writeIntValue("maxRelaysPerChannel",chanMgr->maxRelaysPerChannel);
+               iniFile.writeIntValue("firewallTimeout",firewallTimeout);
+               iniFile.writeBoolValue("forceNormal",forceNormal);
+               iniFile.writeStrValue("rootMsg",rootMsg.cstr());
+               iniFile.writeStrValue("authType",servMgr->authType==ServMgr::AUTH_COOKIE?"cookie":"http-basic");
+               iniFile.writeStrValue("cookiesExpire",servMgr->cookieList.neverExpire==true?"never":"session");
+               iniFile.writeStrValue("htmlPath",servMgr->htmlPath);
+               iniFile.writeIntValue("minPGNUIncoming",servMgr->minGnuIncoming);
+               iniFile.writeIntValue("maxPGNUIncoming",servMgr->maxGnuIncoming);
+               iniFile.writeIntValue("maxServIn",servMgr->maxServIn);
+               iniFile.writeStrValue("chanLog",servMgr->chanLog.cstr());
+
+               networkID.toStr(idStr);
+               iniFile.writeStrValue("networkID",idStr);
+
+
+               iniFile.writeSection("Broadcast");
+               iniFile.writeIntValue("broadcastMsgInterval",chanMgr->broadcastMsgInterval);
+               iniFile.writeStrValue("broadcastMsg",chanMgr->broadcastMsg.cstr());
+               iniFile.writeIntValue("icyMetaInterval",chanMgr->icyMetaInterval);
+               chanMgr->broadcastID.toStr(idStr);
+               iniFile.writeStrValue("broadcastID",idStr);             
+               iniFile.writeIntValue("hostUpdateInterval",chanMgr->hostUpdateInterval);
+               iniFile.writeIntValue("maxControlConnections",servMgr->maxControl);
+               iniFile.writeStrValue("rootHost",servMgr->rootHost.cstr());
+
+               iniFile.writeSection("Client");
+               iniFile.writeIntValue("refreshHTML",refreshHTML);
+               iniFile.writeIntValue("relayBroadcast",servMgr->relayBroadcast);
+               iniFile.writeIntValue("minBroadcastTTL",chanMgr->minBroadcastTTL);
+               iniFile.writeIntValue("maxBroadcastTTL",chanMgr->maxBroadcastTTL);
+               iniFile.writeIntValue("pushTries",chanMgr->pushTries);
+               iniFile.writeIntValue("pushTimeout",chanMgr->pushTimeout);
+               iniFile.writeIntValue("maxPushHops",chanMgr->maxPushHops);
+               iniFile.writeIntValue("autoQuery",chanMgr->autoQuery);
+               iniFile.writeIntValue("queryTTL",servMgr->queryTTL);
+
+
+               iniFile.writeSection("Privacy");
+               iniFile.writeStrValue("password",servMgr->password);
+               iniFile.writeIntValue("maxUptime",chanMgr->maxUptime);
+
+               //JP-EX
+               iniFile.writeSection("Extend");
+               iniFile.writeIntValue("autoRelayKeep",servMgr->autoRelayKeep);
+               iniFile.writeIntValue("autoMaxRelaySetting",servMgr->autoMaxRelaySetting);
+               iniFile.writeIntValue("autoBumpSkipCount",servMgr->autoBumpSkipCount);
+               iniFile.writeIntValue("kickPushStartRelays",servMgr->kickPushStartRelays);
+               iniFile.writeIntValue("kickPushInterval",servMgr->kickPushInterval);
+               iniFile.writeIntValue("allowConnectPCST",servMgr->allowConnectPCST);
+               iniFile.writeIntValue("enableGetName",servMgr->enableGetName);
+
+               iniFile.writeIntValue("maxRelaysIndexTxt", servMgr->maxRelaysIndexTxt); // for PCRaw (relay)
+
+               //JP-EX
+               iniFile.writeSection("Windows");
+               iniFile.writeBoolValue("getModulePath",servMgr->getModulePath);
+               iniFile.writeBoolValue("clearPLS",servMgr->clearPLS);
+               iniFile.writeBoolValue("writeLogFile",servMgr->writeLogFile);
+
+               //VP-EX
+               iniFile.writeStrValue("rootHost2",servMgr->rootHost2.cstr());
+               iniFile.writeBoolValue("autoPort0Kick",servMgr->autoPort0Kick);
+               iniFile.writeBoolValue("allowOnlyVP",servMgr->allowOnlyVP);
+               iniFile.writeIntValue("kickKeepTime",servMgr->kickKeepTime);
+               iniFile.writeBoolValue("vpDebug", servMgr->vpDebug);
+               iniFile.writeBoolValue("saveIniChannel", servMgr->saveIniChannel);
+#ifdef WIN32
+               iniFile.writeBoolValue("saveGuiPos", servMgr->saveGuiPos);
+               if (guiFlg){
+                       GetWindowPlacement(guiWnd, &winPlace);
+                       iniFile.writeIntValue("guiTop", winPlace.rcNormalPosition.top);
+                       iniFile.writeIntValue("guiBottom", winPlace.rcNormalPosition.bottom);
+                       iniFile.writeIntValue("guiLeft", winPlace.rcNormalPosition.left);
+                       iniFile.writeIntValue("guiRight", winPlace.rcNormalPosition.right);
+               }
+#endif
+               int i;
+
+               for(i=0; i<servMgr->numFilters; i++)
+               {
+                       iniFile.writeSection("Filter");
+                               writeFilterSettings(iniFile,servMgr->filters[i]);
+                       iniFile.writeLine("[End]");
+               }
+
+               iniFile.writeSection("Notify");
+                       iniFile.writeBoolValue("PeerCast",notifyMask&NT_PEERCAST);
+                       iniFile.writeBoolValue("Broadcasters",notifyMask&NT_BROADCASTERS);
+                       iniFile.writeBoolValue("TrackInfo",notifyMask&NT_TRACKINFO);
+               iniFile.writeLine("[End]");
+
+
+               iniFile.writeSection("Server1");
+                       writeServerSettings(iniFile,allowServer1);
+               iniFile.writeLine("[End]");
+
+               iniFile.writeSection("Server2");
+                       writeServerSettings(iniFile,allowServer2);
+               iniFile.writeLine("[End]");
+
+
+
+               iniFile.writeSection("Debug");
+               iniFile.writeBoolValue("logDebug",(showLog&(1<<LogBuffer::T_DEBUG))!=0);
+               iniFile.writeBoolValue("logErrors",(showLog&(1<<LogBuffer::T_ERROR))!=0);
+               iniFile.writeBoolValue("logNetwork",(showLog&(1<<LogBuffer::T_NETWORK))!=0);
+               iniFile.writeBoolValue("logChannel",(showLog&(1<<LogBuffer::T_CHANNEL))!=0);
+               iniFile.writeBoolValue("pauseLog",pauseLog);
+               iniFile.writeIntValue("idleSleepTime",sys->idleSleepTime);
+
+
+               if (servMgr->validBCID)
+               {
+                       BCID *bcid = servMgr->validBCID;
+                       while (bcid)
+                       {
+                               iniFile.writeSection("ValidBCID");
+                               char idstr[128];
+                               bcid->id.toStr(idstr);
+                               iniFile.writeStrValue("id",idstr);
+                               iniFile.writeStrValue("name",bcid->name.cstr());
+                               iniFile.writeStrValue("email",bcid->email.cstr());
+                               iniFile.writeStrValue("url",bcid->url.cstr());
+                               iniFile.writeBoolValue("valid",bcid->valid);
+                               iniFile.writeLine("[End]");
+                               
+                               bcid=bcid->next;
+                       }
+               }
+
+               if (servMgr->saveIniChannel){
+                       Channel *c = chanMgr->channel;
+                       while (c)
+                       {
+                               char idstr[64];
+                               if (c->isActive() && c->stayConnected)
+                               {
+                                       c->getIDStr(idstr);
+
+                                       iniFile.writeSection("RelayChannel");
+                                       iniFile.writeStrValue("name",c->getName());
+                                       iniFile.writeStrValue("genre",c->info.genre.cstr());
+                                       if (!c->sourceURL.isEmpty())
+                                               iniFile.writeStrValue("sourceURL",c->sourceURL.cstr());
+                                       iniFile.writeStrValue("sourceProtocol",ChanInfo::getProtocolStr(c->info.srcProtocol));
+                                       iniFile.writeStrValue("contentType",ChanInfo::getTypeStr(c->info.contentType));
+                                       iniFile.writeIntValue("bitrate",c->info.bitrate);
+                                       iniFile.writeStrValue("contactURL",c->info.url.cstr());
+                                       iniFile.writeStrValue("id",idstr);
+                                       iniFile.writeBoolValue("stayConnected",c->stayConnected);
+
+                                       ChanHitList *chl = chanMgr->findHitListByID(c->info.id);
+                                       if (chl)
+                                       {
+
+                                               ChanHitSearch chs;
+                                               chs.trackersOnly = true;
+                                               if (chl->pickHits(chs))
+                                               {
+                                                       char ipStr[64];
+                                                       chs.best[0].host.toStr(ipStr);
+                                                       iniFile.writeStrValue("tracker",ipStr);
+                                               }
+                                       }
+                                       iniFile.writeLine("[End]");
+                               }
+                               c=c->next;
+                       }
+               }
+               
+
+               
+#if 0
+               Servent *s = servents;
+               while (s)
+               {
+                       if (s->type == Servent::T_OUTGOING)
+                               if (s->isConnected())
+                               {
+                                       ServHost sh;
+                                       Host h = s->getHost();
+                                       sh.init(h,ServHost::T_SERVENT,0,s->networkID);
+                                       writeServHost(iniFile,sh);
+                               }
+                       s=s->next;
+               }
+#endif
+
+               for(i=0; i<ServMgr::MAX_HOSTCACHE; i++)
+               {
+                       ServHost *sh = &servMgr->hostCache[i];
+                       if (sh->type != ServHost::T_NONE)
+                               writeServHost(iniFile,*sh);
+               }
+
+               iniFile.close();
+       }
+}
+// --------------------------------------------------
+unsigned int readServerSettings(IniFile &iniFile, unsigned int a)
+{
+       while (iniFile.readNext())
+       {
+               if (iniFile.isName("[End]"))
+                       break;
+               else if (iniFile.isName("allowHTML"))
+                       a = iniFile.getBoolValue()?a|Servent::ALLOW_HTML:a&~Servent::ALLOW_HTML;
+               else if (iniFile.isName("allowDirect"))
+                       a = iniFile.getBoolValue()?a|Servent::ALLOW_DIRECT:a&~Servent::ALLOW_DIRECT;
+               else if (iniFile.isName("allowNetwork"))
+                       a = iniFile.getBoolValue()?a|Servent::ALLOW_NETWORK:a&~Servent::ALLOW_NETWORK;
+               else if (iniFile.isName("allowBroadcast"))
+                       a = iniFile.getBoolValue()?a|Servent::ALLOW_BROADCAST:a&~Servent::ALLOW_BROADCAST;
+       }
+       return a;
+}
+// --------------------------------------------------
+void readFilterSettings(IniFile &iniFile, ServFilter &sv)
+{
+       sv.host.init();
+
+       while (iniFile.readNext())
+       {
+               if (iniFile.isName("[End]"))
+                       break;
+               else if (iniFile.isName("ip"))
+                       sv.host.fromStrIP(iniFile.getStrValue(),0);
+               else if (iniFile.isName("private"))
+                       sv.flags = (sv.flags & ~ServFilter::F_PRIVATE) | (iniFile.getBoolValue()?ServFilter::F_PRIVATE:0);
+               else if (iniFile.isName("ban"))
+                       sv.flags = (sv.flags & ~ServFilter::F_BAN) | (iniFile.getBoolValue()?ServFilter::F_BAN:0);
+               else if (iniFile.isName("allow") || iniFile.isName("network"))
+                       sv.flags = (sv.flags & ~ServFilter::F_NETWORK) | (iniFile.getBoolValue()?ServFilter::F_NETWORK:0);
+               else if (iniFile.isName("direct"))
+                       sv.flags = (sv.flags & ~ServFilter::F_DIRECT) | (iniFile.getBoolValue()?ServFilter::F_DIRECT:0);
+       }
+
+}
+// --------------------------------------------------
+void ServMgr::loadSettings(const char *fn)
+{
+       IniFile iniFile;
+
+       if (!iniFile.openReadOnly(fn))
+               saveSettings(fn);
+
+
+       servMgr->numFilters = 0;
+       showLog = 0;
+
+       if (iniFile.openReadOnly(fn))
+       {
+               while (iniFile.readNext())
+               {
+                       // server settings
+                       if (iniFile.isName("serverPort"))
+                               servMgr->serverHost.port = iniFile.getIntValue();
+                       else if (iniFile.isName("autoServe"))
+                               servMgr->autoServe = iniFile.getBoolValue();
+                       else if (iniFile.isName("autoConnect"))
+                               servMgr->autoConnect = iniFile.getBoolValue();
+                       else if (iniFile.isName("icyPassword"))         // depreciated
+                               strcpy(servMgr->password,iniFile.getStrValue());
+                       else if (iniFile.isName("forceIP"))
+                               servMgr->forceIP = iniFile.getStrValue();
+                       else if (iniFile.isName("isRoot"))
+                               servMgr->isRoot = iniFile.getBoolValue();
+                       else if (iniFile.isName("broadcastID"))
+                       {
+                               chanMgr->broadcastID.fromStr(iniFile.getStrValue());
+                               chanMgr->broadcastID.id[0] = PCP_BROADCAST_FLAGS;                       // hacky, but we need to fix old clients
+
+                       }else if (iniFile.isName("htmlPath"))
+                               strcpy(servMgr->htmlPath,iniFile.getStrValue());
+                       else if (iniFile.isName("maxPGNUIncoming"))
+                               servMgr->maxGnuIncoming = iniFile.getIntValue();
+                       else if (iniFile.isName("minPGNUIncoming"))
+                               servMgr->minGnuIncoming = iniFile.getIntValue();
+
+                       else if (iniFile.isName("maxControlConnections"))
+                       {
+                               servMgr->maxControl = iniFile.getIntValue();
+
+                       }
+                       else if (iniFile.isName("maxBitrateOut"))
+                               servMgr->maxBitrateOut = iniFile.getIntValue();
+
+                       else if (iniFile.isName("maxStreamsOut"))               // depreciated
+                               servMgr->setMaxRelays(iniFile.getIntValue());
+                       else if (iniFile.isName("maxRelays"))           
+                               servMgr->setMaxRelays(iniFile.getIntValue());
+                       else if (iniFile.isName("maxDirect"))           
+                               servMgr->maxDirect = iniFile.getIntValue();
+
+                       else if (iniFile.isName("maxStreamsPerChannel"))                // depreciated
+                               chanMgr->maxRelaysPerChannel = iniFile.getIntValue();
+                       else if (iniFile.isName("maxRelaysPerChannel"))
+                               chanMgr->maxRelaysPerChannel = iniFile.getIntValue();
+
+                       else if (iniFile.isName("firewallTimeout"))
+                               firewallTimeout = iniFile.getIntValue();
+                       else if (iniFile.isName("forceNormal"))
+                               forceNormal = iniFile.getBoolValue();
+                       else if (iniFile.isName("broadcastMsgInterval"))
+                               chanMgr->broadcastMsgInterval = iniFile.getIntValue();
+                       else if (iniFile.isName("broadcastMsg"))
+                               chanMgr->broadcastMsg.set(iniFile.getStrValue(),String::T_ASCII);
+                       else if (iniFile.isName("hostUpdateInterval"))
+                               chanMgr->hostUpdateInterval = iniFile.getIntValue();
+                       else if (iniFile.isName("icyMetaInterval"))
+                               chanMgr->icyMetaInterval = iniFile.getIntValue();
+                       else if (iniFile.isName("maxServIn"))
+                               servMgr->maxServIn = iniFile.getIntValue();
+                       else if (iniFile.isName("chanLog"))
+                               servMgr->chanLog.set(iniFile.getStrValue(),String::T_ASCII);
+
+                       else if (iniFile.isName("rootMsg"))
+                               rootMsg.set(iniFile.getStrValue());
+                       else if (iniFile.isName("networkID"))
+                               networkID.fromStr(iniFile.getStrValue());
+                       else if (iniFile.isName("authType"))
+                       {
+                               char *t = iniFile.getStrValue();
+                               if (stricmp(t,"cookie")==0)
+                                       servMgr->authType = ServMgr::AUTH_COOKIE;
+                               else if (stricmp(t,"http-basic")==0)
+                                       servMgr->authType = ServMgr::AUTH_HTTPBASIC;
+                       }else if (iniFile.isName("cookiesExpire"))
+                       {
+                               char *t = iniFile.getStrValue();
+                               if (stricmp(t,"never")==0)
+                                       servMgr->cookieList.neverExpire = true;
+                               else if (stricmp(t,"session")==0)
+                                       servMgr->cookieList.neverExpire = false;
+
+
+                       }
+
+                       // privacy settings
+                       else if (iniFile.isName("password"))
+                               strcpy(servMgr->password,iniFile.getStrValue());
+                       else if (iniFile.isName("maxUptime"))
+                               chanMgr->maxUptime = iniFile.getIntValue();
+
+                       // client settings
+
+                       else if (iniFile.isName("rootHost"))
+                       {
+                               if (!PCP_FORCE_YP)
+                                       servMgr->rootHost = iniFile.getStrValue();
+
+                       }else if (iniFile.isName("deadHitAge"))
+                               chanMgr->deadHitAge = iniFile.getIntValue();
+                       else if (iniFile.isName("tryoutDelay"))
+                               servMgr->tryoutDelay = iniFile.getIntValue();
+                       else if (iniFile.isName("refreshHTML"))
+                               refreshHTML = iniFile.getIntValue();
+                       else if (iniFile.isName("relayBroadcast"))
+                       {
+                               servMgr->relayBroadcast = iniFile.getIntValue();
+                               if (servMgr->relayBroadcast < 30)
+                                       servMgr->relayBroadcast = 30;
+                       }
+                       else if (iniFile.isName("minBroadcastTTL"))
+                               chanMgr->minBroadcastTTL = iniFile.getIntValue();
+                       else if (iniFile.isName("maxBroadcastTTL"))
+                               chanMgr->maxBroadcastTTL = iniFile.getIntValue();
+                       else if (iniFile.isName("pushTimeout"))
+                               chanMgr->pushTimeout = iniFile.getIntValue();
+                       else if (iniFile.isName("pushTries"))
+                               chanMgr->pushTries = iniFile.getIntValue();
+                       else if (iniFile.isName("maxPushHops"))
+                               chanMgr->maxPushHops = iniFile.getIntValue();
+                       else if (iniFile.isName("autoQuery"))
+                       {
+                               chanMgr->autoQuery = iniFile.getIntValue();
+                               if ((chanMgr->autoQuery < 300) && (chanMgr->autoQuery > 0))
+                                       chanMgr->autoQuery = 300;
+                       }
+                       else if (iniFile.isName("queryTTL"))
+                       {
+                               servMgr->queryTTL = iniFile.getIntValue();
+                       }
+
+                       //JP-Extend
+                       else if (iniFile.isName("autoRelayKeep"))
+                               servMgr->autoRelayKeep = iniFile.getIntValue();
+                       else if (iniFile.isName("autoMaxRelaySetting"))
+                               servMgr->autoMaxRelaySetting = iniFile.getIntValue();
+                       else if (iniFile.isName("autoBumpSkipCount"))
+                               servMgr->autoBumpSkipCount = iniFile.getIntValue();
+                       else if (iniFile.isName("kickPushStartRelays"))
+                               servMgr->kickPushStartRelays = iniFile.getIntValue();
+                       else if (iniFile.isName("kickPushInterval"))
+                       {
+                               servMgr->kickPushInterval = iniFile.getIntValue();
+                               if (servMgr->kickPushInterval < 60)
+                                       servMgr->kickPushInterval = 0;
+                       }
+                       else if (iniFile.isName("allowConnectPCST"))
+                               servMgr->allowConnectPCST = iniFile.getIntValue();
+                       else if (iniFile.isName("enableGetName"))
+                               servMgr->enableGetName = iniFile.getIntValue();
+
+                       else if (iniFile.isName("maxRelaysIndexTxt"))                   // for PCRaw (relay)
+                               servMgr->maxRelaysIndexTxt = iniFile.getIntValue();
+
+                       //JP-Windows
+                       else if (iniFile.isName("getModulePath"))
+                               servMgr->getModulePath = iniFile.getBoolValue();
+                       else if (iniFile.isName("clearPLS"))
+                               servMgr->clearPLS = iniFile.getBoolValue();
+                       else if (iniFile.isName("writeLogFile"))
+                               servMgr->writeLogFile = iniFile.getBoolValue();
+
+                       //VP-EX
+                       else if (iniFile.isName("rootHost2"))
+                       {
+                               if (!PCP_FORCE_YP)
+                                       servMgr->rootHost2 = iniFile.getStrValue();
+                       }
+                       else if (iniFile.isName("autoPort0Kick"))
+                               servMgr->autoPort0Kick = iniFile.getBoolValue();
+                       else if (iniFile.isName("allowOnlyVP"))
+                               servMgr->allowOnlyVP = iniFile.getBoolValue();
+                       else if (iniFile.isName("kickKeepTime"))
+                               servMgr->kickKeepTime = iniFile.getIntValue();
+                       else if (iniFile.isName("vpDebug"))
+                               servMgr->vpDebug = iniFile.getBoolValue();
+                       else if (iniFile.isName("saveIniChannel"))
+                               servMgr->saveIniChannel = iniFile.getBoolValue();
+#ifdef WIN32
+                       else if (iniFile.isName("saveGuiPos"))
+                               servMgr->saveGuiPos = iniFile.getBoolValue();
+                       else if (iniFile.isName("guiTop"))
+                               winPlace.rcNormalPosition.top = iniFile.getIntValue();
+                       else if (iniFile.isName("guiBottom"))
+                               winPlace.rcNormalPosition.bottom = iniFile.getIntValue();
+                       else if (iniFile.isName("guiLeft"))
+                               winPlace.rcNormalPosition.left = iniFile.getIntValue();
+                       else if (iniFile.isName("guiRight")){
+                               winPlace.rcNormalPosition.right = iniFile.getIntValue();
+                               winPlace.length = sizeof(winPlace);
+                               winPlace.flags = 0;
+                               winPlace.showCmd = 1;
+                               winPlace.ptMinPosition.x = -1;
+                               winPlace.ptMinPosition.y = -1;
+                               winPlace.ptMaxPosition.x = -1;
+                               winPlace.ptMaxPosition.y = -1;
+                               if (servMgr->saveGuiPos){
+                                       guiFlg = true;
+                               }
+                       }
+#endif
+
+                       // debug
+                       else if (iniFile.isName("logDebug"))
+                               showLog |= iniFile.getBoolValue() ? 1<<LogBuffer::T_DEBUG:0;
+                       else if (iniFile.isName("logErrors"))
+                               showLog |= iniFile.getBoolValue() ? 1<<LogBuffer::T_ERROR:0;
+                       else if (iniFile.isName("logNetwork"))
+                               showLog |= iniFile.getBoolValue() ? 1<<LogBuffer::T_NETWORK:0;
+                       else if (iniFile.isName("logChannel"))
+                               showLog |= iniFile.getBoolValue() ? 1<<LogBuffer::T_CHANNEL:0;
+                       else if (iniFile.isName("pauseLog"))
+                               pauseLog = iniFile.getBoolValue();
+                       else if (iniFile.isName("idleSleepTime"))
+                               sys->idleSleepTime = iniFile.getIntValue();
+                       else if (iniFile.isName("[Server1]"))
+                               allowServer1 = readServerSettings(iniFile,allowServer1);
+                       else if (iniFile.isName("[Server2]"))
+                               allowServer2 = readServerSettings(iniFile,allowServer2);
+                       else if (iniFile.isName("[Filter]"))
+                       {
+                               readFilterSettings(iniFile,filters[numFilters]);
+
+                               if (numFilters < (MAX_FILTERS-1))
+                                       numFilters++;
+                       }
+                       else if (iniFile.isName("[Notify]"))
+                       {
+                               notifyMask = NT_UPGRADE;
+                               while (iniFile.readNext())
+                               {
+                                       if (iniFile.isName("[End]"))
+                                               break;
+                                       else if (iniFile.isName("PeerCast"))
+                                               notifyMask |= iniFile.getBoolValue()?NT_PEERCAST:0;
+                                       else if (iniFile.isName("Broadcasters"))
+                                               notifyMask |= iniFile.getBoolValue()?NT_BROADCASTERS:0;
+                                       else if (iniFile.isName("TrackInfo"))
+                                               notifyMask |= iniFile.getBoolValue()?NT_TRACKINFO:0;
+                               }
+
+                       }
+                       else if (iniFile.isName("[RelayChannel]"))
+                       {
+                               ChanInfo info;
+                               bool stayConnected=false;
+                               String sourceURL;
+                               while (iniFile.readNext())
+                               {
+                                       if (iniFile.isName("[End]"))
+                                               break;
+                                       else if (iniFile.isName("name"))
+                                               info.name.set(iniFile.getStrValue());
+                                       else if (iniFile.isName("id"))
+                                               info.id.fromStr(iniFile.getStrValue());
+                                       else if (iniFile.isName("sourceType"))
+                                               info.srcProtocol = ChanInfo::getProtocolFromStr(iniFile.getStrValue());
+                                       else if (iniFile.isName("contentType"))
+                                               info.contentType = ChanInfo::getTypeFromStr(iniFile.getStrValue());
+                                       else if (iniFile.isName("stayConnected"))
+                                               stayConnected = iniFile.getBoolValue();
+                                       else if (iniFile.isName("sourceURL"))
+                                               sourceURL.set(iniFile.getStrValue());
+                                       else if (iniFile.isName("genre"))
+                                               info.genre.set(iniFile.getStrValue());
+                                       else if (iniFile.isName("contactURL"))
+                                               info.url.set(iniFile.getStrValue());
+                                       else if (iniFile.isName("bitrate"))
+                                               info.bitrate = atoi(iniFile.getStrValue());
+                                       else if (iniFile.isName("tracker"))
+                                       {
+                                               ChanHit hit;
+                                               hit.init();
+                                               hit.tracker = true;
+                                               hit.host.fromStrName(iniFile.getStrValue(),DEFAULT_PORT);
+                                               hit.rhost[0] = hit.host;
+                                               hit.rhost[1] = hit.host;
+                                               hit.chanID = info.id;
+                                               hit.recv = true;
+                                               chanMgr->addHit(hit);
+                                       }
+
+                               }
+                               if (sourceURL.isEmpty())
+                               {
+                                       chanMgr->createRelay(info,stayConnected);
+                               }else
+                               {
+                                       info.bcID = chanMgr->broadcastID;
+                                       Channel *c = chanMgr->createChannel(info,NULL);
+                                       if (c)
+                                               c->startURL(sourceURL.cstr());
+                               }
+                       } else if (iniFile.isName("[Host]"))
+                       {
+                               Host h;
+                               ServHost::TYPE type=ServHost::T_NONE;
+                               bool firewalled=false;
+                               unsigned int time=0;
+                               while (iniFile.readNext())
+                               {
+                                       if (iniFile.isName("[End]"))
+                                               break;
+                                       else if (iniFile.isName("address"))
+                                               h.fromStrIP(iniFile.getStrValue(),DEFAULT_PORT);
+                                       else if (iniFile.isName("type"))
+                                               type = ServHost::getTypeFromStr(iniFile.getStrValue());
+                                       else if (iniFile.isName("time"))
+                                               time = iniFile.getIntValue();
+                               }
+                               servMgr->addHost(h,type,time);
+
+                       } else if (iniFile.isName("[ValidBCID]"))
+                       {
+                               BCID *bcid = new BCID();
+                               while (iniFile.readNext())
+                               {
+                                       if (iniFile.isName("[End]"))
+                                               break;
+                                       else if (iniFile.isName("id"))
+                                               bcid->id.fromStr(iniFile.getStrValue());
+                                       else if (iniFile.isName("name"))
+                                               bcid->name.set(iniFile.getStrValue());
+                                       else if (iniFile.isName("email"))
+                                               bcid->email.set(iniFile.getStrValue());
+                                       else if (iniFile.isName("url"))
+                                               bcid->url.set(iniFile.getStrValue());
+                                       else if (iniFile.isName("valid"))
+                                               bcid->valid = iniFile.getBoolValue();
+                               }
+                               servMgr->addValidBCID(bcid);
+                       }
+               }       
+       }
+
+       if (!numFilters)
+               setFilterDefaults();
+
+}
+
+// --------------------------------------------------
+unsigned int ServMgr::numStreams(GnuID &cid, Servent::TYPE tp, bool all)
+{
+       int cnt = 0;
+       Servent *sv = servents;
+       while (sv)
+       {
+               if (sv->isConnected())
+                       if (sv->type == tp)
+                               if (sv->chanID.isSame(cid))
+                                       if (all || !sv->isPrivate())
+                                               cnt++;
+               sv=sv->next;
+       }
+       return cnt;
+}
+// --------------------------------------------------
+unsigned int ServMgr::numStreams(Servent::TYPE tp, bool all)
+{
+       int cnt = 0;
+       Servent *sv = servents;
+       while (sv)
+       {
+               if (sv->isConnected())
+                       if (sv->type == tp)
+                               if (all || !sv->isPrivate())
+                               {
+                                       // for PCRaw (relay) start.
+                                       if(tp == Servent::T_RELAY)
+                                       {
+                                               Channel *ch = chanMgr->findChannelByID(sv->chanID);
+
+                                               // index.txt\82Í\83J\83E\83\93\83g\82µ\82È\82¢
+                                               if(!isIndexTxt(ch))
+                                                       cnt++;
+                                       }
+                                       else
+                                       // for PCRaw (relay) end.
+                                       {
+                                               cnt++;
+                                       }
+                               }
+               sv=sv->next;
+       }
+       return cnt;
+}
+
+// --------------------------------------------------
+bool ServMgr::getChannel(char *str,ChanInfo &info, bool relay)
+{
+       // remove file extension (only added for winamp)
+       //char *ext = strstr(str,".");
+       //if (ext) *ext = 0;
+
+       procConnectArgs(str,info);
+
+       WLockBlock wb(&(chanMgr->channellock));
+
+       wb.on();
+       Channel *ch;
+
+       ch = chanMgr->findChannelByNameID(info);
+       if (ch && ch->thread.active)
+       {
+
+               if (!ch->isPlaying())
+               {
+                       if (relay)
+                       {
+                               ch->info.lastPlayStart = 0; // force reconnect 
+                               ch->info.lastPlayEnd = 0; 
+                       }else
+                               return false;
+               }
+               
+               info = ch->info;        // get updated channel info 
+
+               return true;
+       }else
+       {
+               if (relay)
+               {
+                       wb.off();
+                       ch = chanMgr->findAndRelay(info);
+                       if (ch)
+                       {
+                               // \81«Exception point
+                               info = ch->info; //get updated channel info 
+                               return true;
+                       }
+               }
+       }
+
+       return false;
+}
+// --------------------------------------------------
+int ServMgr::findChannel(ChanInfo &info)
+{
+#if 0
+       char idStr[64];
+       info.id.toStr(idStr);
+
+
+       if (info.id.isSet())
+       {
+               // if we have an ID then try and connect to known hosts carrying channel.
+               ServHost sh = getOutgoingServent(info.id);
+               addOutgoing(sh.host,info.id,true);
+       }
+
+       GnuPacket pack;
+
+       XML xml;
+       XML::Node *n = info.createQueryXML();
+       xml.setRoot(n);
+       pack.initFind(NULL,&xml,servMgr->queryTTL);
+
+       addReplyID(pack.id);
+       int cnt = broadcast(pack,NULL);
+
+       LOG_NETWORK("Querying network: %s %s - %d servents",info.name.cstr(),idStr,cnt);
+
+       return cnt;
+#endif
+       return 0;
+}
+// --------------------------------------------------
+// add outgoing network connection from string (ip:port format)
+bool ServMgr::addOutgoing(Host h, GnuID &netid, bool pri)
+{
+#if 0
+       if (h.ip)
+       {
+               if (!findServent(h.ip,h.port,netid))
+               {
+                       Servent *sv = allocServent();
+                       if (sv)
+                       {
+                               if (pri)
+                                       sv->priorityConnect = true;
+                               sv->networkID = netid;
+                               sv->initOutgoing(h,Servent::T_OUTGOING);
+                               return true;
+                       }
+               }
+       }
+#endif
+       return false;
+}
+// --------------------------------------------------
+Servent *ServMgr::findConnection(Servent::TYPE t,GnuID &sid)
+{
+       Servent *sv = servents;
+       while (sv)
+       {
+               if (sv->isConnected())
+                       if (sv->type == t)
+                               if (sv->remoteID.isSame(sid))                           
+                                       return sv;
+               sv=sv->next;
+       }
+       return NULL;
+}
+
+// --------------------------------------------------
+void ServMgr::procConnectArgs(char *str,ChanInfo &info)
+{
+       char arg[MAX_CGI_LEN];
+       char curr[MAX_CGI_LEN];
+
+       char *args = strstr(str,"?");
+       if (args)
+               *args++=0;
+
+       info.initNameID(str);
+
+       if (args)
+       {
+
+               while (args=nextCGIarg(args,curr,arg))
+               {
+                       LOG_DEBUG("cmd: %s, arg: %s",curr,arg);
+
+                       if (strcmp(curr,"sip")==0)
+                       // sip - add network connection to client with channel
+                       {
+                               Host h;
+                               h.fromStrName(arg,DEFAULT_PORT);
+                               if (addOutgoing(h,servMgr->networkID,true))
+                                       LOG_NETWORK("Added connection: %s",arg);
+
+                       }else if (strcmp(curr,"pip")==0)
+                       // pip - add private network connection to client with channel
+                       {
+                               Host h;
+                               h.fromStrName(arg,DEFAULT_PORT);
+                               if (addOutgoing(h,info.id,true))
+                                       LOG_NETWORK("Added private connection: %s",arg);
+                       }else if (strcmp(curr,"ip")==0)
+                       // ip - add hit
+                       {
+                               Host h;
+                               h.fromStrName(arg,DEFAULT_PORT);
+                               ChanHit hit;
+                               hit.init();
+                               hit.host = h; 
+                               hit.rhost[0] = h;
+                               hit.rhost[1].init();
+                               hit.chanID = info.id;
+                               hit.recv = true;
+
+                               chanMgr->addHit(hit);
+                       }else if (strcmp(curr,"tip")==0)
+                       // tip - add tracker hit
+                       {
+                               Host h;
+                               h.fromStrName(arg,DEFAULT_PORT);
+                               chanMgr->hitlistlock.on();
+                               chanMgr->addHit(h,info.id,true);
+                               chanMgr->hitlistlock.off();
+
+                       }
+
+
+               }
+       }
+}
+
+// --------------------------------------------------
+bool ServMgr::start()
+{
+       char idStr[64];
+
+
+       const char *priv;
+#if PRIVATE_BROADCASTER
+       priv = "(private)";
+#else
+       priv = "";
+#endif
+#ifdef VERSION_EX
+       LOG_DEBUG("Peercast %s, %s %s",PCX_VERSTRING_EX,peercastApp->getClientTypeOS(),priv);
+#else
+       LOG_DEBUG("Peercast %s, %s %s",PCX_VERSTRING,peercastApp->getClientTypeOS(),priv);
+#endif
+
+       sessionID.toStr(idStr);
+       LOG_DEBUG("SessionID: %s",idStr);
+
+       chanMgr->broadcastID.toStr(idStr);
+       LOG_DEBUG("BroadcastID: %s",idStr);
+       checkForceIP();
+
+
+       serverThread.func = ServMgr::serverProc;
+       if (!sys->startThread(&serverThread))
+               return false;
+
+       idleThread.func = ServMgr::idleProc;
+       if (!sys->startThread(&idleThread))
+               return false;
+
+       return true;
+}
+// --------------------------------------------------
+int ServMgr::clientProc(ThreadInfo *thread)
+{
+#if 0
+       thread->lock();
+
+       GnuID netID;
+       netID = servMgr->networkID;
+
+       while(thread->active)
+       {
+               if (servMgr->autoConnect)
+               {
+                       if (servMgr->needConnections() || servMgr->forceLookup)
+                       {
+                               if (servMgr->needHosts() || servMgr->forceLookup)
+                               {
+                                       // do lookup to find some hosts
+
+                                       Host lh;
+                                       lh.fromStrName(servMgr->connectHost,DEFAULT_PORT);
+
+
+                                       if (!servMgr->findServent(lh.ip,lh.port,netID))
+                                       {
+                                               Servent *sv = servMgr->allocServent();
+                                               if (sv)
+                                               {
+                                                       LOG_DEBUG("Lookup: %s",servMgr->connectHost);
+                                                       sv->networkID = netID;
+                                                       sv->initOutgoing(lh,Servent::T_LOOKUP);
+                                                       servMgr->forceLookup = false;
+                                               }
+                                       }
+                               }
+
+                               for(int i=0; i<MAX_TRYOUT; i++)
+                               {
+                                       if (servMgr->outUsedFull())
+                                               break;
+                                       if (servMgr->tryFull())
+                                               break;
+
+
+                                       ServHost sh = servMgr->getOutgoingServent(netID);
+
+                                       if (!servMgr->addOutgoing(sh.host,netID,false))
+                                               servMgr->deadHost(sh.host,ServHost::T_SERVENT);
+                                       sys->sleep(servMgr->tryoutDelay);
+                                       break;
+                               }
+                       }
+               }else{
+#if 0
+                       Servent *s = servMgr->servents;
+                       while (s)
+                       {
+
+                               if (s->type == Servent::T_OUTGOING) 
+                                       s->thread.active = false;
+                               s=s->next;
+                       }
+#endif
+               }
+               sys->sleepIdle();
+       }
+       thread->unlock();
+#endif
+       return 0;
+}
+// -----------------------------------
+bool   ServMgr::acceptGIV(ClientSocket *sock)
+{
+       Servent *sv = servents;
+       while (sv)
+       {
+               if (sv->type == Servent::T_COUT)
+               {
+                       if (sv->acceptGIV(sock))
+                               return true;
+               }
+               sv=sv->next;
+       }
+       return false;
+}
+
+// -----------------------------------
+int ServMgr::broadcastPushRequest(ChanHit &hit, Host &to, GnuID &chanID, Servent::TYPE type)
+{
+       ChanPacket pack;
+       MemoryStream pmem(pack.data,sizeof(pack.data));
+       AtomStream atom(pmem);
+
+#ifndef VERSION_EX
+               atom.writeParent(PCP_BCST,8);
+#else
+               atom.writeParent(PCP_BCST,10);
+#endif
+               atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_ALL);
+               atom.writeChar(PCP_BCST_HOPS,0);
+               atom.writeChar(PCP_BCST_TTL,7);
+               atom.writeBytes(PCP_BCST_DEST,hit.sessionID.id,16);
+               atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
+               atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
+               atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
+#ifdef VERSION_EX
+               atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
+               atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
+#endif
+               atom.writeParent(PCP_PUSH,3);
+                       atom.writeInt(PCP_PUSH_IP,to.ip);
+                       atom.writeShort(PCP_PUSH_PORT,to.port);
+                       atom.writeBytes(PCP_PUSH_CHANID,chanID.id,16);
+
+
+       pack.len = pmem.pos;
+       pack.type = ChanPacket::T_PCP;
+
+
+       GnuID noID;
+       noID.clear();
+
+       return servMgr->broadcastPacket(pack,noID,servMgr->sessionID,hit.sessionID,type);
+}
+
+// --------------------------------------------------
+void ServMgr::writeRootAtoms(AtomStream &atom, bool getUpdate)
+{
+       atom.writeParent(PCP_ROOT,5 + (getUpdate?1:0));
+               atom.writeInt(PCP_ROOT_UPDINT,chanMgr->hostUpdateInterval);
+               atom.writeString(PCP_ROOT_URL,"download.php");
+               atom.writeInt(PCP_ROOT_CHECKVER,PCP_ROOT_VERSION);
+               atom.writeInt(PCP_ROOT_NEXT,chanMgr->hostUpdateInterval);
+               atom.writeString(PCP_MESG_ASCII,rootMsg.cstr());
+               if (getUpdate)
+                       atom.writeParent(PCP_ROOT_UPDATE,0);
+
+}
+// --------------------------------------------------
+void ServMgr::broadcastRootSettings(bool getUpdate)
+{
+       if (isRoot)
+       {
+
+               ChanPacket pack;
+               MemoryStream mem(pack.data,sizeof(pack.data));
+               AtomStream atom(mem);
+#ifndef VERSION_EX
+                       atom.writeParent(PCP_BCST,7);
+#else
+                       atom.writeParent(PCP_BCST,9);
+#endif
+                       atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_TRACKERS);
+                       atom.writeChar(PCP_BCST_HOPS,0);
+                       atom.writeChar(PCP_BCST_TTL,7);
+                       atom.writeBytes(PCP_BCST_FROM,sessionID.id,16);
+                       atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
+                       atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
+#ifdef VERSION_EX
+                       atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
+                       atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
+#endif
+                       writeRootAtoms(atom,getUpdate);
+
+               mem.len = mem.pos;
+               mem.rewind();
+               pack.len = mem.len;
+
+               GnuID noID;
+               noID.clear();
+
+               broadcastPacket(pack,noID,servMgr->sessionID,noID,Servent::T_CIN);
+       }
+}
+// --------------------------------------------------
+int ServMgr::broadcastPacket(ChanPacket &pack,GnuID &chanID,GnuID &srcID, GnuID &destID, Servent::TYPE type)
+{
+       int cnt=0;
+       
+       Servent *sv = servents;
+       while (sv)
+       {
+               if (sv->sendPacket(pack,chanID,srcID,destID,type))
+                       cnt++;
+               sv=sv->next;
+       }
+       return cnt;
+}
+
+// --------------------------------------------------
+int ServMgr::idleProc(ThreadInfo *thread)
+{
+
+//     thread->lock();
+
+       unsigned int lastPasvFind=0;
+       unsigned int lastBroadcast=0;
+
+
+       // nothing much to do for the first couple of seconds, so just hang around.
+       sys->sleep(2000);       
+
+       unsigned int lastBWcheck=0;
+       unsigned int bytesIn=0,bytesOut=0;
+
+       unsigned int lastBroadcastConnect = 0;
+       unsigned int lastRootBroadcast = 0;
+
+       unsigned int lastForceIPCheck = 0;
+
+       while(thread->active)
+       {
+               stats.update();
+
+
+
+               unsigned int ctime = sys->getTime();
+
+
+               if (!servMgr->forceIP.isEmpty())
+               {
+                       if ((ctime-lastForceIPCheck) > 60)
+                       {
+                               if (servMgr->checkForceIP())
+                               {
+                                       GnuID noID;
+                                       noID.clear();
+                                       chanMgr->broadcastTrackerUpdate(noID,true);
+                               }
+                               lastForceIPCheck = ctime;
+                       }
+               }
+
+
+               if (chanMgr->isBroadcasting())
+               {
+                       if ((ctime-lastBroadcastConnect) > 30)
+                       {
+                               servMgr->connectBroadcaster();
+                               lastBroadcastConnect = ctime;
+                       }
+               }
+
+               if (servMgr->isRoot)
+               {
+                       if ((servMgr->lastIncoming) && ((ctime-servMgr->lastIncoming) > 60*60))
+                       {
+                               peercastInst->saveSettings();
+                               sys->exit();
+                       }
+
+                       if ((ctime-lastRootBroadcast) > chanMgr->hostUpdateInterval)
+                       {
+                               servMgr->broadcastRootSettings(true);
+                               lastRootBroadcast = ctime;
+                       }
+               }
+
+
+               // clear dead hits
+               chanMgr->clearDeadHits(true);
+
+               if (servMgr->kickPushStartRelays && servMgr->kickPushInterval) //JP-EX
+               {
+                       servMgr->banFirewalledHost();
+               }
+
+               if (servMgr->shutdownTimer)
+               {
+                       if (--servMgr->shutdownTimer <= 0)
+                       {
+                               peercastInst->saveSettings();
+                               sys->exit();
+                       }
+               }
+
+               // shutdown idle channels
+               if (chanMgr->numIdleChannels() > ChanMgr::MAX_IDLE_CHANNELS)
+                       chanMgr->closeOldestIdle();
+
+
+               sys->sleep(500);
+       }
+
+       sys->endThread(thread);
+//     thread->unlock();
+       return 0;
+}
+
+// --------------------------------------------------
+int ServMgr::serverProc(ThreadInfo *thread)
+{
+
+//     thread->lock();
+
+       Servent *serv = servMgr->allocServent();
+       Servent *serv2 = servMgr->allocServent();
+
+       unsigned int lastLookupTime=0;
+
+
+       while (thread->active)
+       {
+
+               if (servMgr->restartServer)
+               {
+                       serv->abort();          // force close
+                       serv2->abort();         // force close
+                       servMgr->quit();
+
+                       servMgr->restartServer = false;
+               }
+
+               if (servMgr->autoServe)
+               {
+                       serv->allow = servMgr->allowServer1;
+                       serv2->allow = servMgr->allowServer2;
+
+
+                       if ((!serv->sock) || (!serv2->sock))
+                       {
+                               LOG_DEBUG("Starting servers");
+//                             servMgr->forceLookup = true;
+
+                               //if (servMgr->serverHost.ip != 0)
+                               {
+
+                                       if (servMgr->forceNormal)
+                                               servMgr->setFirewall(ServMgr::FW_OFF);
+                                       else
+                                               servMgr->setFirewall(ServMgr::FW_UNKNOWN);
+
+                                       Host h = servMgr->serverHost;
+
+                                       if (!serv->sock)
+                                               serv->initServer(h);
+
+                                       h.port++;
+                                       if (!serv2->sock)
+                                               serv2->initServer(h);
+
+
+                               }
+                       }
+               }else{
+                       // stop server
+                       serv->abort();          // force close
+                       serv2->abort();         // force close
+
+                       // cancel incoming connectuions
+                       Servent *s = servMgr->servents;
+                       while (s)
+                       {
+                               if (s->type == Servent::T_INCOMING)
+                                       s->thread.active = false;
+                               s=s->next;
+                       }
+
+                       servMgr->setFirewall(ServMgr::FW_ON);
+               }
+                       
+               sys->sleepIdle();
+
+       }
+
+       sys->endThread(thread);
+//     thread->unlock();
+       return 0;
+}
+
+// -----------------------------------
+void   ServMgr::setMaxRelays(int max)
+{
+       if (max < MIN_RELAYS)
+               max = MIN_RELAYS;
+       maxRelays = max;
+}
+
+// -----------------------------------
+XML::Node *ServMgr::createServentXML()
+{
+
+       return new XML::Node("servent agent=\"%s\" ",PCX_AGENT);
+}
+
+// --------------------------------------------------
+const char *ServHost::getTypeStr(TYPE t)
+{
+       switch(t)
+       {
+               case T_NONE: return "NONE";
+               case T_STREAM: return "STREAM";
+               case T_CHANNEL: return "CHANNEL";
+               case T_SERVENT: return "SERVENT";
+               case T_TRACKER: return "TRACKER";
+       }
+       return "UNKNOWN";
+}
+// --------------------------------------------------
+ServHost::TYPE ServHost::getTypeFromStr(const char *s)
+{
+       if (stricmp(s,"NONE")==0)
+               return T_NONE;
+       else if (stricmp(s,"SERVENT")==0)
+               return T_SERVENT;
+       else if (stricmp(s,"STREAM")==0)
+               return T_STREAM;
+       else if (stricmp(s,"CHANNEL")==0)
+               return T_CHANNEL;
+       else if (stricmp(s,"TRACKER")==0)
+               return T_TRACKER;
+
+       return T_NONE;
+}
+
+
+// --------------------------------------------------
+bool   ServFilter::writeVariable(Stream &out, const String &var)
+{
+       char buf[1024];
+
+       if (var == "network")
+               strcpy(buf,(flags & F_NETWORK)?"1":"0");
+       else if (var == "private")
+               strcpy(buf,(flags & F_PRIVATE)?"1":"0");
+       else if (var == "direct")
+               strcpy(buf,(flags & F_DIRECT)?"1":"0");
+       else if (var == "banned")
+               strcpy(buf,(flags & F_BAN)?"1":"0");
+       else if (var == "ip")
+               host.IPtoStr(buf);
+       else
+               return false;
+
+
+       out.writeString(buf);
+       return true;
+}
+// --------------------------------------------------
+bool   BCID::writeVariable(Stream &out, const String &var)
+{
+       char buf[1024];
+
+       if (var == "id")
+               id.toStr(buf);
+       else if (var == "name")
+               strcpy(buf,name.cstr());
+       else if (var == "email")
+               strcpy(buf,email.cstr());
+       else if (var == "url")
+               strcpy(buf,url.cstr());
+       else if (var == "valid")
+               strcpy(buf,valid?"Yes":"No");
+       else
+               return false;
+
+
+       out.writeString(buf);
+       return true;
+}
+
+
+// --------------------------------------------------
+bool ServMgr::writeVariable(Stream &out, const String &var)
+{
+       char buf[1024];
+       String str;
+
+       if (var == "version")
+#ifdef VERSION_EX
+               strcpy(buf,PCX_VERSTRING_EX);
+#else
+               strcpy(buf,PCX_VERSTRING);
+#endif
+       else if (var == "uptime")
+       {
+               str.setFromStopwatch(getUptime());
+               str.convertTo(String::T_HTML);
+               strcpy(buf,str.cstr());
+       }else if (var == "numRelays")
+               sprintf(buf,"%d",numStreams(Servent::T_RELAY,true));
+       else if (var == "numDirect")
+               sprintf(buf,"%d",numStreams(Servent::T_DIRECT,true));
+       else if (var == "totalConnected")
+               sprintf(buf,"%d",totalConnected());
+       else if (var == "numServHosts")
+               sprintf(buf,"%d",numHosts(ServHost::T_SERVENT));                
+       else if (var == "numServents")
+               sprintf(buf,"%d",numServents());                
+       else if (var == "serverPort")
+               sprintf(buf,"%d",serverHost.port);              
+       else if (var == "serverIP")
+               serverHost.IPtoStr(buf);
+       else if (var == "ypAddress")
+               strcpy(buf,rootHost.cstr());
+       else if (var == "password")
+               strcpy(buf,password);
+       else if (var == "isFirewalled")
+               sprintf(buf,"%d",getFirewall()==FW_ON?1:0);
+       else if (var == "firewallKnown")
+               sprintf(buf,"%d",getFirewall()==FW_UNKNOWN?0:1);
+       else if (var == "rootMsg")
+               strcpy(buf,rootMsg);
+       else if (var == "isRoot")
+               sprintf(buf,"%d",isRoot?1:0);
+       else if (var == "isPrivate")
+               sprintf(buf,"%d",(PCP_BROADCAST_FLAGS&1)?1:0);
+       else if (var == "forceYP")
+               sprintf(buf,"%d",PCP_FORCE_YP?1:0);
+       else if (var == "refreshHTML")
+               sprintf(buf,"%d",refreshHTML?refreshHTML:0x0fffffff);
+       else if (var == "maxRelays")
+               sprintf(buf,"%d",maxRelays);
+       else if (var == "maxDirect")
+               sprintf(buf,"%d",maxDirect);
+       else if (var == "maxBitrateOut")
+               sprintf(buf,"%d",maxBitrateOut);
+       else if (var == "maxControlsIn")
+               sprintf(buf,"%d",maxControl);
+       else if (var == "numFilters")
+               sprintf(buf,"%d",numFilters+1);
+       else if (var == "maxPGNUIn")
+               sprintf(buf,"%d",maxGnuIncoming);
+       else if (var == "minPGNUIn")
+               sprintf(buf,"%d",minGnuIncoming);
+       else if (var == "numActive1")
+               sprintf(buf,"%d",numActiveOnPort(serverHost.port));
+       else if (var == "numActive2")
+               sprintf(buf,"%d",numActiveOnPort(serverHost.port+1));
+       else if (var == "numPGNU")
+               sprintf(buf,"%d",numConnected(Servent::T_PGNU));
+       else if (var == "numCIN")
+               sprintf(buf,"%d",numConnected(Servent::T_CIN));
+       else if (var == "numCOUT")
+               sprintf(buf,"%d",numConnected(Servent::T_COUT));
+       else if (var == "numIncoming")
+               sprintf(buf,"%d",numActive(Servent::T_INCOMING));
+       else if (var == "numValidBCID")
+       {
+               int cnt = 0;
+               BCID *bcid = validBCID;
+               while (bcid)
+               {
+                       cnt++;
+                       bcid=bcid->next;
+               }
+               sprintf(buf,"%d",cnt);
+       }
+
+       else if (var == "disabled")
+               sprintf(buf,"%d",isDisabled);
+
+       // JP-EX
+       else if (var.startsWith("autoRelayKeep")) {
+               if (var == "autoRelayKeep.0")
+                       strcpy(buf, (autoRelayKeep == 0) ? "1":"0");
+               else if (var == "autoRelayKeep.1")
+                       strcpy(buf, (autoRelayKeep == 1) ? "1":"0");
+               else if (var == "autoRelayKeep.2")
+                       strcpy(buf, (autoRelayKeep == 2) ? "1":"0");
+       } else if (var == "autoMaxRelaySetting")
+               sprintf(buf,"%d",autoMaxRelaySetting);
+       else if (var == "autoBumpSkipCount")
+               sprintf(buf,"%d",autoBumpSkipCount);
+       else if (var == "kickPushStartRelays")
+               sprintf(buf,"%d",kickPushStartRelays);
+       else if (var == "kickPushInterval")
+               sprintf(buf,"%d",kickPushInterval);
+       else if (var == "allowConnectPCST")
+               strcpy(buf, (allowConnectPCST == 1) ? "1":"0");
+       else if (var == "enableGetName")
+               strcpy(buf, (enableGetName == 1)? "1":"0");
+
+       // VP-EX
+       else if (var == "ypAddress2")
+               strcpy(buf,rootHost2.cstr());
+       else if (var.startsWith("autoPort0Kick")) {
+               if (var == "autoPort0Kick.0")
+                       strcpy(buf, (autoPort0Kick == 0) ? "1":"0");
+               else if (var == "autoPort0Kick.1")
+                       strcpy(buf, (autoPort0Kick == 1) ? "1":"0");
+       }
+       else if (var.startsWith("allowOnlyVP")) {
+               if (var == "allowOnlyVP.0")
+                       strcpy(buf, (allowOnlyVP == 0) ? "1":"0");
+               else if (var == "allowOnlyVP.1")
+                       strcpy(buf, (allowOnlyVP == 1) ? "1":"0");
+       }
+       else if (var == "kickKeepTime")
+               sprintf(buf, "%d",kickKeepTime);
+
+       else if (var == "serverPort1")
+               sprintf(buf,"%d",serverHost.port);
+       else if (var == "serverLocalIP")
+       {
+               Host lh(ClientSocket::getIP(NULL),0);
+               char ipStr[64];
+               lh.IPtoStr(ipStr);
+               strcpy(buf,ipStr);
+       }else if (var == "upgradeURL")
+               strcpy(buf,servMgr->downloadURL);
+       else if (var == "serverPort2")
+               sprintf(buf,"%d",serverHost.port+1);
+       else if (var.startsWith("allow."))
+       {
+               if (var == "allow.HTML1")
+                       strcpy(buf,(allowServer1&Servent::ALLOW_HTML)?"1":"0");
+               else if (var == "allow.HTML2")
+                       strcpy(buf,(allowServer2&Servent::ALLOW_HTML)?"1":"0");
+               else if (var == "allow.broadcasting1")
+                       strcpy(buf,(allowServer1&Servent::ALLOW_BROADCAST)?"1":"0");
+               else if (var == "allow.broadcasting2")
+                       strcpy(buf,(allowServer2&Servent::ALLOW_BROADCAST)?"1":"0");
+               else if (var == "allow.network1")
+                       strcpy(buf,(allowServer1&Servent::ALLOW_NETWORK)?"1":"0");
+               else if (var == "allow.direct1")
+                       strcpy(buf,(allowServer1&Servent::ALLOW_DIRECT)?"1":"0");
+       }else if (var.startsWith("auth."))
+       {
+               if (var == "auth.useCookies")
+                       strcpy(buf,(authType==AUTH_COOKIE)?"1":"0");
+               else if (var == "auth.useHTTP")
+                       strcpy(buf,(authType==AUTH_HTTPBASIC)?"1":"0");
+               else if (var == "auth.useSessionCookies")
+                       strcpy(buf,(cookieList.neverExpire==false)?"1":"0");
+
+       }else if (var.startsWith("log."))
+       {
+               if (var == "log.debug")
+                       strcpy(buf,(showLog&(1<<LogBuffer::T_DEBUG))?"1":"0");
+               else if (var == "log.errors")
+                       strcpy(buf,(showLog&(1<<LogBuffer::T_ERROR))?"1":"0");
+               else if (var == "log.gnet")
+                       strcpy(buf,(showLog&(1<<LogBuffer::T_NETWORK))?"1":"0");
+               else if (var == "log.channel")
+                       strcpy(buf,(showLog&(1<<LogBuffer::T_CHANNEL))?"1":"0");
+               else
+                       return false;
+       }else if (var == "test")
+       {
+               out.writeUTF8(0x304b);          
+               out.writeUTF8(0x304d);          
+               out.writeUTF8(0x304f);          
+               out.writeUTF8(0x3051);          
+               out.writeUTF8(0x3053);  
+
+               out.writeUTF8(0x0041);  
+               out.writeUTF8(0x0042);  
+               out.writeUTF8(0x0043);  
+               out.writeUTF8(0x0044);  
+
+               out.writeChar('a');
+               out.writeChar('b');
+               out.writeChar('c');
+               out.writeChar('d');
+               return true;
+
+       }else if (var == "maxRelaysIndexTxt")           // for PCRaw (relay)
+               sprintf(buf, "%d", maxRelaysIndexTxt);
+       else
+               return false;
+
+       out.writeString(buf);
+       return true;
+}
+// --------------------------------------------------
+//JP-EX
+bool ServMgr::isCheckPushStream()
+{
+       if (servMgr->kickPushStartRelays)
+               if (servMgr->numStreams(Servent::T_RELAY,false)>=(servMgr->kickPushStartRelays-1))
+                               return true;
+
+       return false;
+}
+// --------------------------------------------------
+//JP-EX
+void ServMgr::banFirewalledHost()
+{
+       unsigned int kickpushtime = sys->getTime();
+       if ((kickpushtime-servMgr->kickPushTime) > servMgr->kickPushInterval)
+       {
+               servMgr->kickPushTime = kickpushtime;
+               Servent *s = servMgr->servents;
+               LOG_DEBUG("Servent scan start.");
+               while (s)
+               {
+                       if (s->type != Servent::T_NONE)
+                       {
+                               Host h = s->getHost();
+                               int ip = h.ip;
+                               int port = h.port;
+                               Host h2(ip,port);
+                               unsigned int tnum = 0;
+
+                               if (s->lastConnect)
+                                       tnum = sys->getTime() - s->lastConnect;
+                               if ((s->type==Servent::T_RELAY) && (s->status==Servent::S_CONNECTED) && (tnum>servMgr->kickPushInterval))
+                               {                                               
+/*                                     ChanHitList *hits[ChanMgr::MAX_HITLISTS];
+                                       int numHits=0;
+                                       for(int i=0; i<ChanMgr::MAX_HITLISTS; i++)
+                                       {
+                                               ChanHitList *chl = &chanMgr->hitlists[i];
+                                               if (chl->isUsed())
+                                                       hits[numHits++] = chl;
+                                       }
+
+                                       bool isfw = false;
+                                       int numRelay = 0;
+                                       if (numHits) 
+                                       {
+                                               for(int k=0; k<numHits; k++)
+                                               {
+                                                       ChanHitList *chl = hits[k];
+                                                       if (chl->isUsed())
+                                                       {
+                                                               for (int j=0; j<ChanHitList::MAX_HITS; j++ )
+                                                               {
+                                                                       ChanHit *hit = &chl->hits[j];
+                                                                       if (hit->host.isValid() && (h2.ip == hit->host.ip))
+                                                                       {
+                                                                               if (hit->firewalled)
+                                                                                       isfw = true;
+                                                                               numRelay = hit->numRelays;
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       if ((isfw==true) && (numRelay==0))
+                                       {
+                                               char hostName[256];
+                                               h2.toStr(hostName);
+                                               if (servMgr->isCheckPushStream())
+                                               {
+                                                       s->thread.active = false;
+                                                       LOG_ERROR("Stop firewalled Servent : %s",hostName);
+                                               }
+                                       }*/
+
+                                       chanMgr->hitlistlock.on();
+                                       ChanHitList *chl = chanMgr->findHitListByID(s->chanID);
+                                       if (chl){
+                                               ChanHit *hit = chl->hit;
+                                               while(hit){
+                                                       if ((hit->numHops == 1) && hit->host.isValid() && (h2.ip == hit->host.ip) && hit->firewalled /*&& !hit->numRelays*/)
+                                                       {
+                                                               char hostName[256];
+                                                               h2.toStr(hostName);
+                                                               if (servMgr->isCheckPushStream())
+                                                               {
+                                                                       s->thread.active = false;
+                                                                       LOG_ERROR("Stop firewalled Servent : %s",hostName);
+                                                               }
+                                                       }
+                                                       hit = hit->next;
+                                               }
+
+                                       }
+                                       chanMgr->hitlistlock.off();
+
+
+                               }
+                       }
+                       s=s->next;
+               }
+               LOG_DEBUG("Servent scan finished.");
+       }
+}
+
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/servmgr.h b/c:/Git/PeerCast.root/PeerCast/core/common/servmgr.h
new file mode 100644 (file)
index 0000000..492520e
--- /dev/null
@@ -0,0 +1,428 @@
+// ------------------------------------------------
+// File : servmgr.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _SERVMGR_H
+#define _SERVMGR_H
+
+#include "servent.h"
+
+// ----------------------------------
+
+const int MIN_YP_RETRY = 20;
+const int MIN_TRACKER_RETRY = 10;
+const int MIN_RELAY_RETRY = 5;
+
+// ----------------------------------
+class BCID
+{
+public:
+       BCID()
+       :next(0),valid(true)
+       {}
+
+       bool    writeVariable(Stream &, const String &);
+
+       GnuID   id;
+       String  name,email,url;
+       bool    valid;
+       BCID    *next;
+};
+
+
+// ----------------------------------
+class ServHost
+{
+public:
+       enum TYPE
+       {
+               T_NONE,
+               T_STREAM,
+               T_CHANNEL,
+               T_SERVENT,
+               T_TRACKER
+       };
+
+       ServHost() {init();}
+       void init()
+       {
+               host.init();
+               time = 0;
+               type = T_NONE;
+       }
+       void init(Host &h, TYPE tp, unsigned int tim)
+       {
+               init();
+               host = h;
+               type = tp;
+               if (tim)
+                       time = tim;
+               else
+                       time = sys->getTime();
+       }
+
+       static const char *getTypeStr(TYPE);
+       static TYPE getTypeFromStr(const char *);
+
+       TYPE type;
+       Host host;
+       unsigned int time;
+};
+// ----------------------------------
+class ServFilter 
+{
+public:
+       enum 
+       {
+               F_PRIVATE  = 0x01,
+               F_BAN      = 0x02,
+               F_NETWORK  = 0x04,
+               F_DIRECT   = 0x08
+       };
+
+       ServFilter() {init();}
+       void    init()
+       {
+               flags = 0;
+               host.init();
+       }
+
+       bool    writeVariable(Stream &, const String &);
+
+       Host host;
+       unsigned int flags;
+};
+
+// ----------------------------------
+// ServMgr keeps track of Servents
+class ServMgr
+{
+
+
+
+public:
+
+       enum NOTIFY_TYPE
+       {
+               NT_UPGRADE                      = 0x0001,
+               NT_PEERCAST                     = 0x0002,
+               NT_BROADCASTERS         = 0x0004,
+               NT_TRACKINFO            = 0x0008
+       };
+
+       enum FW_STATE
+       {
+               FW_OFF,
+               FW_ON,
+               FW_UNKNOWN
+       };
+       enum {
+
+               MAX_HOSTCACHE = 100,            // max. amount of hosts in cache
+               MIN_HOSTS       = 3,                    // min. amount of hosts that should be kept in cache
+
+               MAX_OUTGOING = 3,                       // max. number of outgoing servents to use
+               MAX_INCOMING = 6,                   // max. number of public incoming servents to use
+               MAX_TRYOUT   = 10,                      // max. number of outgoing servents to try connect
+               MIN_CONNECTED = 3,                      // min. amount of connected hosts that should be kept
+
+               MIN_RELAYS = 1,
+
+               MAX_FILTERS = 50,
+
+               MAX_VERSIONS = 16,
+
+               MAX_PREVIEWTIME = 300,          // max. seconds preview per channel available (direct connections)
+               MAX_PREVIEWWAIT = 300,          // max. seconds wait between previews 
+
+       };
+
+       enum AUTH_TYPE
+       {
+               AUTH_COOKIE,
+               AUTH_HTTPBASIC
+       };
+
+       
+
+       ServMgr();
+
+       bool    start();
+
+       Servent *findServent(unsigned int,unsigned short,GnuID &);
+       Servent *findServent(Servent::TYPE);
+       Servent *findServent(Servent::TYPE,Host &,GnuID &);
+       Servent *findOldestServent(Servent::TYPE,bool);
+       Servent *findServentByIndex(int);
+       Servent *findServentByServentID(int);
+
+       bool    writeVariable(Stream &, const String &);
+       Servent *allocServent();
+       unsigned int            numUsed(int);
+       unsigned int            numStreams(GnuID &, Servent::TYPE,bool);
+       unsigned int            numStreams(Servent::TYPE,bool);
+       unsigned int            numConnected(int,bool,unsigned int);
+       unsigned int            numConnected(int t,int tim = 0)
+       {
+               return numConnected(t,false,tim)+numConnected(t,true,tim);
+       }
+       unsigned int            numConnected();
+       unsigned int            numServents();
+
+       unsigned int            totalConnected()
+       {
+               //return numConnected(Servent::T_OUTGOING) + numConnected(Servent::T_INCOMING);
+               return numConnected();
+       }
+       unsigned int            numOutgoing();
+       bool    isFiltered(int,Host &h);
+       bool    addOutgoing(Host,GnuID &,bool);
+       Servent *findConnection(Servent::TYPE,GnuID &);
+
+
+       static  THREAD_PROC             serverProc(ThreadInfo *);
+       static  THREAD_PROC             clientProc(ThreadInfo *);
+       static  THREAD_PROC             trackerProc(ThreadInfo *);
+       static  THREAD_PROC             idleProc(ThreadInfo *);
+
+       int             broadcast(GnuPacket &,Servent * = NULL);
+       int             route(GnuPacket &, GnuID &, Servent * = NULL);
+
+       XML::Node *createServentXML();
+
+       void            connectBroadcaster();
+       void            procConnectArgs(char *,ChanInfo &);
+
+       void            quit();
+       void            closeConnections(Servent::TYPE);
+
+       void            checkFirewall();
+
+       // host cache
+       void                    addHost(Host &,ServHost::TYPE,unsigned int);
+       int                             getNewestServents(Host *,int, Host &);
+       ServHost                getOutgoingServent(GnuID &);
+       void                    deadHost(Host &,ServHost::TYPE);
+       unsigned int    numHosts(ServHost::TYPE);
+       void                    clearHostCache(ServHost::TYPE);
+       bool                    seenHost(Host &,ServHost::TYPE,unsigned int);
+
+       void    setMaxRelays(int);
+       void    setFirewall(FW_STATE);
+       bool    checkForceIP();
+       FW_STATE        getFirewall() {return firewalled;}
+       void    saveSettings(const char *);
+       void    loadSettings(const char *);
+       void    setPassiveSearch(unsigned int);
+       int             findChannel(ChanInfo &);
+       bool    getChannel(char *,ChanInfo &,bool);
+       void    setFilterDefaults();
+
+       bool    acceptGIV(ClientSocket *);
+       void    addVersion(unsigned int);
+
+       void broadcastRootSettings(bool);
+       int broadcastPushRequest(ChanHit &, Host &, GnuID &, Servent::TYPE);
+       void writeRootAtoms(AtomStream &,bool);
+
+       int     broadcastPacket(ChanPacket &,GnuID &,GnuID &,GnuID &,Servent::TYPE type);
+
+       void    addValidBCID(BCID *);
+       void    removeValidBCID(GnuID &);
+       BCID    *findValidBCID(GnuID &);
+       BCID    *findValidBCID(int);
+
+       unsigned int getUptime()
+       {
+               return sys->getTime()-startTime;
+       }
+
+       bool    seenPacket(GnuPacket &);
+
+
+       bool    needHosts()
+       {
+               return false;
+               //return numHosts(ServHost::T_SERVENT) < maxTryout;
+       }
+
+       unsigned int            numActiveOnPort(int);
+       unsigned int            numActive(Servent::TYPE);
+
+       bool    needConnections() 
+       {
+               return numConnected(Servent::T_PGNU,60) < minGnuIncoming;
+       }
+       bool    tryFull() 
+       {
+               return false;
+               //return maxTryout ? numUsed(Servent::T_OUTGOING) > maxTryout: false;
+       }
+
+       bool    pubInOver() 
+       {
+               return numConnected(Servent::T_PGNU) > maxGnuIncoming;
+//             return maxIncoming ? numConnected(Servent::T_INCOMING,false) > maxIncoming : false;
+       }
+       bool    pubInFull() 
+       {
+               return numConnected(Servent::T_PGNU) >= maxGnuIncoming;
+//             return maxIncoming ? numConnected(Servent::T_INCOMING,false) >= maxIncoming : false;
+       }
+
+       bool    outUsedFull() 
+       {
+               return false;
+//             return maxOutgoing ? numUsed(Servent::T_OUTGOING) >= maxOutgoing: false;
+       }
+       bool    outOver() 
+       {
+               return false;
+//             return maxOutgoing ? numConnected(Servent::T_OUTGOING) > maxOutgoing : false;
+       }
+
+       bool    controlInFull()
+       {
+               return numConnected(Servent::T_CIN)>=maxControl;
+       }
+
+       bool    outFull() 
+       {
+               return false;
+//             return maxOutgoing ? numConnected(Servent::T_OUTGOING) >= maxOutgoing : false;
+       }
+
+       bool    relaysFull() 
+       {
+               return numStreams(Servent::T_RELAY,false) >= maxRelays;
+       }
+       bool    directFull() 
+       {
+               return numStreams(Servent::T_DIRECT,false) >= maxDirect;
+       }
+
+       bool    bitrateFull(unsigned int br) 
+       {
+               return maxBitrateOut ? (BYTES_TO_KBPS(totalOutput(false))+br) > maxBitrateOut  : false;
+       }
+
+       unsigned int            totalOutput(bool);
+       unsigned int            totalInput(bool);
+
+       static ThreadInfo serverThread,idleThread;
+
+
+       Servent *servents;
+       WLock   lock;
+
+       ServHost        hostCache[MAX_HOSTCACHE];
+
+       char    password[64];
+
+       bool    allowGnutella;
+
+       unsigned int            maxBitrateOut,maxControl,maxRelays,maxDirect;
+       unsigned int            minGnuIncoming,maxGnuIncoming;
+       unsigned int            maxServIn;
+
+       bool    isDisabled;
+       bool    isRoot;
+       int             totalStreams;
+
+       Host    serverHost;
+       String  rootHost;
+       String  rootHost2;
+
+       char    downloadURL[128];
+       String  rootMsg;
+       String  forceIP;
+       char    connectHost[128];
+       GnuID   networkID;
+       unsigned int            firewallTimeout;
+       int             showLog;
+       int             shutdownTimer;
+       bool    pauseLog;
+       bool    forceNormal;
+       bool    useFlowControl;
+       unsigned int lastIncoming;
+
+       bool    restartServer;
+       bool    allowDirect;
+       bool    autoConnect,autoServe,forceLookup;
+       int             queryTTL;
+
+       unsigned int            allowServer1,allowServer2;
+       unsigned int            startTime;
+       unsigned int            tryoutDelay;
+       unsigned int            refreshHTML;
+       unsigned int            relayBroadcast;
+
+       unsigned int notifyMask;
+
+       BCID            *validBCID;
+       GnuID           sessionID;
+
+       ServFilter      filters[MAX_FILTERS];
+       int     numFilters;
+
+
+       CookieList      cookieList;
+       AUTH_TYPE       authType;
+
+       char    htmlPath[128];
+       unsigned int    clientVersions[MAX_VERSIONS],clientCounts[MAX_VERSIONS];
+       int     numVersions;
+
+       int serventNum;
+       String chanLog;
+
+       char modulePath[256]; //JP-EX
+       int enableGetName; //JP-EX
+       int allowConnectPCST; //JP-EX
+       int autoRelayKeep; //JP-EX
+       unsigned int autoMaxRelaySetting; //JP-EX
+       unsigned int autoBumpSkipCount;//JP-EX
+       unsigned int kickPushStartRelays; //JP-EX
+       unsigned int kickPushInterval; //JP-EX
+       unsigned int kickPushTime;
+       bool    isCheckPushStream(); //JP-EX
+       void    banFirewalledHost(); //JP-EX
+
+       bool    getModulePath; //JP-EX
+       bool    clearPLS; //JP-EX
+       bool    writeLogFile; //JP-EX
+
+       bool    autoPort0Kick;
+       bool    allowOnlyVP;
+       unsigned int kickKeepTime;
+       bool    vpDebug;
+       bool    saveIniChannel;
+       bool    saveGuiPos;
+       bool    keepDownstreams;
+
+       int maxRelaysIndexTxt;  // for PCRaw (relay)
+
+private:
+       FW_STATE        firewalled;
+};
+
+// ----------------------------------
+extern ServMgr *servMgr;
+
+
+#endif
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/socket.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/socket.cpp
new file mode 100644 (file)
index 0000000..80ac2dd
--- /dev/null
@@ -0,0 +1,32 @@
+// ------------------------------------------------
+// File : socket.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             ClientSocket is a generic socket interface, Non OS/HW dependant.
+//             
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+#include <stdio.h>
+#include <string.h>
+#include "socket.h"
+#include "sys.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/socket.h b/c:/Git/PeerCast.root/PeerCast/core/common/socket.h
new file mode 100644 (file)
index 0000000..0e47e07
--- /dev/null
@@ -0,0 +1,185 @@
+// ------------------------------------------------
+// File : socket.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _SOCKET_H
+#define _SOCKET_H
+
+
+#include "common.h"
+#include "stream.h"
+
+//#define DISABLE_NAGLE 1
+
+class SocketBuffer {
+
+public:
+       SocketBuffer(const void *p, int l){
+               buf = ::new char[l];
+               len = l;
+               pos = 0;
+               next = NULL;
+               ctime = sys->getTime();
+               memcpy((void*)buf, p, l);
+       }
+
+       ~SocketBuffer(){
+               if (buf){
+                       ::delete [] buf;
+               }
+       }
+       char *buf;
+       int len;
+       int pos;
+       unsigned int ctime;
+       SocketBuffer *next;
+};
+
+class SocketBufferList {
+
+public:
+       SocketBufferList(){
+               top = NULL;
+               last = NULL;
+               skipCount = 0;
+               lastSkipTime = 0;
+       }
+
+       bool isNull(){ return (top == NULL); }
+       void add(const void *p, int l){
+               SocketBuffer *tmp = new SocketBuffer(p,l);
+
+               if (!last){
+                       top = tmp;
+                       last = tmp;
+               } else {
+                       last->next = tmp;
+                       last = tmp;
+               }
+
+//             LOG_DEBUG("tmp = %d, top = %d, last = %d", tmp, top, last);
+       }
+
+       SocketBuffer *getTop(){
+               unsigned int ctime = sys->getTime();
+
+               while(top){
+                       if (top && (top->ctime + 10 >= ctime)){
+                               break;
+                       } else {
+//                             LOG_DEBUG("over 10sec(data skip)");
+                               skipCount++;
+                               lastSkipTime = sys->getTime();
+                               deleteTop();
+                       }
+               }
+               return top;
+       }
+
+       void deleteTop(){
+//             LOG_DEBUG("oldtop = %d", top);
+               SocketBuffer *tmp = top;
+               top = tmp->next;
+               delete tmp;
+               if (!top){
+                       last = NULL;
+               }
+
+//             LOG_DEBUG("newtop = %d",top);
+       }
+
+       void clear(){
+               while(top){
+                       SocketBuffer *tmp = top;
+                       top = tmp->next;
+                       delete tmp;
+               }
+               top = NULL;
+               last = NULL;
+       }
+
+       SocketBuffer *top;
+       SocketBuffer *last;
+       unsigned int skipCount;
+       unsigned int lastSkipTime;
+
+};
+
+// --------------------------------------------------
+class ClientSocket : public Stream
+{
+public:
+
+       ClientSocket()
+       {
+               readTimeout = 30000;
+               writeTimeout = 30000;
+#ifdef WIN32
+               skipCount = 0;
+               lastSkipTime = 0;
+#endif
+       }
+
+       ~ClientSocket(){
+#ifdef WIN32
+               bufList.clear();
+#endif
+       }
+
+    // required interface
+       virtual void    open(Host &) = 0;
+       virtual void    bind(Host &) = 0;
+       virtual void    connect() = 0;
+       virtual bool    active() = 0;
+       virtual ClientSocket    *accept() = 0;
+       virtual Host    getLocalHost() = 0;
+
+       virtual void    setReadTimeout(unsigned int t)
+       {
+               readTimeout = t;
+       }
+       virtual void    setWriteTimeout(unsigned int t)
+       {
+               writeTimeout = t;
+       }
+       virtual void    setBlocking(bool) {}
+
+
+    static unsigned int    getIP(char *);
+       static bool                     getHostname(char *,unsigned int);
+
+    virtual bool eof()
+    {
+        return active()==false;
+    }
+
+    Host    host;
+
+#ifdef WIN32
+       SocketBufferList        bufList;
+       virtual void bufferingWrite(const void *, int) = 0;
+       unsigned int skipCount;
+       unsigned int lastSkipTime;
+#endif
+
+       unsigned int readTimeout,writeTimeout;
+
+};
+
+
+#endif
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/stats.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/stats.cpp
new file mode 100644 (file)
index 0000000..46e0a44
--- /dev/null
@@ -0,0 +1,102 @@
+// ------------------------------------------------
+// File : stats.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             Statistic logging
+//             
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+#include "stats.h"
+#include "common.h"
+#include "sys.h"
+#include "stream.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+Stats stats;
+// ------------------------------------
+void Stats::clear()
+{
+       for(int i=0; i<Stats::MAX; i++)
+       {
+               current[i] = 0;
+               last[i] = 0;
+               perSec[i] = 0;
+       }
+       lastUpdate = 0;
+}
+// ------------------------------------
+void   Stats::update()
+{
+       unsigned int ctime = sys->getTime();
+
+       unsigned int diff = ctime - lastUpdate;
+       if (diff >= /* 5 */ 1)
+       {
+               
+               for(int i=0; i<Stats::MAX; i++)
+               {
+                       perSec[i] = (current[i]-last[i])/diff;
+                       last[i] = current[i];
+               }
+
+               lastUpdate = ctime;
+       }
+       
+}
+// ------------------------------------
+bool Stats::writeVariable(Stream &out,const String &var)
+{
+       char buf[1024];
+
+       if (var == "totalInPerSec")             
+               sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::BYTESIN)));
+       else if (var == "totalOutPerSec")               
+               sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::BYTESOUT)));
+       else if (var == "totalPerSec")          
+               sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::BYTESIN)+getPerSecond(Stats::BYTESOUT)));
+       else if (var == "wanInPerSec")          
+               sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::BYTESIN)-getPerSecond(Stats::LOCALBYTESIN)));
+       else if (var == "wanOutPerSec")         
+               sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::BYTESOUT)-getPerSecond(Stats::LOCALBYTESOUT)));
+       else if (var == "wanTotalPerSec")               
+               sprintf(buf,"%.1f",BYTES_TO_KBPS((getPerSecond(Stats::BYTESIN)-getPerSecond(Stats::LOCALBYTESIN))+(getPerSecond(Stats::BYTESOUT)-getPerSecond(Stats::LOCALBYTESOUT))));
+       else if (var == "netInPerSec")          
+               sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::PACKETDATAIN)));
+       else if (var == "netOutPerSec")         
+               sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::PACKETDATAOUT)));
+       else if (var == "netTotalPerSec")               
+               sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::PACKETDATAOUT)+getPerSecond(Stats::PACKETDATAIN)));
+       else if (var == "packInPerSec")         
+               sprintf(buf,"%.1f",getPerSecond(Stats::NUMPACKETSIN));
+       else if (var == "packOutPerSec")                
+               sprintf(buf,"%.1f",getPerSecond(Stats::NUMPACKETSOUT));
+       else if (var == "packTotalPerSec")              
+               sprintf(buf,"%.1f",getPerSecond(Stats::NUMPACKETSOUT)+getPerSecond(Stats::NUMPACKETSIN));
+
+       else
+               return false;
+
+       out.writeString(buf);
+
+       return true;
+}
+
+
+
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/stats.h b/c:/Git/PeerCast.root/PeerCast/core/common/stats.h
new file mode 100644 (file)
index 0000000..9c52717
--- /dev/null
@@ -0,0 +1,87 @@
+// ------------------------------------------------
+// File : stats.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _STATS_H
+#define _STATS_H
+
+// ------------------------------------------------------
+class Stats
+{
+public:
+
+       void    clear();
+       void    update();
+
+       enum STAT
+       {
+               NONE,
+
+               PACKETSSTART,
+               NUMQUERYIN,NUMQUERYOUT,
+               NUMPINGIN,NUMPINGOUT,
+               NUMPONGIN,NUMPONGOUT,
+               NUMPUSHIN,NUMPUSHOUT,
+               NUMHITIN,NUMHITOUT,
+               NUMOTHERIN,NUMOTHEROUT,
+               NUMDROPPED,
+               NUMDUP,
+               NUMACCEPTED,
+               NUMOLD,
+               NUMBAD,
+               NUMHOPS1,NUMHOPS2,NUMHOPS3,NUMHOPS4,NUMHOPS5,NUMHOPS6,NUMHOPS7,NUMHOPS8,NUMHOPS9,NUMHOPS10,
+               NUMPACKETSIN,
+               NUMPACKETSOUT,
+               NUMROUTED,
+               NUMBROADCASTED,
+               NUMDISCARDED,
+               NUMDEAD,
+               PACKETDATAIN,
+               PACKETDATAOUT,
+               PACKETSEND,             
+               
+
+               BYTESIN,
+               BYTESOUT,
+               LOCALBYTESIN,
+               LOCALBYTESOUT,
+
+               MAX
+       };
+
+       bool    writeVariable(class Stream &,const class String &);
+
+       void    clearRange(STAT s, STAT e)
+       {
+               for(int i=s; i<=e; i++)
+                       current[i] = 0;
+       }
+       void    clear(STAT s) {current[s]=0;}
+       void    add(STAT s,int n=1) {current[s]+=n;}
+       unsigned int getPerSecond(STAT s) {return perSec[s];}
+       unsigned int getCurrent(STAT s) {return current[s];}
+
+       unsigned int    current[Stats::MAX],last[Stats::MAX],perSec[Stats::MAX];
+       unsigned int    lastUpdate;
+};
+
+extern Stats stats;
+
+
+#endif
+
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/stream.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/stream.cpp
new file mode 100644 (file)
index 0000000..b1f64b5
--- /dev/null
@@ -0,0 +1,367 @@
+// ------------------------------------------------
+// File : stream.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+//             Basic stream handling functions. 
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+#include "stream.h"
+#include "common.h"
+#include "sys.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+// --------------------------------------------------
+void MemoryStream::convertFromBase64()
+{       
+       char *out = buf;
+       char *in = buf;
+       
+       int rl=len;
+    while(rl >= 4) 
+       {
+               out += String::base64WordToChars(out,in);
+               in += 4;
+        rl -= 4;
+    }
+    *out = 0;
+       len = out-buf;
+}
+// -------------------------------------
+void FileStream::openReadOnly(const char *fn)
+{
+       file = fopen(fn,"rb");
+
+    if (!file)
+       throw StreamException("Unable to open file");
+}
+// -------------------------------------
+void FileStream::openWriteReplace(const char *fn)
+{
+       file = fopen(fn,"wb");
+
+       if (!file)
+       throw StreamException("Unable to open file");
+}
+// -------------------------------------
+void FileStream::openWriteAppend(const char *fn)
+{
+        file = fopen(fn,"ab");
+
+        if (!file)
+               throw StreamException("Unable to open file");
+}
+
+// -------------------------------------
+void FileStream::close()
+{
+       if (file)
+       {
+               fclose(file);
+               file = NULL;
+       }
+}
+// -------------------------------------
+void FileStream::rewind()
+{
+       if (file)
+               fseek(file,0,SEEK_SET);
+}
+// -------------------------------------
+int FileStream::length()
+{
+       int len = 0;
+       if (file)
+       {
+               int old = ftell(file);
+               fseek(file,0,SEEK_END);
+               len = ftell(file);
+               fseek(file,old,SEEK_SET);
+
+       }
+       return len;
+}
+
+// -------------------------------------
+bool FileStream::eof()
+{
+       if (file)
+               return (feof(file)!=0);
+       else
+               return true;
+}
+// -------------------------------------
+int FileStream::read(void *ptr, int len)
+{
+       if (!file)
+               return 0;
+       if (feof(file))
+       throw StreamException("End of file");
+
+       int r = (int)fread(ptr,1,len,file);
+
+       updateTotals(r, 0);
+    return r;
+}
+
+// -------------------------------------
+void FileStream::write(const void *ptr, int len)
+{
+       if (!file)
+               return;
+    fwrite(ptr,1,len,file);
+       updateTotals(0, len);
+
+}
+// -------------------------------------
+void FileStream::flush()
+{
+       if (!file)
+               return;
+    fflush(file);
+}
+// -------------------------------------
+int FileStream::pos()
+{
+       if (!file)
+               return 0;
+    return ftell(file);
+}
+
+// -------------------------------------
+void FileStream::seekTo(int pos)
+{
+       if (!file)
+               return;
+       fseek(file,pos,SEEK_SET);
+}
+
+// -------------------------------------
+void Stream::writeTo(Stream &out, int len)
+{
+       char tmp[4096];
+       while (len)
+       {
+               int rlen = sizeof(tmp);
+               if (rlen > len)
+                       rlen = len;
+
+               read(tmp,rlen);
+               out.write(tmp,rlen);
+
+               len-=rlen;
+       }
+}
+// -------------------------------------
+int    Stream::writeUTF8(unsigned int code)
+{
+       if (code < 0x80)
+       {
+               writeChar(code);
+               return 1;
+       }else 
+       if (code < 0x0800)
+       {
+               writeChar(code>>6 | 0xC0);
+               writeChar(code & 0x3F | 0x80);
+               return 2;
+       }else if (code < 0x10000)
+       {
+               writeChar(code>>12 | 0xE0);
+               writeChar(code>>6 & 0x3F | 0x80);
+               writeChar(code & 0x3F | 0x80);
+               return 3;
+       }else 
+       {
+               writeChar(code>>18 | 0xF0);
+               writeChar(code>>12 & 0x3F | 0x80);
+               writeChar(code>>6 & 0x3F | 0x80);
+               writeChar(code & 0x3F | 0x80);
+               return 4;
+       }
+               
+}
+
+// -------------------------------------
+void Stream::skip(int len)
+{
+       char tmp[4096];
+       while (len)
+       {
+               int rlen = sizeof(tmp);
+               if (rlen > len)
+                       rlen = len;
+               read(tmp,rlen);
+               len-=rlen;
+       }
+
+}
+
+
+// -------------------------------------
+void Stream::updateTotals(unsigned int in, unsigned int out)
+{
+       totalBytesIn += in;
+       totalBytesOut += out;
+
+       unsigned int tdiff = sys->getTime()-lastUpdate;
+       if (tdiff >= 5)
+       {
+               bytesInPerSec = (totalBytesIn-lastBytesIn)/tdiff;
+               bytesOutPerSec = (totalBytesOut-lastBytesOut)/tdiff;
+               lastBytesIn = totalBytesIn;
+               lastBytesOut = totalBytesOut;
+               lastUpdate = sys->getTime();
+       }
+}
+// -------------------------------------
+int    Stream::readLine(char *in, int max)
+{
+    int i=0;
+       max -= 2;
+
+       while(max--)
+    {                
+       char c;         
+       read(&c,1);
+               if (c == '\n')
+                       break;
+               if (c == '\r')
+                       continue;
+        in[i++] = c;
+    }
+    in[i] = 0;
+       return i;
+}
+// -------------------------------------
+void Stream::write(const char *fmt,va_list ap)
+{
+       char tmp[4096];
+       vsprintf(tmp,fmt,ap);
+    write(tmp,strlen(tmp));
+}
+// -------------------------------------
+void Stream::writeStringF(const char *fmt,...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       write(fmt,ap);
+       va_end(ap);     
+}
+// -------------------------------------
+void Stream::writeString(const char *str)
+{
+       write(str,strlen(str));
+}
+// -------------------------------------
+void Stream::writeLineF(const char *fmt,...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+
+       write(fmt,ap);
+
+       if (writeCRLF)
+           write("\r\n",2);
+       else
+               write("\n",1);
+
+       va_end(ap);     
+}
+
+// -------------------------------------
+void Stream::writeLine(const char *str)
+{
+       writeString(str);
+
+       if (writeCRLF)
+           write("\r\n",2);
+       else
+               write("\n",1);
+}
+
+// -------------------------------------
+int    Stream::readWord(char *in, int max)
+{
+       int i=0;
+    while (!eof())
+    {
+        char c = readChar();
+
+        if ((c == ' ') || (c == '\t') || (c == '\r') || (c == '\n'))
+        {
+               if (i)
+               break;          // stop reading
+            else
+                       continue;       // skip whitespace
+        }
+
+       if (i >= (max-1))
+               break;
+
+        in[i++] = c;
+    }
+
+       in[i]=0;
+    return i;
+}
+
+
+// --------------------------------------------------
+int Stream::readBase64(char *p, int max)
+{       
+       char vals[4];
+
+       int cnt=0;
+       while (cnt < (max-4))
+       {
+               read(vals,4);
+               int rl = String::base64WordToChars(p,vals);
+               if (!rl)
+                       break;
+
+               p+=rl;
+               cnt+=rl;
+       }
+       *p = 0;
+       return cnt;
+}
+
+
+// -------------------------------------
+int Stream::readBits(int cnt)
+{
+       int v = 0;
+
+       while (cnt)
+       {
+               if (!bitsPos)
+                       bitsBuffer = readChar();
+
+               cnt--;
+
+               v |= (bitsBuffer&(1<<(7-bitsPos)))?(1<<cnt):0;
+
+               bitsPos = (bitsPos+1)&7;
+       }
+
+       return v;
+}
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/stream.h b/c:/Git/PeerCast.root/PeerCast/core/common/stream.h
new file mode 100644 (file)
index 0000000..4561861
--- /dev/null
@@ -0,0 +1,541 @@
+// ------------------------------------------------
+// File : stream.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _STREAM_H
+#define _STREAM_H
+
+// -------------------------------------
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include "common.h"
+#include "sys.h"
+#include "id.h"
+
+// -------------------------------------
+class Stream
+{
+public:
+       Stream()
+       :writeCRLF(true)
+       ,totalBytesIn(0)
+       ,totalBytesOut(0)
+       ,lastBytesIn(0)
+       ,lastBytesOut(0)
+       ,bytesInPerSec(0)
+       ,bytesOutPerSec(0)
+       ,lastUpdate(0)
+       ,bitsBuffer(0)
+       ,bitsPos(0)
+       {
+       }
+       virtual ~Stream() {}
+
+       virtual int readUpto(void *,int) {return 0;}
+       virtual int read(void *,int)=0;
+       virtual void write(const void *,int) = 0;
+    virtual bool eof()
+    {
+       throw StreamException("Stream can`t eof");
+               return false;
+    }
+
+       virtual void rewind()
+       {
+       throw StreamException("Stream can`t rewind");
+       }
+
+       virtual void seekTo(int)
+       {
+       throw StreamException("Stream can`t seek");
+       }
+
+       void writeTo(Stream &out, int len);
+       virtual void skip(int i);
+
+       virtual void close()
+       {
+       }
+
+       virtual void    setReadTimeout(unsigned int ) 
+       {
+       }
+       virtual void    setWriteTimeout(unsigned int )
+       {
+       }
+       virtual void    setPollRead(bool)
+       {
+       }
+
+       virtual int             getPosition() {return 0;}
+
+
+       // binary
+    char       readChar()
+    {
+       char v;
+        read(&v,1);
+        return v;
+    }
+    short      readShort()
+    {
+       short v;
+        read(&v,2);
+               CHECK_ENDIAN2(v);
+        return v;
+    }
+    long       readLong()
+    {
+       long v;
+        read(&v,4);
+               CHECK_ENDIAN4(v);
+        return v;
+    }
+       int readInt()
+       {
+               return readLong();
+       }
+       ID4 readID4()
+       {
+               ID4 id;
+               read(id.getData(),4);
+               return id;
+       }
+       int     readInt24()
+       {
+               int v=0;
+        read(&v,3);
+               CHECK_ENDIAN3(v);
+       }
+
+
+
+       long readTag()
+       {
+               long v = readLong();
+               return SWAP4(v);
+       }
+
+       int     readString(char *s, int max)
+       {
+               int cnt=0;
+               while (max)
+               {
+                       char c = readChar();
+                       *s++ = c;
+                       cnt++;
+                       max--;
+                       if (!c)
+                               break;
+               }
+               return cnt;
+       }
+
+       virtual bool    readReady() {return true;}
+       virtual int numPending() {return 0;}
+
+
+       void writeID4(ID4 id)
+       {
+               write(id.getData(),4);
+       }
+
+       void    writeChar(char v)
+       {
+               write(&v,1);
+       }
+       void    writeShort(short v)
+       {
+               CHECK_ENDIAN2(v);
+               write(&v,2);
+       }
+       void    writeLong(long v)
+       {
+               CHECK_ENDIAN4(v);
+               write(&v,4);
+       }
+       void writeInt(int v) {writeLong(v);}
+
+       void    writeTag(long v)
+       {
+               //CHECK_ENDIAN4(v);
+               writeLong(SWAP4(v));
+       }
+
+       void    writeTag(char id[4])
+       {
+               write(id,4);
+       }
+
+       int     writeUTF8(unsigned int);
+
+       // text
+    int        readLine(char *in, int max);
+
+    int                readWord(char *, int);
+       int             readBase64(char *, int);
+
+       void    write(const char *,va_list);
+       void    writeLine(const char *);
+       void    writeLineF(const char *,...);
+       void    writeString(const char *);
+       void    writeStringF(const char *,...);
+
+       bool    writeCRLF;
+
+       int             readBits(int);
+
+       void    updateTotals(unsigned int,unsigned int);
+
+
+       unsigned char bitsBuffer;
+       unsigned int bitsPos;
+
+       unsigned int totalBytesIn,totalBytesOut;
+       unsigned int lastBytesIn,lastBytesOut;
+       unsigned int bytesInPerSec,bytesOutPerSec;
+       unsigned int lastUpdate;
+
+};
+
+
+// -------------------------------------
+class FileStream : public Stream
+{
+public:
+       FileStream() {file=NULL;}
+
+    void       openReadOnly(const char *);
+    void       openWriteReplace(const char *);
+    void       openWriteAppend(const char *);
+       bool    isOpen(){return file!=NULL;}
+       int             length();
+       int             pos();
+
+       virtual void    seekTo(int);
+       virtual int             getPosition() {return pos();}
+       virtual void    flush();
+    virtual int                read(void *,int);
+    virtual void       write(const void *,int);
+    virtual bool       eof();
+    virtual void       rewind();
+    virtual void       close();
+
+       FILE *file;
+};
+// -------------------------------------
+class MemoryStream : public Stream
+{
+public:
+       MemoryStream()
+       :buf(NULL)
+       ,len(0)
+       ,pos(0)
+       ,own(false)
+       {
+       }
+
+       MemoryStream(void *p, int l)
+       :buf((char *)p)
+       ,len(l)
+       ,pos(0)
+       ,own(false)
+       {
+       }
+
+       MemoryStream(int l)
+       :buf(new char[l])
+       ,len(l)
+       ,pos(0)
+       ,own(true)
+       {
+       }
+
+       ~MemoryStream() {free2();}
+
+       void readFromFile(FileStream &file)
+       {
+               len = file.length();
+               buf = new char[len];
+               own = true;
+               pos = 0;
+               file.read(buf,len);
+       }
+
+       void free2()
+       {
+               if (own && buf)
+               {
+                       delete buf;
+                       buf = NULL;
+                       own = false;
+               }
+
+       }
+
+       virtual int read(void *p,int l)
+    {
+               if (pos+l <= len)
+               {
+                       memcpy(p,&buf[pos],l);
+                       pos += l;
+                       return l;
+               }else
+               {
+                       memset(p,0,l);
+                       return 0;
+               }
+    }
+
+       virtual void write(const void *p,int l)
+    {
+               if ((pos+l) > len)
+                       throw StreamException("Stream - premature end of write()");
+               memcpy(&buf[pos],p,l);
+               pos += l;
+    }
+
+    virtual bool eof()
+    {
+        return pos >= len;
+    }
+
+       virtual void rewind()
+       {
+               pos = 0;
+       }
+
+       virtual void seekTo(int p)
+       {
+               pos = p;
+       }
+
+       virtual int getPosition()
+       {
+               return pos;
+       }
+
+       void    convertFromBase64();
+
+
+       char *buf;
+       bool own;
+       int len,pos;
+};
+// --------------------------------------------------
+class IndirectStream : public Stream
+{
+public:
+
+       void init(Stream *s)
+       {
+               stream = s;
+       }
+
+       virtual int read(void *p,int l)
+    {
+               return stream->read(p,l);
+    }
+
+       virtual void write(const void *p,int l)
+    {
+               stream->write(p,l);
+    }
+
+    virtual bool eof()
+    {
+        return stream->eof();
+    }
+
+    virtual void close()
+    {
+        stream->close();
+    }
+
+       Stream *stream;
+};
+
+// -------------------------------------
+
+class SockBufStream : public Stream
+{
+public:
+       SockBufStream(Stream &sockStream, int bufsize=128*1024)
+               : sock(sockStream), mem(bufsize)
+               {
+               }
+
+       ~SockBufStream()
+               {
+                       flush();
+                       mem.free2();
+               }
+
+       virtual int read(void *p,int l)
+               {
+                       return sock.read(p, l);
+               }
+
+       virtual void write(const void *p, int len)
+               {
+                       if ( mem.pos+len > mem.len )
+                               flush();
+
+                       mem.write(p, len);
+               }
+
+       void flush()
+               {
+                       if ( mem.pos > 0 ) {
+                               sock.write(mem.buf, mem.pos);
+                               clearWriteBuffer();
+                       }
+               }
+
+       void clearWriteBuffer()
+               {
+                       mem.rewind();
+               }
+
+private:
+       Stream &sock;
+       MemoryStream mem;
+};
+
+// -------------------------------------
+class WriteBufferStream : public Stream
+{
+public:
+       WriteBufferStream(Stream *out_)
+       :buf(NULL)
+       ,own(false)
+       ,len(0)
+       ,pos(0)
+       ,out(out_)
+       {
+       }
+
+       WriteBufferStream(void *p, int l, Stream *out_)
+       :buf((char *)p)
+       ,own(false)
+       ,len(l)
+       ,pos(0)
+       ,out(out_)
+       {
+       }
+
+       WriteBufferStream(int l, Stream *out_)
+       :buf(new char[l])
+       ,own(true)
+       ,len(l)
+       ,pos(0)
+       ,out(out_)
+       {
+       }
+
+       virtual ~WriteBufferStream()
+       {
+               try {
+                       flush();
+               } catch (StreamException &) {}
+               free();
+       }
+
+       void readFromFile(FileStream &file)
+       {
+               len = file.length();
+               buf = new char[len];
+               own = true;
+               pos = 0;
+               file.read(buf,len);
+       }
+
+       void flush()
+       {
+               if (!out || !buf) return;
+               out->write(buf, pos);
+               pos = 0;
+       }
+
+       void free()
+       {
+               if (own && buf)
+               {
+                       delete buf;
+                       buf = NULL;
+                       own = false;
+               }
+
+       }
+
+       virtual int read(void *p,int l)
+    {
+               return 0;
+    }
+
+       virtual void write(const void *p,int l)
+    {
+               char *cp = (char *) p;
+               while ((pos + l) >= len) {
+                       int n = len - pos;
+                       memcpy(&buf[pos], cp, n);
+                       l -= n;
+                       cp += n;
+                       pos = len;
+                       flush();
+                       if (pos != 0) return;
+               }
+               if (l > 0) {
+                       memcpy(&buf[pos], cp, l);
+                       pos += l;
+               }
+    }
+
+    virtual bool eof()
+    {
+        return true;
+    }
+
+       virtual void rewind()
+       {
+               pos = 0;
+       }
+
+       virtual void seekTo(int p)
+       {
+               pos = p;
+       }
+
+       virtual int getPosition()
+       {
+               return pos;
+       }
+
+       void    convertFromBase64();
+
+
+       char *buf;
+       bool own;
+       int len,pos;
+       Stream *out;
+};
+
+#endif
+
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/sys.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/sys.cpp
new file mode 100644 (file)
index 0000000..1e0704b
--- /dev/null
@@ -0,0 +1,1041 @@
+// ------------------------------------------------
+// File : sys.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             Sys is a base class for all things systemy, like starting threads, creating sockets etc..
+//             Lock is a very basic cross platform CriticalSection class               
+//             SJIS-UTF8 conversion by ????
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "common.h"
+#include "sys.h"
+#include "socket.h"
+#include "gnutella.h"
+#include "servmgr.h" //JP-EX
+#ifdef WIN32
+#include "utf8.h" //JP-Patch
+#endif
+#include <stdlib.h>
+#include <time.h>
+#include "jis.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// -----------------------------------
+#define isSJIS(a,b) ((a >= 0x81 && a <= 0x9f || a >= 0xe0 && a<=0xfc) && (b >= 0x40 && b <= 0x7e || b >= 0x80 && b<=0xfc))
+#define isEUC(a) (a >= 0xa1 && a <= 0xfe)
+#define isASCII(a) (a <= 0x7f) 
+#define isPLAINASCII(a) (((a >= '0') && (a <= '9')) || ((a >= 'a') && (a <= 'z')) || ((a >= 'A') && (a <= 'Z')))
+#define isUTF8(a,b) ((a & 0xc0) == 0xc0 && (b & 0x80) == 0x80 )
+#define isESCAPE(a,b) ((a == '&') && (b == '#'))
+#define isHTMLSPECIAL(a) ((a == '&') || (a == '\"') || (a == '\'') || (a == '<') || (a == '>'))
+
+
+
+// -----------------------------------
+const char *LogBuffer::logTypes[]=
+{
+       "",
+       "DBUG",
+       "EROR",
+       "GNET",
+       "CHAN",
+};
+
+// -----------------------------------
+// base64 encode/decode taken from ices2 source.. 
+static char base64table[64] = {
+    'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
+    'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
+    'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
+    'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
+};
+#if 0
+// -----------------------------------
+static char *util_base64_encode(char *data)
+{
+    int len = strlen(data);
+    char *out = malloc(len*4/3 + 4);
+    char *result = out;
+    int chunk;
+
+    while(len > 0) {
+        chunk = (len >3)?3:len;
+        *out++ = base64table[(*data & 0xFC)>>2];
+        *out++ = base64table[((*data & 0x03)<<4) | ((*(data+1) & 0xF0) >> 4)];
+        switch(chunk) {
+            case 3:
+                *out++ = base64table[((*(data+1) & 0x0F)<<2) | ((*(data+2) & 0xC0)>>6)];
+                *out++ = base64table[(*(data+2)) & 0x3F];
+                break;
+            case 2:
+                *out++ = base64table[((*(data+1) & 0x0F)<<2)];
+                *out++ = '=';
+                break;
+            case 1:
+                *out++ = '=';
+                *out++ = '=';
+                break;
+        }
+        data += chunk;
+        len -= chunk;
+    }
+
+    return result;
+}
+#endif
+
+// -----------------------------------
+static int base64chartoval(char input)
+{
+    if(input >= 'A' && input <= 'Z')
+        return input - 'A';
+    else if(input >= 'a' && input <= 'z')
+        return input - 'a' + 26;
+    else if(input >= '0' && input <= '9')
+        return input - '0' + 52;
+    else if(input == '+')
+        return 62;
+    else if(input == '/')
+        return 63;
+    else if(input == '=')
+        return -1;
+    else
+        return -2;
+}
+
+// -----------------------------------
+static char *util_base64_decode(char *input)
+{
+       return NULL;
+}
+
+
+
+
+
+// ------------------------------------------
+Sys::Sys()
+{
+       idleSleepTime = 10;
+       logBuf = new LogBuffer(1000,100);
+       numThreads=0;
+}
+
+// ------------------------------------------
+void Sys::sleepIdle()
+{
+       sleep(idleSleepTime);
+}
+
+// ------------------------------------------
+bool Host::isLocalhost()
+{
+       return loopbackIP() || (ip == ClientSocket::getIP(NULL)); 
+}
+// ------------------------------------------
+void Host::fromStrName(const char *str, int p)
+{
+       if (!strlen(str))
+       {
+               port = 0;
+               ip = 0;
+               return;
+       }
+
+       char name[128];
+       strncpy(name,str,sizeof(name)-1);
+       name[127] = '\0';
+       port = p;
+       char *pp = strstr(name,":");
+       if (pp)
+       {
+               port = atoi(pp+1);
+               pp[0] = 0;
+       }
+
+       ip = ClientSocket::getIP(name);
+}
+// ------------------------------------------
+void Host::fromStrIP(const char *str, int p)
+{
+       unsigned int ipb[4];
+       unsigned int ipp;
+
+
+       if (strstr(str,":"))
+       {
+               if (sscanf(str,"%03d.%03d.%03d.%03d:%d",&ipb[0],&ipb[1],&ipb[2],&ipb[3],&ipp) == 5)
+               {
+                       ip = ((ipb[0]&0xff) << 24) | ((ipb[1]&0xff) << 16) | ((ipb[2]&0xff) << 8) | ((ipb[3]&0xff));
+                       port = ipp;
+               }else
+               {
+                       ip = 0;
+                       port = 0;
+               }
+       }else{
+               port = p;
+               if (sscanf(str,"%03d.%03d.%03d.%03d",&ipb[0],&ipb[1],&ipb[2],&ipb[3]) == 4)
+                       ip = ((ipb[0]&0xff) << 24) | ((ipb[1]&0xff) << 16) | ((ipb[2]&0xff) << 8) | ((ipb[3]&0xff));
+               else
+                       ip = 0;
+       }
+}
+// -----------------------------------
+bool Host::isMemberOf(Host &h)
+{
+       if (h.ip==0)
+               return false;
+
+    if( h.ip0() != 255 && ip0() != h.ip0() )
+        return false;
+    if( h.ip1() != 255 && ip1() != h.ip1() )
+        return false;
+    if( h.ip2() != 255 && ip2() != h.ip2() )
+        return false;
+    if( h.ip3() != 255 && ip3() != h.ip3() )
+        return false;
+
+/* removed for endieness compatibility
+       for(int i=0; i<4; i++)
+               if (h.ipByte[i] != 255)
+                       if (ipByte[i] != h.ipByte[i])
+                               return false;
+*/
+       return true;
+}
+
+// -----------------------------------
+char *trimstr(char *s1)
+{
+       while (*s1)
+       {
+               if ((*s1 == ' ') || (*s1 == '\t'))
+                       s1++;
+               else
+                       break;
+
+       }
+
+       char *s = s1;
+
+       if(strlen(s1) > 0) {
+/*     s1 = s1+strlen(s1);
+
+       while (*--s1)
+               if ((*s1 != ' ') && (*s1 != '\t'))
+                       break;*/
+
+               s1 = s1+strlen(s1);
+
+//     s1[1] = 0;
+
+               while (*--s1)
+                       if ((*s1 != ' ') && (*s1 != '\t'))
+                               break;
+               s1[1] = 0;
+       }
+       return s;
+}
+
+// -----------------------------------
+char *stristr(const char *s1, const char *s2)
+{
+       while (*s1)
+       {
+               if (TOUPPER(*s1) == TOUPPER(*s2))
+               {
+                       const char *c1 = s1;
+                       const char *c2 = s2;
+
+                       while (*c1 && *c2)
+                       {
+                               if (TOUPPER(*c1) != TOUPPER(*c2))
+                                       break;
+                               c1++;
+                               c2++;
+                       }
+                       if (*c2==0)
+                               return (char *)s1;
+               }
+
+               s1++;
+       }
+       return NULL;
+}
+// -----------------------------------
+bool String::isValidURL()
+{
+       return (strnicmp(data,"http://",7)==0) || (strnicmp(data,"mailto:",7)==0);
+}
+
+// -----------------------------------
+void String::setFromTime(unsigned int t)
+{
+//     char *p = ctime((time_t*)&t);
+       time_t tmp = t;
+       char *p = ctime(&tmp);
+       if (p)
+               strcpy(data,p);
+       else
+               strcpy(data,"-");
+       type = T_ASCII;
+}
+// -----------------------------------
+void String::setFromStopwatch(unsigned int t)
+{
+       unsigned int sec,min,hour,day;
+
+       sec = t%60;
+       min = (t/60)%60;
+       hour = (t/3600)%24;
+       day = (t/86400);
+
+       if (day)
+               sprintf(data,"%d day, %d hour",day,hour);
+       else if (hour)
+               sprintf(data,"%d hour, %d min",hour,min);
+       else if (min)
+               sprintf(data,"%d min, %d sec",min,sec);
+       else if (sec)
+               sprintf(data,"%d sec",sec);
+       else
+               sprintf(data,"-");
+
+       type = T_ASCII;
+}
+// -----------------------------------
+void String::setFromString(const char *str, TYPE t)
+{
+       int cnt=0;
+       bool quote=false;
+       while (*str)
+       {
+               bool add=true;
+               if (*str == '\"')
+               {
+                       if (quote) 
+                               break;
+                       else 
+                               quote = true;
+                       add = false;
+               }else if (*str == ' ')
+               {
+                       if (!quote)
+                       {
+                               if (cnt)
+                                       break;
+                               else
+                                       add = false;
+                       }
+               }
+
+               if (add)
+               {
+                       data[cnt++] = *str++;
+                       if (cnt >= (MAX_LEN-1))
+                               break;
+               }else
+                       str++;
+       }
+       data[cnt] = 0;
+       type = t;
+}
+
+// -----------------------------------
+int String::base64WordToChars(char *out,const char *input)
+{
+       char *start = out;
+       signed char vals[4];
+
+    vals[0] = base64chartoval(*input++);
+    vals[1] = base64chartoval(*input++);
+    vals[2] = base64chartoval(*input++);
+    vals[3] = base64chartoval(*input++);
+
+    if(vals[0] < 0 || vals[1] < 0 || vals[2] < -1 || vals[3] < -1) 
+               return 0;
+
+    *out++ = vals[0]<<2 | vals[1]>>4;
+    if(vals[2] >= 0)
+        *out++ = ((vals[1]&0x0F)<<4) | (vals[2]>>2);
+    else
+        *out++ = 0;
+
+    if(vals[3] >= 0)
+        *out++ = ((vals[2]&0x03)<<6) | (vals[3]);
+    else
+        *out++ = 0;
+
+       return out-start;
+}
+
+// -----------------------------------
+void String::BASE642ASCII(const char *input)
+{
+       char *out = data;
+    int len = strlen(input);
+
+    while(len >= 4) 
+       {
+               out += base64WordToChars(out,input);
+               input += 4;
+        len -= 4;
+    }
+    *out = 0;
+}
+
+
+
+// -----------------------------------
+void String::UNKNOWN2UNICODE(const char *in,bool safe)
+{
+       MemoryStream utf8(data,MAX_LEN-1);
+
+       unsigned char c;
+       unsigned char d;
+
+       while (c = *in++)
+       {
+               d = *in;
+
+               if (isUTF8(c,d))                // utf8 encoded 
+               {
+                       int numChars=0;
+                       int i;
+
+                       for(i=0; i<6; i++)
+                       {
+                               if (c & (0x80>>i))
+                                       numChars++;
+                               else
+                                       break;
+                       }
+
+                       utf8.writeChar(c);
+                       for(i=0; i<numChars-1; i++)
+                               utf8.writeChar(*in++);
+
+               }
+               else if(isSJIS(c,d))                    // shift_jis
+               {
+                       utf8.writeUTF8(JISConverter::sjisToUnicode((c<<8 | d)));
+                       in++;
+
+               }
+               else if(isEUC(c) && isEUC(d))           // euc-jp
+               {
+                       utf8.writeUTF8(JISConverter::eucToUnicode((c<<8 | d)));
+                       in++;
+
+               }
+               else if (isESCAPE(c,d))         // html escape tags &#xx;
+               {
+                       in++;
+                       char code[16];
+                       char *cp = code;
+                       while (c=*in++) 
+                       {
+                               if (c!=';')
+                                       *cp++ = c;
+                               else
+                                       break;
+                       }
+                       *cp = 0;
+
+                       utf8.writeUTF8(strtoul(code,NULL,10));
+
+               }
+               else if (isPLAINASCII(c))       // plain ascii : a-z 0-9 etc..
+               {
+                       utf8.writeUTF8(c);
+
+               }
+               else if (isHTMLSPECIAL(c) && safe)                      
+               {
+                       const char *str = NULL;
+                       if (c == '&') str = "&amp;";
+                       else if (c == '\"') str = "&quot;";
+                       else if (c == '\'') str = "&#039;";
+                       else if (c == '<') str = "&lt;";
+                       else if (c == '>') str = "&gt;";
+                       else str = "?";
+
+                       utf8.writeString(str);
+               }
+               else
+               {
+                       utf8.writeUTF8(c);
+               }
+
+               if (utf8.pos >= (MAX_LEN-10))
+                       break;
+
+
+       }
+
+       utf8.writeChar(0);      // null terminate
+
+}
+
+// -----------------------------------
+void String::ASCII2HTML(const char *in)
+{
+       char *op = data;
+       char *oe = data+MAX_LEN-10;
+       unsigned char c;
+       const char *p = in;
+       while (c = *p++)
+       {
+               
+               if (((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')))
+               {
+                       *op++ = c;
+               }else
+               {
+                       sprintf(op,"&#x%02X;",(int)c);
+                       op+=6;
+               }
+               if (op >= oe)
+                       break;
+       }
+       *op = 0;
+}
+// -----------------------------------
+void String::ASCII2ESC(const char *in, bool safe)
+{
+       char *op = data;
+       char *oe = data+MAX_LEN-10;
+       const char *p = in;
+       unsigned char c;
+       while (c = *p++)
+       {
+               if (((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')))
+                       *op++ = c;
+               else
+               {
+                       *op++ = '%';
+                       if (safe)
+                               *op++ = '%';
+                       *op=0;
+                       sprintf(op,"%02X",(int)c);
+                       op+=2;
+               }
+               if (op >= oe)
+                       break;
+       }
+       *op=0;
+}
+// -----------------------------------
+void String::HTML2ASCII(const char *in)
+{
+       unsigned char c;
+       char *o = data;
+       char *oe = data+MAX_LEN-10;
+       const char *p = in;
+       while (c = *p++)
+       {
+               if ((c == '&') && (p[0] == '#'))
+               {
+                       p++;
+                       char code[8];
+                       char *cp = code;
+                       char ec = *p++;         // hex/dec
+                       while (c=*p++) 
+                       {
+                               if (c!=';')
+                                       *cp++ = c;
+                               else
+                                       break;
+                       }
+                       *cp = 0;
+                       c = (unsigned char)strtoul(code,NULL,ec=='x'?16:10);
+               }
+               *o++ = c;
+               if (o >= oe)
+                       break;
+       }
+
+       *o=0;
+}
+// -----------------------------------
+void String::HTML2UNICODE(const char *in)
+{
+       MemoryStream utf8(data,MAX_LEN-1);
+
+       unsigned char c;
+       while (c = *in++)
+       {
+               if ((c == '&') && (*in == '#'))
+               {
+                       in++;
+                       char code[16];
+                       char *cp = code;
+                       char ec = *in++;                // hex/dec
+                       while (c=*in++) 
+                       {
+                               if (c!=';')
+                                       *cp++ = c;
+                               else
+                                       break;
+                       }
+                       *cp = 0;
+                       utf8.writeUTF8(strtoul(code,NULL,ec=='x'?16:10));
+               }else
+                       utf8.writeUTF8(c);
+
+               if (utf8.pos >= (MAX_LEN-10))
+                       break;
+       }
+
+       utf8.writeUTF8(0);
+}
+
+// -----------------------------------
+void String::ESC2ASCII(const char *in)
+{
+       unsigned char c;
+       char *o = data;
+       char *oe = data+MAX_LEN-10;
+       const char *p = in;
+       while (c = *p++)
+       {
+               if (c == '+')
+                       c = ' ';
+               else if (c == '%')
+               {
+                       if (p[0] == '%')
+                               p++;
+
+                       char hi = TOUPPER(p[0]);
+                       char lo = TOUPPER(p[1]);
+                       c = (TONIBBLE(hi)<<4) | TONIBBLE(lo);
+                       p+=2;
+               }
+               *o++ = c;
+               if (o >= oe)
+                       break;
+       }
+
+       *o=0;
+}
+// -----------------------------------
+void String::ASCII2META(const char *in, bool safe)
+{
+       char *op = data;
+       char *oe = data+MAX_LEN-10;
+       const char *p = in;
+       unsigned char c;
+       while (c = *p++)
+       {
+               switch (c)
+               {
+                       case '%':
+                               if (safe)
+                                       *op++='%';
+                               break;
+                       case ';':
+                               c = ':';
+                               break;
+               }
+
+               *op++=c;
+               if (op >= oe)
+                       break;
+       }
+       *op=0;
+}
+#ifdef WIN32
+// -----------------------------------
+void String::ASCII2SJIS(const char *in) //JP-EX
+{
+       char *op = data;
+       char *p;
+       if (utf8_decode(in,&p)<0)
+       {
+               strcpy(op,in);
+               return;
+       }
+       strcpy(op,p);
+       free(p);
+}
+#endif
+// -----------------------------------
+void String::convertTo(TYPE t)
+{
+       if (t != type)
+       {
+               String tmp = *this;
+
+               // convert to ASCII
+               switch (type)
+               {
+                       case T_UNKNOWN:
+                       case T_ASCII:
+                               break;
+                       case T_HTML:
+                               tmp.HTML2ASCII(data);
+                               break;
+                       case T_ESC:
+                       case T_ESCSAFE:
+                               tmp.ESC2ASCII(data);
+                               break;
+                       case T_META:
+                       case T_METASAFE:
+                               break;
+                       case T_BASE64:
+                               tmp.BASE642ASCII(data);
+                               break;
+               }
+
+               // convert to new format
+               switch (t)
+               {
+                       case T_UNKNOWN:
+                       case T_ASCII:
+                               strcpy(data,tmp.data);
+                               break;
+                       case T_UNICODE:
+                               UNKNOWN2UNICODE(tmp.data,false);
+                               break;
+                       case T_UNICODESAFE:
+                               UNKNOWN2UNICODE(tmp.data,true);
+                               break;
+                       case T_HTML:
+                               ASCII2HTML(tmp.data);
+                               break;
+                       case T_ESC:
+                               ASCII2ESC(tmp.data,false);
+                               break;
+                       case T_ESCSAFE:
+                               ASCII2ESC(tmp.data,true);
+                               break;
+                       case T_META:
+                               ASCII2META(tmp.data,false);
+                               break;
+                       case T_METASAFE:
+                               ASCII2META(tmp.data,true);
+                               break;
+#ifdef WIN32
+                       case T_SJIS: //JP-EX
+                               ASCII2SJIS(tmp.data);
+                               break;
+#endif
+               }
+
+               type = t;
+       }
+}
+// -----------------------------------
+void LogBuffer::write(const char *str, TYPE t)
+{
+       lock.on();
+
+       unsigned int len = strlen(str);
+       int cnt=0;
+       while (len)
+       {
+               unsigned int rlen = len;
+               if (rlen > (lineLen-1))
+                       rlen = lineLen-1;
+
+               int i = currLine % maxLines;
+               int bp = i*lineLen;
+               strncpy(&buf[bp],str,rlen);
+               buf[bp+rlen] = 0;
+               if (cnt==0)
+               {
+                       times[i] = sys->getTime();
+                       types[i] = t;
+               }else
+               {
+                       times[i] = 0;
+                       types[i] = T_NONE;
+               }
+               currLine++;
+
+               str += rlen;
+               len -= rlen;
+               cnt++;
+       }
+
+       lock.off();
+}
+
+// -----------------------------------
+char *getCGIarg(const char *str, const char *arg)
+{
+       if (!str)
+               return NULL;
+
+//     char *s = strstr(str,arg);
+       char *s = (char*)strstr(str,arg);
+
+       if (!s)
+               return NULL;
+
+       s += strlen(arg);
+
+       return s;
+}
+
+// -----------------------------------
+bool cmpCGIarg(char *str, char *arg, char *value)
+{
+       if ((!str) || (!strlen(value)))
+               return false;
+
+       if (strnicmp(str,arg,strlen(arg)) == 0)
+       {
+
+               str += strlen(arg);
+
+               return strncmp(str,value,strlen(value))==0;
+       }else
+               return false;
+}
+// -----------------------------------
+bool hasCGIarg(char *str, char *arg)
+{
+       if (!str)
+               return false;
+
+       char *s = strstr(str,arg);
+
+       if (!s)
+               return false;
+
+       return true;
+}
+
+
+// ---------------------------
+void GnuID::encode(Host *h, const char *salt1, const char *salt2, unsigned char salt3)
+{
+       int s1=0,s2=0;
+       for(int i=0; i<16; i++)
+       {
+               unsigned char ipb = id[i];
+
+               // encode with IP address 
+               if (h)
+                       ipb ^= ((unsigned char *)&h->ip)[i&3];
+
+               // add a bit of salt 
+               if (salt1)
+               {
+                       if (salt1[s1])
+                               ipb ^= salt1[s1++];
+                       else
+                               s1=0;
+               }
+
+               // and some more
+               if (salt2)
+               {
+                       if (salt2[s2])
+                               ipb ^= salt2[s2++];
+                       else
+                               s2=0;
+               }
+
+               // plus some pepper
+               ipb ^= salt3;
+
+               id[i] = ipb;
+       }
+
+}
+// ---------------------------
+void GnuID::toStr(char *str)
+{
+
+       str[0] = 0;
+       for(int i=0; i<16; i++)
+       {
+               char tmp[8];
+               unsigned char ipb = id[i];
+
+               sprintf(tmp,"%02X",ipb);
+               strcat(str,tmp);
+       }
+
+}
+// ---------------------------
+void GnuID::fromStr(const char *str)
+{
+       clear();
+
+       if (strlen(str) < 32)
+               return;
+
+       char buf[8];
+
+       buf[2] = 0;
+
+       for(int i=0; i<16; i++)
+       {
+               buf[0] = str[i*2];
+               buf[1] = str[i*2+1];
+               id[i] = (unsigned char)strtoul(buf,NULL,16);
+       }
+
+}
+
+// ---------------------------
+void GnuID::generate(unsigned char flags)
+{
+       clear();
+
+       for(int i=0; i<16; i++)
+               id[i] = sys->rnd();
+
+       id[0] = flags;
+}
+
+// ---------------------------
+unsigned char GnuID::getFlags()
+{
+       return id[0];
+}
+
+// ---------------------------
+GnuIDList::GnuIDList(int max)
+:ids(new GnuID[max])
+{
+       maxID = max;
+       for(int i=0; i<maxID; i++)
+               ids[i].clear();
+}
+// ---------------------------
+GnuIDList::~GnuIDList()
+{
+       delete [] ids;
+}
+// ---------------------------
+bool GnuIDList::contains(GnuID &id)
+{
+       for(int i=0; i<maxID; i++)
+               if (ids[i].isSame(id))
+                       return true;
+       return false;
+}
+// ---------------------------
+int GnuIDList::numUsed()
+{
+       int cnt=0;
+       for(int i=0; i<maxID; i++)
+               if (ids[i].storeTime)
+                       cnt++;
+       return cnt;
+}
+// ---------------------------
+unsigned int GnuIDList::getOldest()
+{
+       unsigned int t=(unsigned int)-1;
+       for(int i=0; i<maxID; i++)
+               if (ids[i].storeTime)
+                       if (ids[i].storeTime < t)
+                               t = ids[i].storeTime;
+       return t;
+}
+// ---------------------------
+void GnuIDList::add(GnuID &id)
+{
+       unsigned int minTime = (unsigned int) -1;
+       int minIndex = 0;
+
+       // find same or oldest
+       for(int i=0; i<maxID; i++)
+       {
+               if (ids[i].isSame(id))
+               {
+                       ids[i].storeTime = sys->getTime();
+                       return;
+               }
+               if (ids[i].storeTime <= minTime)
+               {
+                       minTime = ids[i].storeTime;
+                       minIndex = i;
+               }
+       }
+
+       ids[minIndex] = id;
+       ids[minIndex].storeTime = sys->getTime();
+}
+// ---------------------------
+void GnuIDList::clear()
+{
+       for(int i=0; i<maxID; i++)
+               ids[i].clear();
+}
+       
+// ---------------------------
+void LogBuffer::dumpHTML(Stream &out)
+{
+       WLockBlock lb(&lock);
+       lb.on();
+
+       unsigned int nl = currLine;
+       unsigned int sp = 0;
+       if (nl > maxLines)
+       {
+               nl = maxLines-1;
+               sp = (currLine+1)%maxLines;
+       }
+
+       String tim,str;
+       if (nl)
+       {
+               for(unsigned int i=0; i<nl; i++)
+               {
+                       unsigned int bp = sp*lineLen;
+
+                       if (types[sp])
+                       {
+                               tim.setFromTime(times[sp]);
+
+                               out.writeString(tim.cstr());
+                               out.writeString(" <b>[");
+                               out.writeString(getTypeStr(types[sp]));
+                               out.writeString("]</b> ");
+                       }
+                       str.set(&buf[bp]);
+                       str.convertTo(String::T_HTML);
+
+                       out.writeString(str.cstr());
+                       out.writeString("<br>");
+
+                       sp++;
+                       sp %= maxLines;
+               }
+       }
+
+       lb.off();
+
+}
+
+// ---------------------------
+void   ThreadInfo::shutdown()
+{
+       active = false;
+       //sys->waitThread(this);
+}
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/sys.h b/c:/Git/PeerCast.root/PeerCast/core/common/sys.h
new file mode 100644 (file)
index 0000000..5583a9d
--- /dev/null
@@ -0,0 +1,534 @@
+// ------------------------------------------------
+// File : sys.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _SYS_H
+#define _SYS_H
+
+#include <string.h>
+#include "common.h"
+
+#define RAND(a,b) (((a = 36969 * (a & 65535) + (a >> 16)) << 16) + \
+                    (b = 18000 * (b & 65535) + (b >> 16))  )
+extern char *stristr(const char *s1, const char *s2);
+extern char *trimstr(char *s);
+
+
+#define MAX_CGI_LEN 1024
+// ------------------------------------
+class String
+{
+public:
+       enum {
+               MAX_LEN = 256
+       };
+
+       enum TYPE
+       {
+               T_UNKNOWN,
+               T_ASCII,
+               T_HTML,
+               T_ESC,
+               T_ESCSAFE,
+               T_META,
+               T_METASAFE,
+               T_BASE64,
+               T_UNICODE,
+               T_UNICODESAFE,
+#ifdef WIN32
+               T_SJIS, //JP-EX
+#endif
+       };
+
+       String() {clear();}
+       String(const char *p, TYPE t=T_ASCII) 
+       {
+               set(p,t);
+       }
+
+       // set from straight null terminated string
+       void set(const char *p, TYPE t=T_ASCII) 
+       {
+               strncpy(data,p,MAX_LEN-1);
+               data[MAX_LEN-1] = 0;
+               type = t;
+       }
+
+       // set from quoted or unquoted null terminated string
+       void setFromString(const char *str, TYPE t=T_ASCII);
+       
+       // set from stopwatch
+       void setFromStopwatch(unsigned int t);
+
+       // set from time
+       void setFromTime(unsigned int t);
+
+
+       // from single word (end at whitespace)
+       void setFromWord(const char *str)
+       {
+               int i;
+               for(i=0; i<MAX_LEN-1; i++)
+               {
+                       data[i] = *str++;
+                       if ((data[i]==0) || (data[i]==' '))
+                               break;
+               }
+               data[i]=0;
+       }
+
+
+       // set from null terminated string, remove first/last chars
+       void setUnquote(const char *p, TYPE t=T_ASCII) 
+       {
+               int slen = strlen(p);
+               if (slen > 2)
+               {
+                       if (slen >= MAX_LEN) slen = MAX_LEN;
+                       strncpy(data,p+1,slen-2);
+                       data[slen-2]=0;
+               }else
+                       clear();
+               type = t;
+       }
+
+       void clear() 
+       {
+               data[0]=0;
+               type = T_UNKNOWN;
+       }
+       void ASCII2ESC(const char *,bool);
+       void ASCII2HTML(const char *);
+       void ASCII2META(const char *,bool);
+       void ESC2ASCII(const char *);
+       void HTML2ASCII(const char *);
+       void HTML2UNICODE(const char *);
+       void BASE642ASCII(const char *);
+       void UNKNOWN2UNICODE(const char *,bool);
+#ifdef WIN32
+       void ASCII2SJIS(const char *); //JP-EX
+#endif
+
+       static  int     base64WordToChars(char *,const char *);
+
+       static bool isSame(const char *s1, const char *s2) {return strcmp(s1,s2)==0;}
+
+       bool startsWith(const char *s) const {return strncmp(data,s,strlen(s))==0;}
+       bool isValidURL();
+       bool isEmpty() {return data[0]==0;}
+       bool isSame(::String &s) const {return strcmp(data,s.data)==0;}
+       bool isSame(const char *s) const {return strcmp(data,s)==0;}
+       bool contains(::String &s) {return stristr(data,s.data)!=NULL;}
+       bool contains(const char *s) {return stristr(data,s)!=NULL;}
+       void append(const char *s)
+       {
+               if ((strlen(s)+strlen(data) < (MAX_LEN-1)))
+                       strcat(data,s);
+       }
+       void append(char c)
+       {
+               char tmp[2];
+               tmp[0]=c;
+               tmp[1]=0;
+               append(tmp);
+       }
+
+       void prepend(const char *s)
+       {
+               ::String tmp;
+               tmp.set(s);
+               tmp.append(data);
+               tmp.type = type;
+               *this = tmp;
+       }
+
+       bool operator == (const char *s) const {return isSame(s);}
+
+       operator const char *() const {return data;}
+
+       void convertTo(TYPE t);
+
+       char    *cstr() {return data;}
+
+       static bool isWhitespace(char c) {return c==' ' || c=='\t';}
+
+       TYPE    type;
+       char    data[MAX_LEN];
+};
+
+// ------------------------------------
+namespace peercast {
+class Random {
+public:
+       Random(int s=0x14235465)
+       {
+               setSeed(s);
+       }
+       
+       unsigned int next()
+       {
+               return RAND(a[0],a[1]);
+       }
+
+       void setSeed(int s)
+       {
+               a[0] = a[1] = s;
+       }       
+       
+       unsigned long a[2];
+};
+}
+// ------------------------------------
+class Sys
+{
+public:
+       Sys();
+
+
+
+    virtual class ClientSocket *createSocket() = 0;
+       virtual bool                    startThread(class ThreadInfo *) = 0;
+       virtual void                    sleep(int) = 0;
+       virtual void                    appMsg(long,long = 0) = 0;
+       virtual unsigned int    getTime() = 0;          
+       virtual double                  getDTime() = 0;         
+       virtual unsigned int    rnd() = 0;
+       virtual void                    getURL(const char *) = 0;
+       virtual void                    exit() = 0;
+       virtual bool                    hasGUI() = 0;
+       virtual void                    callLocalURL(const char *,int)=0;
+       virtual void                    executeFile(const char *) = 0;
+       virtual void                    endThread(ThreadInfo *) {}
+       virtual void                    waitThread(ThreadInfo *, int timeout = 30000) {}
+
+
+
+#ifdef __BIG_ENDIAN__
+       unsigned short  convertEndian(unsigned short v) { return SWAP2(v); }
+       unsigned int    convertEndian(unsigned int v) { return SWAP4(v); }
+#else
+       unsigned short  convertEndian(unsigned short v) { return v; }
+       unsigned int    convertEndian(unsigned int v) { return v; }
+#endif
+
+
+       void    sleepIdle();
+
+       unsigned int idleSleepTime;
+       unsigned int rndSeed;
+       unsigned int numThreads;
+
+       class LogBuffer *logBuf;
+};
+
+
+#ifdef WIN32
+#include <windows.h>
+
+typedef __int64 int64_t;
+
+
+// ------------------------------------
+class WEvent
+{
+public:
+       WEvent()
+       {
+                event = ::CreateEvent(NULL, // no security attributes
+                                  TRUE, // manual-reset
+                                  FALSE,// initially non-signaled
+                                  NULL);// anonymous
+       }
+
+       ~WEvent()
+       {
+               ::CloseHandle(event);
+       }
+
+       void    signal()
+       {
+               ::SetEvent(event);
+       }
+
+       void    wait(int timeout = 30000)
+       {
+               switch(::WaitForSingleObject(event, timeout))
+               {
+          case WAIT_TIMEOUT:
+              throw TimeoutException();
+              break;
+          //case WAIT_OBJECT_0:
+              //break;
+               }
+       }
+
+       void    reset()
+       {
+               ::ResetEvent(event);
+       }
+
+
+
+       HANDLE event;
+};
+
+
+
+// ------------------------------------
+typedef int (WINAPI *THREAD_FUNC)(ThreadInfo *);
+typedef unsigned int THREAD_HANDLE;
+#define THREAD_PROC int WINAPI
+#define vsnprintf _vsnprintf
+
+// ------------------------------------
+class WLock
+{
+public:
+       WLock()
+       {
+               InitializeCriticalSection(&cs);
+       }
+
+
+       void    on()
+       {
+               EnterCriticalSection(&cs);
+       }
+
+       void    off()
+       {
+               LeaveCriticalSection(&cs);
+       }
+       
+       CRITICAL_SECTION cs;
+};
+#endif
+
+
+#ifdef _UNIX
+// ------------------------------------
+#include <pthread.h>
+#include <errno.h>
+
+#ifdef __APPLE__
+#include <sched.h>
+#define _BIG_ENDIAN 1
+#endif
+
+typedef long long int64_t;
+
+typedef int (*THREAD_FUNC)(ThreadInfo *);
+#define THREAD_PROC int 
+typedef pthread_t THREAD_HANDLE;
+
+// ------------------------------------
+#define stricmp strcasecmp
+#define strnicmp strncasecmp
+
+
+// ------------------------------------
+class WEvent
+{
+public:
+
+       WEvent()
+       {
+       }
+
+       void    signal()
+       {
+       }
+
+       void    wait(int timeout = 30000)
+       {
+       }
+
+       void    reset()
+       {
+       }
+
+};
+
+// ------------------------------------
+class WLock 
+{
+private:
+       pthread_mutex_t mutex;
+public:
+       WLock()
+       {
+           const pthread_mutexattr_t mattr = 
+               {
+#ifdef __APPLE__               
+                       PTHREAD_MUTEX_RECURSIVE
+#else
+                       PTHREAD_MUTEX_RECURSIVE_NP
+#endif
+                };
+                
+        pthread_mutex_init( &mutex, &mattr );
+       }
+
+       ~WLock()
+       {
+        pthread_mutex_destroy( &mutex );
+       }
+
+
+       void    on()
+       {
+               pthread_mutex_lock(&mutex);
+       }
+
+       void    off()
+       {
+               pthread_mutex_unlock(&mutex);
+       }
+       
+};
+#endif
+
+class WLockBlock
+{
+private:
+       WLock *lock;
+       bool flg;
+public:
+       WLockBlock(WLock *l){
+               lock = l;
+               flg = false;
+       }
+       ~WLockBlock(){
+               if (flg){
+                       lock->off();
+                       LOG_DEBUG("LOCK OFF by destructor");
+               }
+       }
+       void on(){
+               flg = true;
+               lock->on();
+       }
+       void off(){
+               flg = false;
+               lock->off();
+       }
+};
+
+// ------------------------------------
+class ThreadInfo
+{
+public:
+       //typedef int  (__stdcall *THREAD_FUNC)(ThreadInfo *);
+
+       ThreadInfo()
+       {
+               active = false;
+               finish = false;
+               id = 0;
+               func = NULL;
+               data = NULL;
+       }
+
+       void    shutdown();
+
+       volatile bool   active;
+       volatile bool   finish;
+       int             id;
+       THREAD_FUNC func;
+       THREAD_HANDLE handle;
+       
+
+       void    *data;
+};
+
+
+// ------------------------------------
+class LogBuffer 
+{
+public:
+       enum TYPE
+       {
+               T_NONE,
+               T_DEBUG,
+               T_ERROR,
+               T_NETWORK,
+               T_CHANNEL,
+       };
+
+       LogBuffer(int i, int l)
+       {
+               lineLen = l;
+               maxLines = i;
+               currLine = 0;
+               buf = new char[lineLen*maxLines];
+               times = new unsigned int [maxLines];
+               types = new TYPE [maxLines];
+       }
+
+       void    clear()
+       {
+               currLine = 0;
+       }
+       void    write(const char *, TYPE);
+       static const char *getTypeStr(TYPE t) {return logTypes[t];}
+       void    dumpHTML(class Stream &);
+
+       char *buf;
+       unsigned int *times;
+       unsigned int currLine,maxLines,lineLen;
+       TYPE    *types;
+       WLock   lock;
+       static  const char *logTypes[];
+
+};
+
+#define RWLOCK_READ_MAX 32
+
+class LockBlock
+{
+public:
+       LockBlock(WLock &l){ flg = false; lock = l; }
+       ~LockBlock(){ if (flg) lock.off(); }
+       void lockon(){ flg = true; lock.on(); }
+       void lockoff(){ flg = false; lock.off(); }
+
+private:
+       WLock lock;
+       bool flg;
+};
+
+// ------------------------------------
+extern Sys *sys;
+
+// ------------------------------------
+
+
+#if _BIG_ENDIAN
+#define CHECK_ENDIAN2(v) v=SWAP2(v)
+#define CHECK_ENDIAN3(v) v=SWAP3(v)
+#define CHECK_ENDIAN4(v) v=SWAP4(v)
+#else
+#define CHECK_ENDIAN2
+#define CHECK_ENDIAN3
+#define CHECK_ENDIAN4
+#endif
+
+
+// ------------------------------------
+#endif
+
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/url.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/url.cpp
new file mode 100644 (file)
index 0000000..f98d195
--- /dev/null
@@ -0,0 +1,355 @@
+// ------------------------------------------------
+// File : url.h
+// Date: 20-feb-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "url.h"
+#include "socket.h"
+#include "http.h"
+#include "servent.h"
+#include "servmgr.h"
+#include "peercast.h"
+#include "version2.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ------------------------------------------------
+void URLSource::stream(Channel *ch)
+{
+       
+       String url,tmpUrl;
+       while (ch->thread.active && !peercastInst->isQuitting)
+       {
+               tmpUrl = url;
+               if (url.isEmpty())
+                       url = baseurl;
+
+               url = streamURL(ch,url.cstr());
+               if (url == tmpUrl){
+                       sys->sleep(2000);
+               }
+       }
+
+}
+// ------------------------------------------------
+int URLSource::getSourceRate()
+{
+       if (inputStream)
+               return inputStream->bytesInPerSec;
+       else
+               return 0;
+}
+
+// ------------------------------------------------
+::String URLSource::streamURL(Channel *ch, const char *url)
+{
+       String nextURL;
+
+       if (peercastInst->isQuitting || !ch->thread.active)
+               return nextURL;
+
+
+       String urlTmp;
+       urlTmp.set(url);
+
+       char *fileName = urlTmp.cstr();
+
+       PlayList *pls=NULL;
+       ChannelStream *source=NULL;
+
+       LOG_CHANNEL("Fetch URL=%s",fileName);
+
+       try
+       {
+
+               // get the source protocol
+               if (strnicmp(fileName,"http://",7)==0)  
+               {
+                       ch->info.srcProtocol = ChanInfo::SP_HTTP;
+                       fileName += 7;
+               }
+               else if (strnicmp(fileName,"mms://",6)==0)      
+               {
+                       ch->info.srcProtocol = ChanInfo::SP_MMS;
+                       fileName += 6;
+               }
+               else if (strnicmp(fileName,"pcp://",6)==0)      
+               {
+                       ch->info.srcProtocol = ChanInfo::SP_PCP;
+                       fileName += 6;
+               }
+               else if (strnicmp(fileName,"file://",7)==0)     
+               {
+                       ch->info.srcProtocol = ChanInfo::SP_FILE;
+                       fileName += 7;
+               }
+               else 
+               {
+                       ch->info.srcProtocol = ChanInfo::SP_FILE;
+               }
+
+               // default to mp3 for shoutcast servers
+               if (ch->info.contentType == ChanInfo::T_PLS)
+                       ch->info.contentType = ChanInfo::T_MP3;
+
+
+               ch->setStatus(Channel::S_CONNECTING);
+
+               if ((ch->info.srcProtocol == ChanInfo::SP_HTTP) || (ch->info.srcProtocol == ChanInfo::SP_PCP) || (ch->info.srcProtocol == ChanInfo::SP_MMS))
+               {
+
+                       if ((ch->info.contentType == ChanInfo::T_WMA) || (ch->info.contentType == ChanInfo::T_WMV))
+                               ch->info.srcProtocol = ChanInfo::SP_MMS;
+
+                       
+                       LOG_CHANNEL("Channel source is HTTP");
+
+                       ClientSocket *inputSocket = sys->createSocket();
+                       if (!inputSocket)
+                               throw StreamException("Channel cannot create socket");
+
+
+                       inputStream = inputSocket;
+
+
+                       char *dir = strstr(fileName,"/");
+                       if (dir)
+                               *dir++=0;
+
+
+                       LOG_CHANNEL("Fetch Host=%s",fileName);
+                       if (dir)
+                               LOG_CHANNEL("Fetch Dir=%s",dir);
+
+
+                       Host host;
+                       host.fromStrName(fileName,80);
+
+                       inputSocket->open(host);
+                       inputSocket->connect();
+
+                       HTTP http(*inputSocket);
+                       http.writeLineF("GET /%s HTTP/1.0",dir?dir:"");
+
+                       http.writeLineF("%s %s",HTTP_HS_HOST,fileName);
+                       http.writeLineF("%s %s",HTTP_HS_CONNECTION,"close");
+                       http.writeLineF("%s %s",HTTP_HS_ACCEPT,"*/*");
+
+                       if (ch->info.srcProtocol == ChanInfo::SP_MMS)
+                       {
+                               http.writeLineF("%s %s",HTTP_HS_AGENT,"NSPlayer/4.1.0.3856");
+                               http.writeLine("Pragma: no-cache,rate=1.000000,request-context=1");
+                               //http.writeLine("Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=4294967295:4294967295,request-context=22605256,max-duration=0");
+                               http.writeLine("Pragma: xPlayStrm=1");
+                               http.writeLine("Pragma: xClientGUID={c77e7400-738a-11d2-9add-0020af0a3278}");
+                               http.writeLine("Pragma: stream-switch-count=2");
+                               http.writeLine("Pragma: stream-switch-entry=ffff:1:0 ffff:2:0");
+                       }else
+                       {
+                               http.writeLineF("%s %s",HTTP_HS_AGENT,PCX_AGENT);  
+                               http.writeLineF("%s %d",PCX_HS_PCP,1);  
+                               http.writeLine("Icy-MetaData:1");                               // fix by ravon 
+                       }
+
+                       http.writeLine("");
+
+                       int res = http.readResponse();
+
+
+                       String name = ch->info.name;
+
+                       while (http.nextHeader())
+                       {                               
+
+                               LOG_CHANNEL("Fetch HTTP: %s",http.cmdLine);
+
+                               ChanInfo tmpInfo = ch->info;
+                               Servent::readICYHeader(http,ch->info,NULL);
+
+                               if (!tmpInfo.name.isEmpty())
+                                       ch->info.name = tmpInfo.name;
+                               if (!tmpInfo.genre.isEmpty())
+                                       ch->info.genre = tmpInfo.genre;
+                               if (!tmpInfo.url.isEmpty())
+                                       ch->info.url = tmpInfo.url;
+
+                               if (http.isHeader("icy-metaint"))
+                                       ch->icyMetaInterval = http.getArgInt();
+                               else if (http.isHeader("Location:"))
+                                       nextURL.set(http.getArgStr());
+
+                               char *arg = http.getArgStr();
+                               if (arg)
+                               {
+                                       if (http.isHeader("content-type"))
+                                       {
+                                               if (stristr(arg,MIME_XSCPLS))
+                                                       pls = new PlayList(PlayList::T_SCPLS, 1000);
+                                               else if (stristr(arg,MIME_PLS))
+                                                       pls = new PlayList(PlayList::T_PLS, 1000);
+                                               else if (stristr(arg,MIME_XPLS))
+                                                       pls = new PlayList(PlayList::T_PLS, 1000);
+                                               else if (stristr(arg,MIME_M3U))
+                                                       pls = new PlayList(PlayList::T_PLS, 1000);
+                                               else if (stristr(arg,MIME_TEXT))
+                                                       pls = new PlayList(PlayList::T_PLS, 1000);
+                                               else if (stristr(arg,MIME_ASX))
+                                                       pls = new PlayList(PlayList::T_ASX, 1000);
+                                               else if (stristr(arg,MIME_MMS))
+                                                       ch->info.srcProtocol = ChanInfo::SP_MMS;
+                                       }
+                               }
+
+                       }
+
+                       if ((!nextURL.isEmpty()) && (res==302))
+                       {
+                               LOG_CHANNEL("Channel redirect: %s",nextURL.cstr());
+                               inputSocket->close();
+                               delete inputSocket;
+                               inputSocket = NULL;
+                               return nextURL;
+                       }
+
+                       if (res!=200)
+                       {
+                               LOG_ERROR("HTTP response: %d",res);
+                               throw StreamException("Bad HTTP connect");
+                       }
+
+
+               }else if (ch->info.srcProtocol == ChanInfo::SP_FILE)
+               {
+
+                       LOG_CHANNEL("Channel source is FILE");
+
+                       FileStream *fs = new FileStream();
+                       fs->openReadOnly(fileName);
+                       inputStream = fs;
+
+                       ChanInfo::TYPE fileType = ChanInfo::T_UNKNOWN;
+                       // if filetype is unknown, try and figure it out from file extension.
+                       //if ((info.srcType == ChanInfo::T_UNKNOWN) || (info.srcType == ChanInfo::T_PLAYLIST))
+                       {
+                               const char *ext = fileName+strlen(fileName);
+                               while (*--ext)
+                                       if (*ext=='.')
+                                       {
+                                               ext++;
+                                               break;
+                                       }
+
+                               fileType = ChanInfo::getTypeFromStr(ext);
+                       }
+
+
+                       if (ch->info.bitrate)
+                               ch->readDelay = true;
+
+
+                       if (fileType == ChanInfo::T_PLS) 
+                               pls = new PlayList(PlayList::T_PLS, 1000);
+                       else if (fileType == ChanInfo::T_ASX) 
+                               pls = new PlayList(PlayList::T_ASX, 1000);
+                       else
+                               ch->info.contentType = fileType;
+
+               }else
+               {
+                       throw StreamException("Unsupported URL");
+               }
+
+               
+               if (pls)
+               {
+
+                       LOG_CHANNEL("Channel is Playlist");
+
+                       pls->read(*inputStream);
+
+                       inputStream->close();
+                       delete inputStream;
+                       inputStream = NULL;
+
+                       int urlNum=0;
+                       String url;
+
+                       LOG_CHANNEL("Playlist: %d URLs",pls->numURLs);
+                       while ((ch->thread.active) && (pls->numURLs) && (!peercastInst->isQuitting))
+                       {
+                               if (url.isEmpty())
+                               {
+                                       url = pls->urls[urlNum%pls->numURLs];
+                                       urlNum++;
+                               }
+                               try
+                               {
+                                       url = streamURL(ch,url.cstr());
+                               }catch(StreamException &)
+                               {}
+                       }
+
+                       delete pls;
+                       
+               }else
+               {
+
+                       // if we didn`t get a channel id from the source, then create our own (its an original broadcast)
+                       if (!ch->info.id.isSet())
+                       {
+                               ch->info.id = chanMgr->broadcastID;
+                               ch->info.id.encode(NULL,ch->info.name.cstr(),ch->info.genre,ch->info.bitrate);
+                       }
+
+                       if (ch->info.contentType == ChanInfo::T_ASX)
+                               ch->info.contentType = ChanInfo::T_WMV;
+
+                       ch->setStatus(Channel::S_BROADCASTING);
+
+                       inputStream->setReadTimeout(60);        // use longer read timeout
+
+                       source = ch->createSource();
+
+                       ch->readStream(*inputStream,source);
+
+                       inputStream->close();
+               }
+
+       }catch(StreamException &e)
+       {
+               ch->setStatus(Channel::S_ERROR);
+               LOG_ERROR("Channel error: %s",e.msg);
+               sys->sleep(1000);
+       }
+
+
+       ch->setStatus(Channel::S_CLOSING);
+       if (inputStream)
+       {
+               delete inputStream;
+               inputStream = NULL;
+       }
+
+       if (source)
+               delete source;
+
+
+       return nextURL;
+
+}
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/url.h b/c:/Git/PeerCast.root/PeerCast/core/common/url.h
new file mode 100644 (file)
index 0000000..8d113c0
--- /dev/null
@@ -0,0 +1,49 @@
+// ------------------------------------------------
+// File : url.h
+// Date: 20-feb-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _URL_H
+#define _URL_H
+
+#include "channel.h"
+
+// ------------------------------------------------
+class URLSource : public ChannelSource
+{
+public:
+       URLSource(const char *url) 
+       :inputStream(NULL)
+       {
+               baseurl.set(url);
+       }
+
+       ::String streamURL(Channel *, const char *);    
+
+       virtual void stream(Channel *);
+
+       virtual int getSourceRate();
+
+
+       Stream          *inputStream;
+       ::String        baseurl;
+};
+
+
+
+
+#endif
+
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/utf8.c b/c:/Git/PeerCast.root/PeerCast/core/common/utf8.c
new file mode 100644 (file)
index 0000000..4747c3f
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2001 Peter Harris <peter.harris@hummingbird.com>
+ * Copyright (C) 2001 Edmund Grimley Evans <edmundo@rano.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * Convert a string between UTF-8 and the locale's charset.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "utf8.h"
+#include "identify_encoding.h"
+#ifdef _WIN32
+
+/* Thanks to Peter Harris <peter.harris@hummingbird.com> for this win32
+ * code.
+ */
+
+#include <stdio.h>
+#include <windows.h>
+
+static unsigned char *make_utf8_string(const wchar_t *unicode)
+{
+       int size = 0, index = 0, out_index = 0;
+       unsigned char *out;
+       unsigned short c;
+
+       /* first calculate the size of the target string */
+       c = unicode[index++];
+       while (c) 
+       {
+               if (c < 0x0080) 
+               {
+                       size += 1;
+               }
+               else if (c < 0x0800)
+               {
+                       size += 2;
+        }else{
+                       size += 3;
+               }
+               c = unicode[index++];
+       }
+
+       out = (unsigned char *)malloc(size + 1);
+       if (out == NULL)
+               return NULL;
+       index = 0;
+
+       c = unicode[index++];
+       while (c)
+    {
+               if (c < 0x080)
+               {
+                       out[out_index++] = (unsigned char)c;
+               }else if (c < 0x800)
+               {
+                       out[out_index++] = 0xc0 | (c >> 6);
+                       out[out_index++] = 0x80 | (c & 0x3f);
+        }else{
+                       out[out_index++] = 0xe0 | (c >> 12);
+                       out[out_index++] = 0x80 | ((c >> 6) & 0x3f);
+                       out[out_index++] = 0x80 | (c & 0x3f);
+               }
+               c = unicode[index++];
+       }
+       out[out_index] = 0x00;
+
+       return out;
+}
+
+static wchar_t *make_unicode_string(const unsigned char *utf8)
+{
+       int size = 0, index = 0, out_index = 0;
+       wchar_t *out;
+       unsigned char c;
+
+       /* first calculate the size of the target string */
+       c = utf8[index++];
+       while (c)
+       {
+               if ((c & 0x80) == 0)
+               {
+                       index += 0;
+               }else if((c & 0xe0) == 0xe0)
+               {
+                       index += 2;
+        }else{
+                       index += 1;
+               }
+               size += 1;
+               c = utf8[index++];
+       }
+
+       out = (wchar_t *)malloc((size + 1) * sizeof(wchar_t));
+       if (out == NULL)
+               return NULL;
+       index = 0;
+
+       c = utf8[index++];
+       while (c)
+       {
+               if ((c & 0x80) == 0)
+               {
+            out[out_index++] = c;
+        }else if ((c & 0xe0) == 0xe0)
+               {
+                       out[out_index] = (c & 0x1F) << 12;
+                       c = utf8[index++];
+                       out[out_index] |= (c & 0x3F) << 6;
+                       c = utf8[index++];
+                       out[out_index++] |= (c & 0x3F);
+        }else{
+                       out[out_index] = (c & 0x3F) << 6;
+                       c = utf8[index++];
+                       out[out_index++] |= (c & 0x3F);
+               }
+               c = utf8[index++];
+       }
+       out[out_index] = 0;
+
+       return out;
+}
+
+int utf8_encode(const char *from, char **to)
+{
+       wchar_t *unicode;
+       int wchars, err;
+
+
+       wchars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from,
+                       strlen(from), NULL, 0);
+
+       if(wchars == 0)
+       {
+//             fprintf(stderr, "Unicode translation error %d\n", GetLastError());
+               return -1;
+       }
+
+       unicode = (wchar_t *)calloc(wchars + 1, sizeof(unsigned short));
+       if(unicode == NULL) 
+       {
+//             fprintf(stderr, "Out of memory processing string to UTF8\n");
+               return -1;
+       }
+
+       err = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, strlen(from), unicode, wchars);
+       if (err != wchars)
+       {
+               free(unicode);
+//             fprintf(stderr, "Unicode translation error %d\n", GetLastError());
+               return -1;
+       }
+
+       /* On NT-based windows systems, we could use WideCharToMultiByte(), but 
+        * MS doesn't actually have a consistent API across win32.
+        */
+       *to = (char *)make_utf8_string(unicode);
+
+       free(unicode);
+       return 0;
+}
+
+int utf8_decode(const char *from, char **to)
+{
+       wchar_t *unicode;
+       int chars, err;
+
+       const char *cds;
+       identify_encoding_t *cdt;
+       enum identify_encoding_order order;
+       order = ieo_SJIS;
+       cdt = identify_encoding_open(order);
+       cds = identify_encoding(cdt,(char *)from);
+       if (strcmp(cds,"UTF-8")!=0)
+       {
+               identify_encoding_close(cdt);
+               return -1;
+       }
+       identify_encoding_close(cdt);
+
+
+       /* On NT-based windows systems, we could use MultiByteToWideChar(CP_UTF8), but 
+        * MS doesn't actually have a consistent API across win32.
+        */
+       unicode = (wchar_t *)make_unicode_string((const unsigned char *)from);
+       if (unicode == NULL) 
+       {
+//             fprintf(stderr, "Out of memory processing string from UTF8 to UNICODE16\n");
+               return -1;
+       }
+
+       chars = WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, unicode, -1, NULL, 0, NULL, NULL);
+
+       if (chars == 0)
+       {
+//             fprintf(stderr, "Unicode translation error %d\n", GetLastError());
+               free(unicode);
+               return -1;
+       }
+
+       *to = (char *)calloc(chars + 1, sizeof(unsigned char));
+       if (*to == NULL) 
+       {
+//             fprintf(stderr, "Out of memory processing string to local charset\n");
+               free(unicode);
+               return -1;
+       }
+
+       err = WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, unicode, -1, *to, chars, NULL, NULL);
+       if (err != chars)
+       {
+//             fprintf(stderr, "Unicode translation error %d\n", GetLastError());
+               free(unicode);
+               free(*to);
+               *to = NULL;
+               return -1;
+       }
+
+       free(unicode);
+       return 0;
+}
+
+#else /* End win32. Rest is for real operating systems */
+
+
+#ifdef HAVE_LANGINFO_CODESET
+#include <langinfo.h>
+#endif
+
+int iconvert(const char *fromcode, const char *tocode,
+                        const char *from, size_t fromlen,
+                        char **to, size_t *tolen);
+
+static char *current_charset = 0; /* means "US-ASCII" */
+
+void convert_set_charset(const char *charset)
+{
+
+       if (!charset)
+               charset = getenv("CHARSET");
+
+#ifdef HAVE_LANGINFO_CODESET
+       if (!charset)
+               charset = nl_langinfo(CODESET);
+#endif
+
+       free(current_charset);
+       current_charset = 0;
+       if (charset && *charset)
+               current_charset = strdup(charset);
+}
+
+static int convert_buffer(const char *fromcode, const char *tocode,
+                                                 const char *from, size_t fromlen,
+                                                 char **to, size_t *tolen)
+{
+       int ret = -1;
+
+#ifdef HAVE_ICONV
+       ret = iconvert(fromcode, tocode, from, fromlen, to, tolen);
+       if (ret != -1)
+               return ret;
+#endif
+
+#ifndef HAVE_ICONV /* should be ifdef USE_CHARSET_CONVERT */
+       ret = charset_convert(fromcode, tocode, from, fromlen, to, tolen);
+       if (ret != -1)
+               return ret;
+#endif
+
+       return ret;
+}
+
+static int convert_string(const char *fromcode, const char *tocode,
+                                                 const char *from, char **to, char replace)
+{
+       int ret;
+       size_t fromlen;
+       char *s;
+
+       fromlen = strlen(from);
+       ret = convert_buffer(fromcode, tocode, from, fromlen, to, 0);
+       if (ret == -2)
+               return -1;
+       if (ret != -1)
+               return ret;
+
+       s = malloc(fromlen + 1);
+       if (!s)
+               return -1;
+       strcpy(s, from);
+       *to = s;
+       for (; *s; s++)
+               if (*s & ~0x7f)
+                       *s = replace;
+       return 3;
+}
+
+int utf8_encode(const char *from, char **to)
+{
+       char *charset;
+
+       if (!current_charset)
+               convert_set_charset(0);
+       charset = current_charset ? current_charset : "US-ASCII";
+       return convert_string(charset, "UTF-8", from, to, '#');
+}
+
+int utf8_decode(const char *from, char **to)
+{
+       char *charset;
+
+       if (*from == 0)
+       {
+               *to = malloc(1);
+               **to = 0;
+               return 1;
+       }
+
+       if (!current_charset)
+               convert_set_charset(0);
+       charset = current_charset ? current_charset : "US-ASCII";
+       return convert_string("UTF-8", charset, from, to, '?');
+}
+
+#endif
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/utf8.h b/c:/Git/PeerCast.root/PeerCast/core/common/utf8.h
new file mode 100644 (file)
index 0000000..f701319
--- /dev/null
@@ -0,0 +1,36 @@
+
+/*
+ * Convert a string between UTF-8 and the locale's charset.
+ * Invalid bytes are replaced by '#', and characters that are
+ * not available in the target encoding are replaced by '?'.
+ *
+ * If the locale's charset is not set explicitly then it is
+ * obtained using nl_langinfo(CODESET), where available, the
+ * environment variable CHARSET, or assumed to be US-ASCII.
+ *
+ * Return value of conversion functions:
+ *
+ *  -1 : memory allocation failed
+ *   0 : data was converted exactly
+ *   1 : valid data was converted approximately (using '?')
+ *   2 : input was invalid (but still converted, using '#')
+ *   3 : unknown encoding (but still converted, using '?')
+ */
+
+#ifndef __UTF8_H
+#define __UTF8_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void convert_set_charset(const char *charset);
+
+int utf8_encode(const char *from, char **to);
+int utf8_decode(const char *from, char **to);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __UTF8_H */
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/version2.h b/c:/Git/PeerCast.root/PeerCast/core/common/version2.h
new file mode 100644 (file)
index 0000000..24a45ce
--- /dev/null
@@ -0,0 +1,53 @@
+// ------------------------------------------------
+// File : version2.h
+// Date: 17-june-2005
+// Author: giles
+//
+// (c) 2005 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _VERSION2_H
+#define _VERSION2_H
+
+// ------------------------------------------------
+#ifdef PRIVATE_BROADCASTER
+static const char PCP_BROADCAST_FLAGS  = 0x01; 
+static bool    PCP_FORCE_YP                            = true;
+#else
+static const char PCP_BROADCAST_FLAGS  = 0x00;
+static bool    PCP_FORCE_YP                            = false;
+#endif
+// ------------------------------------------------
+static const int PCP_CLIENT_VERSION            = 1217;
+static const int PCP_CLIENT_VERSION_VP = 23;
+static const int PCP_ROOT_VERSION              = 1212;
+
+static const int PCP_CLIENT_MINVERSION = 1200;
+
+static const char *PCX_AGENT           = "PeerCast/0.1217";    
+static const char *PCX_AGENTJP                 = "PeerCast/0.1217-J";
+static const char *PCX_AGENTVP         = "PeerCast/0.1217(VP0023)";
+static const char *PCX_VERSTRING       = "v0.1217(VP0023)";
+
+#if 1 /* for VP extend version */
+#define VERSION_EX 1
+static const char *PCP_CLIENT_VERSION_EX_PREFIX = "IM"; // 2bytes only
+static const int  PCP_CLIENT_VERSION_EX_NUMBER = 7651;
+static const char *PCX_AGENTEX = "PeerCast/0.1217(IM7651)";
+static const char *PCX_VERSTRING_EX = "v0.1217(IM7651)";
+#endif
+
+// ------------------------------------------------
+
+
+#endif
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/xml.cpp b/c:/Git/PeerCast.root/PeerCast/core/common/xml.cpp
new file mode 100644 (file)
index 0000000..19c1035
--- /dev/null
@@ -0,0 +1,491 @@
+// ------------------------------------------------
+// File : xml.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             Basic XML parsing/creation 
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "xml.h"
+#include "stream.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ----------------------------------
+void XML::Node::add(Node *n)
+{
+       if (!n)
+               return;
+
+       n->parent = this;
+
+    if (child)
+    {
+       // has children, add to last sibling
+        Node *s = child;
+        while (s->sibling)
+               s = s->sibling;
+        s->sibling = n;
+
+    }else{
+       // no children yet
+        child = n;
+    }
+}
+// ---------------------------------
+inline char nibsToByte(char n1, char n2)
+{
+       if (n1 >= 'A') n1 = n1-'A'+10;
+       else n1 = n1-'0';
+       if (n2 >= 'A') n2 = n2-'A'+10;
+       else n2 = n2-'0';
+
+    return ((n2&0xf)<<4)|(n1&0xf);
+}
+
+// ----------------------------------
+int XML::Node::getBinaryContent(void *ptr, int size)
+{
+       char *in = contData;
+    char *out = (char *)ptr;
+
+    int i=0;
+    while (*in)
+    {
+       if (isWhiteSpace(*in))
+        {
+               in++;
+        }else
+        {
+               if (i >= size)
+               throw StreamException("Too much binary data");
+               out[i++] = nibsToByte(in[0],in[1]);
+               in+=2;
+        }
+    }
+    return i;
+}
+// ----------------------------------
+void XML::Node::setBinaryContent(void *ptr, int size)
+{
+       const char hexTable[] = "0123456789ABCDEF";
+    const int lineWidth = 1023;
+
+       contData = new char[size*2+1+(size/lineWidth)];
+
+    char *bp = (char *)ptr;
+    register char *ap = contData;
+
+    for(register int i=0; i<size; i++)
+    {
+       register char c = bp[i];
+       *ap++ = hexTable[c&0xf];
+       *ap++ = hexTable[(c>>4)&0xf];
+        if ((i&lineWidth)==lineWidth)
+               *ap++ = '\n';
+    }
+    ap[0] = 0;
+}
+
+
+// ----------------------------------
+void XML::Node::setContent(const char *n)
+{
+       contData = strdup(n);
+}
+// ----------------------------------
+void XML::Node::setAttributes(const char *n)
+{
+    char c;
+
+       attrData = strdup(n);
+
+    // count maximum amount of attributes
+    int maxAttr = 1;           // 1 for tag name
+    bool inQ = false;
+    int i=0;
+    while ((c=attrData[i++])!=0)
+    {
+       if (c=='\"')
+                       inQ ^= true;
+
+               if (!inQ)
+                       if (c=='=')
+                               maxAttr++;
+    }
+
+
+    attr = new Attribute[maxAttr];
+
+    attr[0].namePos = 0;
+    attr[0].valuePos = 0;
+
+    numAttr=1;
+
+    i=0;
+
+    // skip until whitespace
+    while (c=attrData[i++])
+       if (isWhiteSpace(c))
+               break;
+
+    if (!c) return;    // no values
+
+    attrData[i-1]=0;
+
+
+    while ((c=attrData[i])!=0)
+    {
+       if (!isWhiteSpace(c))
+        {
+                       if (numAttr>=maxAttr)
+                               throw StreamException("Too many attributes");
+
+                       // get start of tag name
+               attr[numAttr].namePos = i;
+
+
+                       // skip whitespaces until next '='
+                       // terminate name on next whitespace or '='
+            while (attrData[i])
+                       {
+                               c = attrData[i++];
+
+                               if ((c == '=') || isWhiteSpace(c))
+                               {
+                                       attrData[i-1] = 0;      // null term. name
+                                       if (c == '=')
+                               break;
+                               }
+                       }
+
+                       // skip whitespaces
+            while (attrData[i])
+                       {
+                   if (isWhiteSpace(attrData[i]))
+                                       i++;
+                               else
+                                       break;
+                       }
+
+                       // check for valid start of attribute value - '"'
+                       if (attrData[i++] != '\"')
+               throw StreamException("Bad tag value");
+
+            attr[numAttr++].valuePos = i;
+
+                       // terminate attribute value at next '"'
+
+            while (attrData[i])
+                               if (attrData[i++] == '\"')
+                       break;
+
+                       attrData[i-1] = 0;      // null term. value
+
+
+        }else{
+               i++;
+       }
+    }
+}
+// ----------------------------------
+XML::Node::Node(const char *fmt,...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+
+       char tmp[8192];
+       vsprintf(tmp,fmt,ap);
+       setAttributes(tmp);
+
+       va_end(ap);     
+       init();
+}
+
+// ----------------------------------
+void XML::Node::init()
+{
+    parent = sibling = child = NULL;
+    contData = NULL;
+    userPtr = NULL;
+}      
+// ----------------------------------
+int XML::Node::findAttrInt(const char *name)
+{
+       char *v = findAttr(name);
+    if (!v) return 0;
+    return atoi(v);
+}
+// ----------------------------------
+int XML::Node::findAttrID(const char *name)
+{
+       char *v = findAttr(name);
+    if (!v) return 0;
+    return strToID(v);
+}
+// ----------------------------------
+char *XML::Node::findAttr(const char *name)
+{
+       int nlen = strlen(name);
+       for(int i=1; i<numAttr; i++)
+    {
+       char *an = getAttrName(i);
+       if (strnicmp(an,name,nlen)==0)
+               return getAttrValue(i);
+    }
+    return NULL;
+}
+// ----------------------------------
+void XML::Node::write(Stream &out, int level)
+{
+    int i;
+#if 0
+    char tabs[64];
+
+    for(i=0; i<level; i++)
+       tabs[i] = ' ';
+    tabs[i] = '\0';
+
+
+    if (level)
+           out.write(tabs,i);
+#endif
+    char *name = getAttrValue(0);
+
+    out.write("<",1);
+    out.write(name,strlen(name));
+
+    for(i=1; i<numAttr; i++)
+    {
+           out.write(" ",1);
+       char *at = getAttrName(i);
+           out.write(at,strlen(at));
+
+           out.write("=\"",2);
+        char *av = getAttrValue(i);
+           out.write(av,strlen(av));
+           out.write("\"",1);
+    }
+
+       if ((!contData) && (!child))
+       {
+           out.write("/>\n",3);
+       }else
+       {
+           out.write(">\n",2);
+
+           if (contData)
+                   out.write(contData,strlen(contData));
+
+               if (child)
+               child->write(out,level+1);
+#if 0
+           if (level)
+                   out.write(tabs,strlen(tabs));
+#endif
+           out.write("</",2);
+           out.write(name,strlen(name));
+           out.write(">\n",2);
+       }
+
+    if (sibling)
+       sibling->write(out,level);
+}
+// ----------------------------------
+XML::Node::~Node()
+{
+//     LOG("delete %s",getName());
+
+       if (contData)
+       delete [] contData;
+    if (attrData)
+       delete [] attrData;
+    if (attr)
+       delete [] attr;
+
+    Node *n = child;
+    while (n)
+    {
+       Node *nn = n->sibling;
+       delete n;
+       n = nn;
+    }
+}
+
+
+// ----------------------------------
+XML::~XML()
+{
+       if (root)
+       delete root;
+}
+
+// ----------------------------------
+void XML::write(Stream &out)
+{
+       if (!root)
+       throw StreamException("No XML root");
+
+       out.writeLine("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
+    root->write(out,1);
+
+}
+// ----------------------------------
+void XML::writeCompact(Stream &out)
+{
+       if (!root)
+       throw StreamException("No XML root");
+
+       out.writeLine("<?xml ?>");
+    root->write(out,1);
+
+}
+// ----------------------------------
+void XML::writeHTML(Stream &out)
+{
+       if (!root)
+       throw StreamException("No XML root");
+
+    root->write(out,1);
+}
+
+// ----------------------------------
+void XML::setRoot(Node *n)
+{
+       root=n;
+}
+
+
+// ----------------------------------
+XML::Node *XML::findNode(const char *n)
+{
+       if (root)
+       return root->findNode(n);
+       else
+               return NULL;
+}
+
+
+// ----------------------------------
+XML::Node *XML::Node::findNode(const char *name)
+{
+       if (stricmp(getName(),name)==0)
+       return this;
+
+       XML::Node *c = child;
+
+       while (c)
+       {
+               XML::Node *fn = c->findNode(name);
+               if (fn)
+                       return fn;
+               c=c->sibling;
+       }
+
+       return NULL;
+}
+
+// ----------------------------------
+void XML::read(Stream &in)
+{
+       const int BUFFER_LEN = 100*1024;
+       static char buf[BUFFER_LEN];
+
+    Node *currNode=NULL;
+    int tp=0;
+
+    while (!in.eof())
+    {
+       char c = in.readChar();
+
+        if (c == '<')
+        {
+               if (tp && currNode)     // check for content
+            {
+               buf[tp] = 0;
+               currNode->setContent(buf);
+            }
+            tp = 0;
+
+               // read to next '>'
+            while (!in.eof())
+            {
+               c = in.readChar();
+                if (c == '>')
+                       break;
+
+                       if (tp >= BUFFER_LEN)
+                       throw StreamException("Tag too long");
+
+                buf[tp++] = c;
+            }
+            buf[tp]=0;
+
+            if (buf[0] == '!')                                 // comment
+            {
+               // do nothing
+            }else if (buf[0] == '?')                   // doc type
+            {
+               if (strnicmp(&buf[1],"xml ",4))
+                       throw StreamException("Not XML document");
+            }else if (buf[0] == '/')                   // end tag
+            {
+               if (!currNode)
+                       throw StreamException("Unexpected end tag");
+               currNode = currNode->parent;
+            }else      // new tag
+            {
+                   //LOG("tag: %s",buf);
+
+               bool singleTag = false;
+
+                if (buf[tp-1] == '/')                  // check for single tag
+                {
+                       singleTag = true;
+                    buf[tp-1] = 0;
+                }
+
+                               // only add valid tags
+                               if (strlen(buf))
+                               {
+                                       Node *n = new Node(buf);
+
+                                       if (currNode)
+                               currNode->add(n);
+                                       else
+                               setRoot(n);
+
+                                       if (!singleTag)
+                                               currNode = n;
+                               }
+            }
+
+            tp = 0;
+        } else {
+
+               if (tp >= BUFFER_LEN)
+               throw StreamException("Content too big");
+
+               buf[tp++] = c;
+
+        }
+    }
+}
+
diff --git a/c:/Git/PeerCast.root/PeerCast/core/common/xml.h b/c:/Git/PeerCast.root/PeerCast/core/common/xml.h
new file mode 100644 (file)
index 0000000..df157a4
--- /dev/null
@@ -0,0 +1,92 @@
+// ------------------------------------------------
+// File : xml.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _XML_H
+#define _XML_H
+
+//-----------------------
+#include "common.h"
+#include <stdarg.h>
+
+//-----------------------
+class Stream;
+
+//-----------------------
+class XML
+{
+public:
+       class Node
+    {
+    public:
+       class Attribute
+        {
+               public:
+                int namePos,valuePos;
+        };
+
+               Node(const char *,...);
+
+               void    init();
+
+        ~Node();
+        
+           void        add(Node *);
+        void   write(Stream &,int);    // output, level
+        char   *getName() {return getAttrName(0);}
+
+        char   *getAttrValue(int i) {return &attrData[attr[i].valuePos];}
+        char   *getAttrName(int i) {return &attrData[attr[i].namePos];}
+        char   *getContent()  {return contData; }
+        int            getBinaryContent(void *, int);
+
+        void   setAttributes(const char *);
+        void   setContent(const char *);
+        void   setBinaryContent(void *, int);
+
+           Node        *findNode(const char *);
+        char   *findAttr(const char *);
+        int            findAttrInt(const char *);
+        int            findAttrID(const char *);
+
+        char *contData,*attrData;
+
+        Attribute      *attr;
+        int    numAttr;
+
+       Node *child,*parent,*sibling;
+        void *userPtr;
+    };
+
+    XML()
+    {
+       root = NULL;
+    }
+
+    ~XML();
+
+    void       setRoot(Node *n);
+    void       write(Stream &);
+    void       writeCompact(Stream &);
+    void       writeHTML(Stream &);
+    void       read(Stream &);
+    Node       *findNode(const char *n);
+
+    Node *root;
+};
+#endif
diff --git a/c:/Git/PeerCast.root/PeerCast/core/win32/lib/corelib.vcproj b/c:/Git/PeerCast.root/PeerCast/core/win32/lib/corelib.vcproj
new file mode 100644 (file)
index 0000000..6f7743e
--- /dev/null
@@ -0,0 +1,1573 @@
+<?xml version="1.0" encoding="shift_jis"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="corelib"
+       ProjectGUID="{7BCFE65B-8757-45F3-8DFB-1E7D683950D1}"
+       RootNamespace="corelib"
+       SccProjectName="&quot;$/PeerCast.root/PeerCast&quot;, JCAAAAAA"
+       SccLocalPath="..\..\.."
+       SccProvider="MSSCCI:Microsoft Visual SourceSafe"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Private Release|Win32"
+                       OutputDirectory=".\corelib___Win32_Private_Release"
+                       IntermediateDirectory=".\corelib___Win32_Private_Release"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+                       UseOfMFC="0"
+                       ATLMinimizesCRunTimeLibraryUsage="false"
+                       CharacterSet="2"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="2"
+                               InlineFunctionExpansion="1"
+                               AdditionalIncludeDirectories="../../,../../common"
+                               PreprocessorDefinitions="WIN32;NDEBUG;_LIB;PRIVATE_BROADCASTER"
+                               StringPooling="true"
+                               RuntimeLibrary="0"
+                               EnableFunctionLevelLinking="true"
+                               PrecompiledHeaderFile=".\corelib___Win32_Private_Release/corelib.pch"
+                               AssemblerListingLocation=".\corelib___Win32_Private_Release/"
+                               ObjectFile=".\corelib___Win32_Private_Release/"
+                               ProgramDataBaseFileName=".\corelib___Win32_Private_Release/"
+                               WarningLevel="3"
+                               SuppressStartupBanner="true"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="NDEBUG"
+                               Culture="1033"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                               OutputFile=".\corelib___Win32_Private_Release\corelib.lib"
+                               SuppressStartupBanner="true"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                               SuppressStartupBanner="true"
+                               OutputFile=".\corelib___Win32_Private_Release/corelib.bsc"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Debug|Win32"
+                       OutputDirectory=".\Debug"
+                       IntermediateDirectory=".\Debug"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+                       UseOfMFC="0"
+                       ATLMinimizesCRunTimeLibraryUsage="false"
+                       CharacterSet="2"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="0"
+                               AdditionalIncludeDirectories="../../,../../common,../../../ui/win32/simple"
+                               PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
+                               MinimalRebuild="true"
+                               BasicRuntimeChecks="3"
+                               RuntimeLibrary="1"
+                               PrecompiledHeaderFile=".\Debug/corelib.pch"
+                               AssemblerListingLocation=".\Debug/"
+                               ObjectFile=".\Debug/"
+                               ProgramDataBaseFileName=".\Debug/"
+                               WarningLevel="3"
+                               SuppressStartupBanner="true"
+                               DebugInformationFormat="4"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="_DEBUG"
+                               Culture="1033"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                               OutputFile=".\Debug\corelib.lib"
+                               SuppressStartupBanner="true"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                               SuppressStartupBanner="true"
+                               OutputFile=".\Debug/corelib.bsc"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       OutputDirectory=".\Release"
+                       IntermediateDirectory=".\Release"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+                       UseOfMFC="0"
+                       ATLMinimizesCRunTimeLibraryUsage="false"
+                       CharacterSet="2"
+                       WholeProgramOptimization="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="2"
+                               InlineFunctionExpansion="1"
+                               EnableIntrinsicFunctions="true"
+                               AdditionalIncludeDirectories="../../,../../common"
+                               PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+                               StringPooling="true"
+                               RuntimeLibrary="0"
+                               EnableFunctionLevelLinking="true"
+                               PrecompiledHeaderFile=".\Release/corelib.pch"
+                               AssemblerListingLocation=".\Release/"
+                               ObjectFile=".\Release/"
+                               ProgramDataBaseFileName=".\Release/"
+                               WarningLevel="3"
+                               SuppressStartupBanner="true"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="NDEBUG"
+                               Culture="1033"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                               OutputFile=".\Release\corelib.lib"
+                               SuppressStartupBanner="true"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                               SuppressStartupBanner="true"
+                               OutputFile=".\Release/corelib.bsc"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Private Debug|Win32"
+                       OutputDirectory=".\corelib___Win32_Private_Debug"
+                       IntermediateDirectory=".\corelib___Win32_Private_Debug"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+                       UseOfMFC="0"
+                       ATLMinimizesCRunTimeLibraryUsage="false"
+                       CharacterSet="2"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="0"
+                               AdditionalIncludeDirectories="../../,../../common"
+                               PreprocessorDefinitions="WIN32;_DEBUG;_LIB;PRIVATE_BROADCASTER"
+                               MinimalRebuild="true"
+                               BasicRuntimeChecks="3"
+                               RuntimeLibrary="1"
+                               PrecompiledHeaderFile=".\corelib___Win32_Private_Debug/corelib.pch"
+                               AssemblerListingLocation=".\corelib___Win32_Private_Debug/"
+                               ObjectFile=".\corelib___Win32_Private_Debug/"
+                               ProgramDataBaseFileName=".\corelib___Win32_Private_Debug/"
+                               WarningLevel="3"
+                               SuppressStartupBanner="true"
+                               DebugInformationFormat="4"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="_DEBUG"
+                               Culture="1033"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                               OutputFile=".\corelib___Win32_Private_Debug\corelib.lib"
+                               SuppressStartupBanner="true"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                               SuppressStartupBanner="true"
+                               OutputFile=".\corelib___Win32_Private_Debug/corelib.bsc"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="Core Source"
+                       >
+                       <File
+                               RelativePath="..\..\common\channel.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\gnutella.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\html.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\http.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\icy.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\inifile.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\jis.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\mms.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\mp3.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\nsv.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\ogg.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\pcp.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\peercast.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\rtsp.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\servent.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\servhs.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\servmgr.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\socket.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\stats.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\stream.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\sys.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\url.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\common\xml.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+               </Filter>
+               <Filter
+                       Name="Core Includes"
+                       >
+                       <File
+                               RelativePath="..\..\common\asf.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\atom.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\channel.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\common.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\cstream.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\gnutella.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\html-xml.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\html.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\http.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\icy.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\id.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\inifile.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\jis.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\mms.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\mp3.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\nsv.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\ogg.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\pcp.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\peercast.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\rtsp.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\servent.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\servmgr.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\socket.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\stats.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\stream.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\sys.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\url.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\version2.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\common\xml.h"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="Win32 Source"
+                       >
+                       <File
+                               RelativePath="..\wsocket.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\wsys.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+               </Filter>
+               <Filter
+                       Name="Win32 Includes"
+                       >
+                       <File
+                               RelativePath="..\wsocket.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\wsys.h"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="Unix Source"
+                       >
+                       <File
+                               RelativePath="..\..\unix\usocket.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\unix\usys.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+               </Filter>
+               <Filter
+                       Name="Unix Includes"
+                       >
+                       <File
+                               RelativePath="..\..\unix\usocket.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\unix\usys.h"
+                               >
+                       </File>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/c:/Git/PeerCast.root/PeerCast/core/win32/lib/corelib.vcproj.vspscc b/c:/Git/PeerCast.root/PeerCast/core/win32/lib/corelib.vcproj.vspscc
new file mode 100644 (file)
index 0000000..16d4a14
--- /dev/null
@@ -0,0 +1,10 @@
+""
+{
+"FILE_VERSION" = "9237"
+"ENLISTMENT_CHOICE" = "NEVER"
+"PROJECT_FILE_RELATIVE_PATH" = "relative:core\\win32\\lib"
+"NUMBER_OF_EXCLUDED_FILES" = "0"
+"ORIGINAL_PROJECT_FILE_PATH" = ""
+"NUMBER_OF_NESTED_PROJECTS" = "0"
+"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
+}
diff --git a/c:/Git/PeerCast.root/PeerCast/core/win32/wsocket.cpp b/c:/Git/PeerCast.root/PeerCast/core/win32/wsocket.cpp
new file mode 100644 (file)
index 0000000..5b03e4c
--- /dev/null
@@ -0,0 +1,675 @@
+// ------------------------------------------------
+// File : wsocket.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             Windows version of ClientSocket. Handles the nitty gritty of actually
+//             reading and writing TCP
+//             
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+// TODO: fix socket closing
+
+
+//#include "stdafx.h"
+//#include "winsock2.h"
+#include <windows.h>
+#include <stdio.h>
+#include "wsocket.h"
+#include "stats.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+// --------------------------------------------------
+void WSAClientSocket::init()
+{
+       WORD wVersionRequested;
+       WSADATA wsaData;
+       int err;
+    
+       wVersionRequested = MAKEWORD( 2, 0 );
+       err = WSAStartup( wVersionRequested, &wsaData );
+       if ( err != 0 )
+               throw SockException("Unable to init sockets");
+
+    //LOG4("WSAStartup:  OK");
+
+}
+// --------------------------------------------------
+bool ClientSocket::getHostname(char *str,unsigned int ip)
+{
+       HOSTENT *he;
+
+       ip = htonl(ip);
+
+       he = gethostbyaddr((char *)&ip,sizeof(ip),AF_INET);
+
+       if (he)
+       {
+               strcpy(str,he->h_name);
+               return true;
+       }else
+               return false;
+}
+
+unsigned int cache_ip = 0;
+unsigned int cache_time = 0;
+
+// --------------------------------------------------
+unsigned int ClientSocket::getIP(char *name)
+{
+       unsigned int ctime = sys->getTime();
+       bool null_flg = (name == NULL);
+
+       if (null_flg){
+               if ((cache_time != 0) && (cache_time + 60 > ctime)){
+                       return cache_ip;
+               } else {
+                       cache_time = 0;
+                       cache_ip = 0;
+               }
+       }
+
+       char szHostName[256];
+
+       if (!name)
+       {
+               if (gethostname(szHostName, sizeof(szHostName))==0)
+                       name = szHostName;
+               else
+                       return 0;
+       }
+
+       HOSTENT *he = WSAClientSocket::resolveHost(name);
+
+       if (!he)
+               return 0;
+
+
+       LPSTR lpAddr = he->h_addr_list[0];
+       if (lpAddr)
+       {
+               unsigned int ret;
+               struct in_addr  inAddr;
+               memmove (&inAddr, lpAddr, 4);
+
+               ret =  inAddr.S_un.S_un_b.s_b1<<24 |
+                          inAddr.S_un.S_un_b.s_b2<<16 |
+                          inAddr.S_un.S_un_b.s_b3<<8 |
+                          inAddr.S_un.S_un_b.s_b4;
+
+               if (null_flg){
+                       cache_ip = ret;
+                       cache_time = ctime;
+               }
+               return ret;
+       }
+       return 0;
+}
+// --------------------------------------------------
+void WSAClientSocket::setLinger(int sec)
+{
+       linger linger;
+       linger.l_onoff = (sec>0)?1:0;
+    linger.l_linger = sec;
+
+       if (setsockopt(sockNum, SOL_SOCKET, SO_LINGER, (const char *)&linger, sizeof (linger)) == -1) 
+               throw SockException("Unable to set LINGER");
+}
+
+// --------------------------------------------------
+void WSAClientSocket::setBlocking(bool yes)
+{
+       unsigned long op = yes ? 0 : 1;
+       if (ioctlsocket(sockNum, FIONBIO, &op) == SOCKET_ERROR)
+               throw SockException("Can`t set blocking");
+}
+// --------------------------------------------------
+void WSAClientSocket::setNagle(bool on)
+{
+    int nodelay = (on==false);
+       if (setsockopt(sockNum, SOL_SOCKET, TCP_NODELAY, (char *)&nodelay, sizeof nodelay) == -1) 
+               throw SockException("Unable to set NODELAY");
+
+}
+
+// --------------------------------------------------
+void WSAClientSocket::setReuse(bool yes)
+{
+       unsigned long op = yes ? 1 : 0;
+       if (setsockopt(sockNum,SOL_SOCKET,SO_REUSEADDR,(char *)&op,sizeof(unsigned long)) == -1) 
+               throw SockException("Unable to set REUSE");
+}
+
+// --------------------------------------------------
+void WSAClientSocket::setBufSize(int size)
+{
+       int oldop;
+       int op = size;
+       int len = sizeof(op);
+       if (getsockopt(sockNum,SOL_SOCKET,SO_RCVBUF,(char *)&oldop,&len) == -1) {
+               LOG_DEBUG("Unable to get RCVBUF");
+       } else if (oldop < size) {
+               if (setsockopt(sockNum,SOL_SOCKET,SO_RCVBUF,(char *)&op,len) == -1) 
+                       LOG_DEBUG("Unable to set RCVBUF");
+               //else
+               //      LOG_DEBUG("*** recvbufsize:%d -> %d", oldop, op);
+       }
+
+       if (getsockopt(sockNum,SOL_SOCKET,SO_SNDBUF,(char *)&oldop,&len) == -1) {
+               LOG_DEBUG("Unable to get SNDBUF");
+       } else if (oldop < size) {
+               if (setsockopt(sockNum,SOL_SOCKET,SO_SNDBUF,(char *)&op,len) == -1) 
+                       LOG_DEBUG("Unable to set SNDBUF");
+               //else
+               //      LOG_DEBUG("*** sendbufsize: %d -> %d", oldop, op);
+       }
+}
+
+// --------------------------------------------------
+HOSTENT *WSAClientSocket::resolveHost(const char *hostName)
+{
+       HOSTENT *he;
+
+       if ((he = gethostbyname(hostName)) == NULL)
+       {
+               // if failed, try using gethostbyaddr instead
+
+               unsigned long ip = inet_addr(hostName);
+               
+               if (ip == INADDR_NONE)
+                       return NULL;
+
+               if ((he = gethostbyaddr((char *)&ip,sizeof(ip),AF_INET)) == NULL)
+                       return NULL;    
+       }
+       return he;
+}
+
+// --------------------------------------------------
+void WSAClientSocket::open(Host &rh)
+{
+       sockNum = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+       if (sockNum == INVALID_SOCKET)
+               throw SockException("Can`t open socket");
+
+       setBlocking(false);
+#ifdef DISABLE_NAGLE
+       setNagle(false);
+#endif
+       setBufSize(65535);
+
+       host = rh;
+
+       memset(&remoteAddr,0,sizeof(remoteAddr));
+
+       remoteAddr.sin_family = AF_INET;
+       remoteAddr.sin_port = htons(host.port);
+       remoteAddr.sin_addr.S_un.S_addr = htonl(host.ip);
+
+}
+// --------------------------------------------------
+void WSAClientSocket::checkTimeout(bool r, bool w)
+{
+    int err = WSAGetLastError();
+    if (err == WSAEWOULDBLOCK)
+    {
+
+               timeval timeout;
+               fd_set read_fds;
+               fd_set write_fds;
+
+               timeout.tv_sec = 0;
+               timeout.tv_usec = 0;
+
+        FD_ZERO (&write_fds);
+               if (w)
+               {
+                       timeout.tv_sec = (int)this->writeTimeout/1000;
+                       FD_SET (sockNum, &write_fds);
+               }
+
+        FD_ZERO (&read_fds);
+               if (r)
+               {
+                       timeout.tv_sec = (int)this->readTimeout/1000;
+               FD_SET (sockNum, &read_fds);
+               }
+
+               timeval *tp;
+               if (timeout.tv_sec)
+                       tp = &timeout;
+               else
+                       tp = NULL;
+
+
+               int r=select (NULL, &read_fds, &write_fds, NULL, tp);
+
+        if (r == 0)
+                       throw TimeoutException();
+               else if (r == SOCKET_ERROR)
+                       throw SockException("select failed.");
+
+       }else{
+               char str[32];
+               sprintf(str,"%d",err);
+               throw SockException(str);
+       }
+}
+
+// --------------------------------------------------
+void WSAClientSocket::checkTimeout2(bool r, bool w)
+{
+    {
+
+               timeval timeout;
+               fd_set read_fds;
+               fd_set write_fds;
+
+               timeout.tv_sec = 0;
+               timeout.tv_usec = 0;
+
+        FD_ZERO (&write_fds);
+               if (w)
+               {
+                       timeout.tv_sec = (int)this->writeTimeout/1000;
+                       FD_SET (sockNum, &write_fds);
+               }
+
+        FD_ZERO (&read_fds);
+               if (r)
+               {
+                       timeout.tv_sec = (int)this->readTimeout/1000;
+               FD_SET (sockNum, &read_fds);
+               }
+
+               timeval *tp;
+               if (timeout.tv_sec)
+                       tp = &timeout;
+               else
+                       tp = NULL;
+
+
+               int r=select (NULL, &read_fds, &write_fds, NULL, tp);
+
+        if (r == 0)
+                       throw TimeoutException();
+               else if (r == SOCKET_ERROR)
+                       throw SockException("select failed.");
+       }
+}
+
+// --------------------------------------------------
+Host WSAClientSocket::getLocalHost()
+{
+       struct sockaddr_in localAddr;
+
+       int len = sizeof(localAddr);
+    if (getsockname(sockNum, (sockaddr *)&localAddr, &len) == 0)
+               return Host(SWAP4(localAddr.sin_addr.s_addr),0);
+       else
+               return Host(0,0);
+}
+
+// --------------------------------------------------
+void WSAClientSocket::connect()
+{
+       if (::connect(sockNum,(struct sockaddr *)&remoteAddr,sizeof(remoteAddr)) == SOCKET_ERROR)
+               checkTimeout(false,true);
+
+}
+// --------------------------------------------------
+int WSAClientSocket::read(void *p, int l)
+{
+       int bytesRead=0;
+
+       while (l)
+       {
+               if (rbDataSize >= l) {
+                       memcpy(p, &apReadBuf[rbPos], l);
+                       rbPos += l;
+                       rbDataSize -= l;
+                       return l;
+               } else if (rbDataSize > 0) {
+                       memcpy(p, &apReadBuf[rbPos], rbDataSize);
+                       p = (char *) p + rbDataSize;
+                       l -= rbDataSize;
+                       bytesRead += rbDataSize;
+               }
+
+               rbPos = 0;
+               rbDataSize = 0;
+               //int r = recv(sockNum, (char *)p, l, 0);
+               int r = recv(sockNum, apReadBuf, RBSIZE, 0);
+               if (r == SOCKET_ERROR)
+               {
+                       // non-blocking sockets always fall through to here
+                       checkTimeout(true,false);
+
+               }else if (r == 0)
+               {
+                       throw EOFException("Closed on read");
+
+               }else
+               {
+                       stats.add(Stats::BYTESIN,r);
+                       if (host.localIP())
+                               stats.add(Stats::LOCALBYTESIN,r);
+                       updateTotals(r,0);
+                       //bytesRead += r;
+                       //l -= r;
+                       //p = (char *)p+r;
+
+                       rbDataSize += r;
+               }
+       }
+       return bytesRead;
+}
+// --------------------------------------------------
+int WSAClientSocket::readUpto(void *p, int l)
+{
+       int bytesRead=0;
+       while (l)
+       {
+               int r = recv(sockNum, (char *)p, l, 0);
+               if (r == SOCKET_ERROR)
+               {
+                       // non-blocking sockets always fall through to here
+                       //checkTimeout(true,false);
+                       return r;
+
+               }else if (r == 0)
+               {
+                       break;
+               }else
+               {
+                       stats.add(Stats::BYTESIN,r);
+                       if (host.localIP())
+                               stats.add(Stats::LOCALBYTESIN,r);
+                       updateTotals(r,0);
+                       bytesRead += r;
+                       l -= r;
+                       p = (char *)p+r;
+               }
+               if (bytesRead) break;
+       }
+       return bytesRead;
+}
+
+
+// --------------------------------------------------
+void WSAClientSocket::write(const void *p, int l)
+{
+       while (l)
+       {
+               int r = send(sockNum, (char *)p, l, 0);
+               if (r == SOCKET_ERROR)
+               {
+                       checkTimeout(false,true);       
+               }
+               else if (r == 0)
+               {
+                       throw SockException("Closed on write");
+               }
+               else
+               if (r > 0)
+               {
+                       stats.add(Stats::BYTESOUT,r);
+                       if (host.localIP())
+                               stats.add(Stats::LOCALBYTESOUT,r);
+
+                       updateTotals(0,r);
+                       l -= r;
+                       p = (char *)p+r;
+               }
+       }
+}
+
+// --------------------------------------------------
+void WSAClientSocket::bufferingWrite(const void *p, int l)
+{
+       if (bufList.isNull() && p != NULL){
+               while(l){
+                       int r = send(sockNum, (char *)p, l, 0);
+                       if (r == SOCKET_ERROR){
+                               int err = WSAGetLastError();
+                               if (err == WSAEWOULDBLOCK){
+                                       bufList.add(p, l);
+//                                     LOG_DEBUG("normal add");
+                                       break;
+                               } else {
+                                       char str[32];
+                                       sprintf(str,"%d",err);
+                                       throw SockException(str);
+                               }
+                       } else if (r == 0) {
+                               throw SockException("Closed on write");
+                       } else if (r > 0){
+                               stats.add(Stats::BYTESOUT,r);
+                               if (host.localIP())
+                                       stats.add(Stats::LOCALBYTESOUT,r);
+
+                               updateTotals(0,r);
+                               l -= r;
+                               p = (char *)p+r;
+                       }
+               }
+       } else {
+//             LOG_DEBUG("***************BufferingWrite");
+               if (p)
+                       bufList.add(p,l);
+
+               bool flg = true;
+
+               while(flg){
+                       SocketBuffer *tmp;
+                       tmp = bufList.getTop();
+
+                       if (tmp){
+//                             LOG_DEBUG("tmp->pos = %d, tmp->len = %d, %d", tmp->pos, tmp->len, tmp);
+                               while(tmp->pos < tmp->len){
+                                       int r = send(sockNum, (char*)(tmp->buf + tmp->pos), tmp->len - tmp->pos, 0);
+//                                     LOG_DEBUG("send = %d", r);
+                                       if (r == SOCKET_ERROR){
+                                               int err = WSAGetLastError();
+                                               if (err == WSAEWOULDBLOCK){
+                                                       flg = false;
+                                                       break;
+                                               } else {
+                                                       bufList.clear();
+                                                       char str[32];
+                                                       sprintf(str,"%d",err);
+                                                       throw SockException(str);
+                                               }
+                                       } else if (r == 0){
+                                               bufList.clear();
+                                               throw SockException("Closed on write");
+                                       } else if (r > 0){
+                                               stats.add(Stats::BYTESOUT,r);
+                                               if (host.localIP())
+                                                       stats.add(Stats::LOCALBYTESOUT,r);
+
+                                               updateTotals(0,r);
+
+                                               tmp->pos += r;
+                                               if (tmp->pos >= tmp->len){
+//                                                     LOG_DEBUG("deleteTop");
+                                                       bufList.deleteTop();
+                                                       break;
+                                               }
+                                       }
+                               }
+                       } else {
+                               flg = false;
+                       }
+               }
+//             LOG_DEBUG("bufferingWrite end");
+       }
+}
+
+// --------------------------------------------------
+void WSAClientSocket::checkBuffering(bool r, bool w)
+{
+    int err = WSAGetLastError();
+    if (err == WSAEWOULDBLOCK)
+    {
+
+               timeval timeout;
+               fd_set read_fds;
+               fd_set write_fds;
+
+               timeout.tv_sec = 0;
+               timeout.tv_usec = 0;
+
+        FD_ZERO (&write_fds);
+               if (w)
+               {
+                       timeout.tv_sec = (int)this->writeTimeout/1000;
+                       FD_SET (sockNum, &write_fds);
+               }
+
+        FD_ZERO (&read_fds);
+               if (r)
+               {
+                       timeout.tv_sec = (int)this->readTimeout/1000;
+               FD_SET (sockNum, &read_fds);
+               }
+
+               timeval *tp;
+               if (timeout.tv_sec)
+                       tp = &timeout;
+               else
+                       tp = NULL;
+
+
+               int r=select (NULL, &read_fds, &write_fds, NULL, tp);
+
+        if (r == 0)
+                       throw TimeoutException();
+               else if (r == SOCKET_ERROR)
+                       throw SockException("select failed.");
+
+       }else{
+               char str[32];
+               sprintf(str,"%d",err);
+               throw SockException(str);
+       }
+}
+
+// --------------------------------------------------
+void WSAClientSocket::bind(Host &h)
+{
+       struct sockaddr_in localAddr;
+
+       if ((sockNum = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
+               throw SockException("Can`t open socket");
+
+       setBlocking(false);
+       setReuse(true);
+
+       memset(&localAddr,0,sizeof(localAddr));
+       localAddr.sin_family = AF_INET;
+       localAddr.sin_port = htons(h.port);
+       localAddr.sin_addr.s_addr = INADDR_ANY;
+
+       if( ::bind (sockNum, (sockaddr *)&localAddr, sizeof(localAddr)) == -1)
+               throw SockException("Can`t bind socket");
+
+       if (::listen(sockNum,SOMAXCONN))
+               throw SockException("Can`t listen",WSAGetLastError());
+
+       host = h;
+}
+// --------------------------------------------------
+ClientSocket *WSAClientSocket::accept()
+{
+
+       int fromSize = sizeof(sockaddr_in);
+       sockaddr_in from;
+
+       int conSock = ::accept(sockNum,(sockaddr *)&from,&fromSize);
+
+
+       if (conSock ==  INVALID_SOCKET)
+               return NULL;
+
+       
+    WSAClientSocket *cs = new WSAClientSocket();
+       cs->sockNum = conSock;
+
+       cs->host.port = from.sin_port;
+       cs->host.ip = from.sin_addr.S_un.S_un_b.s_b1<<24 |
+                                 from.sin_addr.S_un.S_un_b.s_b2<<16 |
+                                 from.sin_addr.S_un.S_un_b.s_b3<<8 |
+                                 from.sin_addr.S_un.S_un_b.s_b4;
+
+
+       cs->setBlocking(false);
+#ifdef DISABLE_NAGLE
+       cs->setNagle(false);
+#endif
+       cs->setBufSize(65535);
+
+       return cs;
+}
+
+// --------------------------------------------------
+void WSAClientSocket::close()
+{
+       sockLock.on();
+       if (sockNum)
+       {
+//             shutdown(sockNum,SD_SEND);
+
+               setReadTimeout(2000);
+               unsigned int stime = sys->getTime();
+               try
+               {
+                       char c[1024];
+                       while (readUpto(&c,1024) > 0)
+                               if (sys->getTime() - stime > 5) break;
+                       //readUpto(&c,1);
+               }catch(StreamException &) {}
+
+               if (closesocket (sockNum))
+                       LOG_ERROR("closesocket() error");
+
+
+               sockNum=0;
+       }
+       sockLock.off();
+}
+
+// --------------------------------------------------
+bool   WSAClientSocket::readReady()
+{
+       if (rbDataSize) return true;
+
+       timeval timeout;
+       fd_set read_fds;
+
+       timeout.tv_sec = 0;
+       timeout.tv_usec = 0;
+
+    FD_ZERO (&read_fds);
+    FD_SET (sockNum, &read_fds);
+
+       return select (sockNum+1, &read_fds, NULL, NULL, &timeout) == 1;
+}
+
diff --git a/c:/Git/PeerCast.root/PeerCast/core/win32/wsocket.h b/c:/Git/PeerCast.root/PeerCast/core/win32/wsocket.h
new file mode 100644 (file)
index 0000000..fdf4055
--- /dev/null
@@ -0,0 +1,86 @@
+// ------------------------------------------------
+// File : wsocket.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             see .cpp for details
+//             
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _WSOCKET_H
+#define _WSOCKET_H
+
+#include <windows.h>
+#include "socket.h"
+//#include "winsock2.h"
+
+
+// --------------------------------------------------
+class WSAClientSocket : public ClientSocket
+{
+public:
+       static void     init();
+
+    WSAClientSocket()
+       :sockNum(0)
+       ,writeCnt(0)
+       ,rbPos(0)
+       ,rbDataSize(0)
+    {
+    }
+
+       ~WSAClientSocket(){
+               bufList.clear();
+       }
+
+       virtual void    open(Host &);
+       virtual int             read(void *, int);
+       virtual int             readUpto(void *, int);
+       virtual void    write(const void *, int);
+       virtual void    bind(Host &);
+       virtual void    connect();
+       virtual void    close();
+       virtual ClientSocket * accept();
+       virtual bool    active() {return sockNum != 0;}
+       virtual bool    readReady();
+       virtual Host    getLocalHost();
+       virtual void    setBlocking(bool);
+       void    setReuse(bool);
+       void    setNagle(bool);
+       void    setLinger(int);
+       void    setBufSize(int size);
+
+//     static  HOSTENT         *resolveHost(const char *);
+       static  hostent         *resolveHost(const char *);
+
+       void    checkTimeout(bool,bool);
+       void    checkTimeout2(bool,bool);
+
+       virtual void    bufferingWrite(const void*, int);
+       void    checkBuffering(bool, bool);
+
+       unsigned int writeCnt;
+       unsigned int sockNum;
+       struct sockaddr_in remoteAddr;
+
+       enum {RBSIZE = 8192};
+       char apReadBuf[RBSIZE];
+       int rbPos;
+       int rbDataSize;
+
+       WLock sockLock;
+};
+
+#endif
\ No newline at end of file
diff --git a/c:/Git/PeerCast.root/PeerCast/core/win32/wsys.cpp b/c:/Git/PeerCast.root/PeerCast/core/win32/wsys.cpp
new file mode 100644 (file)
index 0000000..9ed1fcf
--- /dev/null
@@ -0,0 +1,150 @@
+// ------------------------------------------------
+// File : wsys.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             WSys derives from Sys to provide basic win32 functions such as starting threads.
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+//#include "stdafx.h"
+#include <process.h>
+#include <windows.h>
+#include <time.h>
+#include "win32/wsys.h"
+#include "win32/wsocket.h"
+#include "stats.h"
+#include "peercast.h"
+#include <sys/timeb.h>
+#include <time.h>
+#include "shellapi.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ---------------------------------
+WSys::WSys(HWND w)
+{
+       stats.clear();
+       
+       rndGen.setSeed(getTime());
+       
+       mainWindow = w;
+       WSAClientSocket::init();
+
+       rndSeed = rnd();
+}
+// ---------------------------------
+double WSys::getDTime()
+{
+   struct _timeb timebuffer;
+
+   _ftime( &timebuffer );
+
+   return (double)timebuffer.time+(((double)timebuffer.millitm)/1000);
+}
+// ---------------------------------
+unsigned int WSys::getTime()
+{
+       time_t ltime;
+       time( &ltime );
+       return ltime;
+}
+
+// ---------------------------------
+ClientSocket *WSys::createSocket()
+{
+    return new WSAClientSocket();
+}
+// ---------------------------------
+void WSys::endThread(ThreadInfo *info)
+{
+}             
+// ---------------------------------
+void WSys::waitThread(ThreadInfo *info, int timeout)
+{
+       switch(WaitForSingleObject((void *)info->handle, timeout))
+       {
+      case WAIT_TIMEOUT:
+          throw TimeoutException();
+          break;
+       }
+}
+  
+
+// ---------------------------------
+bool   WSys::startThread(ThreadInfo *info)
+{
+       info->active = true;
+
+/*     typedef unsigned ( __stdcall *start_address )( void * );
+
+       unsigned int threadID;
+       info->handle = (unsigned int)_beginthreadex( NULL, 0, (start_address)info->func, info, 0, &threadID );
+
+    if(info->handle == 0) 
+               return false;*/
+
+       typedef void (__cdecl *start_address)( void * );
+       info->handle = _beginthread((start_address)info->func, 0,info);
+
+    if(info->handle == -1) 
+               return false;
+
+  return true;
+
+}
+// ---------------------------------
+void   WSys::sleep(int ms)
+{
+       Sleep(ms);
+}
+
+// ---------------------------------
+void WSys::appMsg(long msg, long arg)
+{
+       //SendMessage(mainWindow,WM_USER,(WPARAM)msg,(LPARAM)arg);
+}
+
+// --------------------------------------------------
+void WSys::callLocalURL(const char *str,int port)
+{
+       char cmd[512];
+       sprintf(cmd,"http://localhost:%d/%s",port,str);
+       ShellExecute(mainWindow, NULL, cmd, NULL, NULL, SW_SHOWNORMAL);
+}
+
+// ---------------------------------
+void WSys::getURL(const char *url)
+{
+       if (mainWindow)
+               if (strnicmp(url,"http://",7) || strnicmp(url,"mailto:",7))
+                       ShellExecute(mainWindow, NULL, url, NULL, NULL, SW_SHOWNORMAL);
+}
+// ---------------------------------
+void WSys::exit()
+{
+       if (mainWindow)
+               PostMessage(mainWindow,WM_CLOSE,0,0);
+       else
+               ::exit(0);
+}
+// --------------------------------------------------
+void WSys::executeFile(const char *file)
+{
+    ShellExecute(NULL,"open",file,NULL,NULL,SW_SHOWNORMAL);  
+}
diff --git a/c:/Git/PeerCast.root/PeerCast/core/win32/wsys.h b/c:/Git/PeerCast.root/PeerCast/core/win32/wsys.h
new file mode 100644 (file)
index 0000000..95f479a
--- /dev/null
@@ -0,0 +1,61 @@
+// ------------------------------------------------
+// File : wsys.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             WSys derives from Sys to provide basic win32 functions such as starting threads.
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+
+#ifndef _WSYS_H
+#define _WSYS_H
+// ------------------------------------
+#include <windows.h>
+#include "socket.h"
+#include "sys.h"
+
+// ------------------------------------
+class WSys : public Sys
+{
+public:
+       WSys(HWND);
+
+       virtual ClientSocket    *createSocket();
+       virtual bool                    startThread(ThreadInfo *);
+       virtual void                    sleep(int );
+       virtual void                    appMsg(long,long);
+       virtual unsigned int    getTime();
+       virtual double                  getDTime();             
+       virtual unsigned int    rnd() {return rndGen.next();}
+       virtual void                    getURL(const char *);
+       virtual void                    exit();
+       virtual bool                    hasGUI() {return mainWindow!=NULL;}
+       virtual void                    callLocalURL(const char *str,int port);
+       virtual void                    executeFile(const char *);
+       virtual void                    endThread(ThreadInfo *);
+       virtual void                    waitThread(ThreadInfo *, int timeout = 30000);
+
+
+       HWND    mainWindow;
+       peercast::Random rndGen;
+};                               
+
+
+// ------------------------------------
+#endif
+
+
\ No newline at end of file
diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/PeerCast.sln b/c:/Git/PeerCast.root/PeerCast/ui/win32/PeerCast.sln
new file mode 100644 (file)
index 0000000..9768be1
--- /dev/null
@@ -0,0 +1,49 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "corelib", "..\..\core\win32\lib\corelib.vcproj", "{7BCFE65B-8757-45F3-8DFB-1E7D683950D1}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Simple", "simple\Simple.vcproj", "{7D4833CE-1286-4587-9470-52E098B29C12}"
+EndProject
+Global
+       GlobalSection(SourceCodeControl) = preSolution
+               SccNumberOfProjects = 3
+               SccProjectName0 = \u0022$/PeerCast.root/PeerCast\u0022,\u0020JCAAAAAA
+               SccLocalPath0 = ..\\..
+               SccProvider0 = MSSCCI:Microsoft\u0020Visual\u0020SourceSafe
+               SccProjectFilePathRelativizedFromConnection0 = ui\\win32\\
+               SccProjectUniqueName1 = ..\\..\\core\\win32\\lib\\corelib.vcproj
+               SccLocalPath1 = ..\\..
+               SccProjectFilePathRelativizedFromConnection1 = core\\win32\\lib\\
+               SccProjectUniqueName2 = simple\\Simple.vcproj
+               SccLocalPath2 = ..\\..
+               SccProjectFilePathRelativizedFromConnection2 = ui\\win32\\simple\\
+       EndGlobalSection
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution
+               Debug|Win32 = Debug|Win32
+               Private Debug|Win32 = Private Debug|Win32
+               Private Release|Win32 = Private Release|Win32
+               Release|Win32 = Release|Win32
+       EndGlobalSection
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution
+               {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Debug|Win32.ActiveCfg = Debug|Win32
+               {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Debug|Win32.Build.0 = Debug|Win32
+               {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Private Debug|Win32.ActiveCfg = Private Debug|Win32
+               {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Private Debug|Win32.Build.0 = Private Debug|Win32
+               {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Private Release|Win32.ActiveCfg = Private Release|Win32
+               {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Private Release|Win32.Build.0 = Private Release|Win32
+               {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Release|Win32.ActiveCfg = Release|Win32
+               {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Release|Win32.Build.0 = Release|Win32
+               {7D4833CE-1286-4587-9470-52E098B29C12}.Debug|Win32.ActiveCfg = Debug|Win32
+               {7D4833CE-1286-4587-9470-52E098B29C12}.Debug|Win32.Build.0 = Debug|Win32
+               {7D4833CE-1286-4587-9470-52E098B29C12}.Private Debug|Win32.ActiveCfg = Private Debug|Win32
+               {7D4833CE-1286-4587-9470-52E098B29C12}.Private Debug|Win32.Build.0 = Private Debug|Win32
+               {7D4833CE-1286-4587-9470-52E098B29C12}.Private Release|Win32.ActiveCfg = Private Release|Win32
+               {7D4833CE-1286-4587-9470-52E098B29C12}.Private Release|Win32.Build.0 = Private Release|Win32
+               {7D4833CE-1286-4587-9470-52E098B29C12}.Release|Win32.ActiveCfg = Release|Win32
+               {7D4833CE-1286-4587-9470-52E098B29C12}.Release|Win32.Build.0 = Release|Win32
+       EndGlobalSection
+       GlobalSection(SolutionProperties) = preSolution
+               HideSolutionNode = FALSE
+       EndGlobalSection
+EndGlobal
diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/PeerCast.vsscc b/c:/Git/PeerCast.root/PeerCast/ui/win32/PeerCast.vsscc
new file mode 100644 (file)
index 0000000..51e2532
Binary files /dev/null and b/c:/Git/PeerCast.root/PeerCast/ui/win32/PeerCast.vsscc differ
diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/PeerCast.vssscc b/c:/Git/PeerCast.root/PeerCast/ui/win32/PeerCast.vssscc
new file mode 100644 (file)
index 0000000..e957f02
--- /dev/null
@@ -0,0 +1,10 @@
+""
+{
+"FILE_VERSION" = "9237"
+"ENLISTMENT_CHOICE" = "NEVER"
+"PROJECT_FILE_RELATIVE_PATH" = "relative:ui\\win32"
+"NUMBER_OF_EXCLUDED_FILES" = "0"
+"ORIGINAL_PROJECT_FILE_PATH" = ""
+"NUMBER_OF_NESTED_PROJECTS" = "0"
+"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
+}
diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/SMALL.ICO b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/SMALL.ICO
new file mode 100644 (file)
index 0000000..c7dee29
Binary files /dev/null and b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/SMALL.ICO differ
diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.ICO b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.ICO
new file mode 100644 (file)
index 0000000..51811ea
Binary files /dev/null and b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.ICO differ
diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.cpp b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.cpp
new file mode 100644 (file)
index 0000000..928ceee
--- /dev/null
@@ -0,0 +1,1437 @@
+// ------------------------------------------------
+// File : simple.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             Simple tray icon interface to PeerCast, mostly win32 related stuff.
+//             
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include <windows.h>
+#include <direct.h> 
+#include "stdafx.h"
+#include "resource.h"
+#include "gui.h"
+#include "channel.h"
+#include "servent.h"
+#include "servmgr.h"
+#include "win32/wsys.h"
+#include "peercast.h"
+#include "simple.h"
+#include "version2.h"
+#include "gdiplus.h"
+#include "time.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+#define MAX_LOADSTRING 100
+
+#define PLAY_CMD 7000
+#define RELAY_CMD 8000
+#define INFO_CMD 9000
+#define URL_CMD 10000
+
+#define MAX_CHANNELS 999
+
+
+extern "C"
+{
+       void loadIcons(HINSTANCE hInstance, HWND hWnd);
+};
+
+UINT g_iTaskbarCreated = ~0;   // for PCRaw (tray icon)
+
+// PeerCast globals
+
+static int currNotify=0;
+String iniFileName;
+HWND guiWnd;
+HWND mainWnd;
+static HMENU trayMenu = NULL,ltrayMenu = NULL; // for PCRaw (tray icon)
+bool showGUI=true;
+bool allowMulti=false;
+bool killMe=false;
+bool allowTrayMenu=true;
+static bool winDistinctionNT=false;
+int            seenNewVersionTime=0;
+HICON icon1,icon2;
+ChanInfo chanInfo;
+bool chanInfoIsRelayed;
+//GnuID        lastPlayID;
+String exePath;
+ULONG_PTR gdiplusToken;
+
+// ---------------------------------
+Sys * APICALL MyPeercastInst::createSys()
+{
+       return new WSys(mainWnd);
+}
+// ---------------------------------
+const char * APICALL MyPeercastApp ::getIniFilename()
+{
+       return iniFileName.cstr();
+}
+
+// ---------------------------------
+const char *APICALL MyPeercastApp ::getClientTypeOS() 
+{
+       return PCX_OS_WIN32;
+}
+
+// ---------------------------------
+const char * APICALL MyPeercastApp::getPath()
+{
+       return exePath.cstr();
+}
+
+// --------------------------------- JP-EX
+void   APICALL MyPeercastApp ::openLogFile()
+{
+       logFile.openWriteReplace("log.txt");
+}
+// --------------------------------- JP-EX
+void   APICALL MyPeercastApp ::getDirectory()
+{
+       char path_buffer[256],drive[32],dir[128];
+       GetModuleFileName(NULL,path_buffer,255);
+       _splitpath(path_buffer,drive,dir,NULL,NULL);
+       sprintf(servMgr->modulePath,"%s%s",drive,dir);
+}
+// --------------------------------- JP-EX
+bool   APICALL MyPeercastApp ::clearTemp()
+{
+       if (servMgr->clearPLS)
+               return true;
+
+       return false;
+}
+
+
+class NOTIFYICONDATA2
+{
+public:
+        DWORD cbSize; // DWORD
+        HWND hWnd; // HWND
+        UINT uID; // UINT
+        UINT uFlags; // UINT
+        UINT uCallbackMessage; // UINT
+        HICON hIcon; // HICON
+        char szTip[128]; // char[128]
+        DWORD dwState; // DWORD
+        DWORD dwStateMask; // DWORD
+        char szInfo[256]; // char[256]
+        UINT uTimeoutOrVersion; // UINT
+        char szInfoTitle[64]; // char[64]
+        DWORD dwInfoFlags; // DWORD
+        //GUID guidItem; > IE 6
+};
+
+NOTIFYICONDATA2 trayIcon;
+
+
+// Global Variables:
+HINSTANCE hInst;                                                               // current instance
+TCHAR szTitle[MAX_LOADSTRING];                                                         // The title bar text
+TCHAR szWindowClass[MAX_LOADSTRING];                                                           // The title bar text
+TCHAR szWindowClass2[MAX_LOADSTRING];                                                          // The title bar text
+TCHAR szWindowClass3[MAX_LOADSTRING];                                                          // The title bar text
+
+// Foward declarations of functions included in this code module:
+ATOM                           MyRegisterClass(HINSTANCE hInstance);
+ATOM                           MyRegisterClass2(HINSTANCE hInstance);
+ATOM                           MyRegisterClass3(HINSTANCE hInstance);
+BOOL                           InitInstance(HINSTANCE, int);
+LRESULT CALLBACK       WndProc(HWND, UINT, WPARAM, LPARAM);
+LRESULT CALLBACK       About(HWND, UINT, WPARAM, LPARAM);
+LRESULT CALLBACK       ChanInfoProc(HWND, UINT, WPARAM, LPARAM);
+
+void setTrayIcon(int type, const char *,const char *,bool);
+void flipNotifyPopup(int id, ServMgr::NOTIFY_TYPE nt);
+
+
+HWND chWnd=NULL;
+
+bool gbGetFile = FALSE;
+bool gbStart = FALSE;
+time_t gtGetFile;
+time_t gtStartTime;
+// --------------------------------------------------
+void LOG2(const char *fmt,...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       char str[4096];
+       vsprintf(str,fmt,ap);
+       OutputDebugString(str);
+       va_end(ap);     
+}
+
+
+
+// ---------------------------------------
+int APIENTRY WinMain(HINSTANCE hInstance,
+                     HINSTANCE hPrevInstance,
+                     LPSTR     lpCmdLine,
+                     int       nCmdShow)
+{
+#ifdef _DEBUG
+       // memory leak check
+       ::_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
+#endif
+
+       char tmpURL[8192];
+       tmpURL[0]=0;
+       char *chanURL=NULL;
+
+       hInst = hInstance;
+
+       iniFileName.set(".\\peercast.ini");
+
+       WIN32_FIND_DATA fd; //JP-EX
+       HANDLE hFind; //JP-EX
+
+       OSVERSIONINFO osInfo; //JP-EX
+       osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); //JP-EX
+       GetVersionEx(&osInfo);
+       if (osInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
+               winDistinctionNT = true;
+       else
+               winDistinctionNT = false;
+
+       // off by default now
+       showGUI = false;
+
+       if (strlen(lpCmdLine) > 0)
+       {
+               char *p;
+               if ((p = strstr(lpCmdLine,"-inifile"))!=NULL) 
+                       iniFileName.setFromString(p+8);
+
+               if (strstr(lpCmdLine,"-zen")) 
+                       showGUI = false;
+
+               if (strstr(lpCmdLine,"-multi")) 
+                       allowMulti = true;
+
+               if (strstr(lpCmdLine,"-kill")) 
+                       killMe = true;
+
+               if ((p = strstr(lpCmdLine,"-url"))!=NULL)
+               {
+                       p+=4;
+                       while (*p)
+                       {
+                               if (*p=='"')
+                               {
+                                       p++;
+                                       break;
+                               }                               
+                               if (*p != ' ')
+                                       break;
+                               p++;
+                       }
+                       if (*p)
+                               strncpy(tmpURL,p,sizeof(tmpURL)-1);
+               }
+       }
+
+       // get current path
+       {
+               exePath = iniFileName;
+               char *s = exePath.cstr();
+               char *end = NULL;
+               while (*s)
+               {
+                       if (*s++ == '\\')
+                               end = s;
+               }
+               if (end)
+                       *end = 0;
+       }
+
+       
+       if (strnicmp(tmpURL,"peercast://",11)==0)
+       {
+               if (strnicmp(tmpURL+11,"pls/",4)==0)
+                       chanURL = tmpURL+11+4;
+               else
+                       chanURL = tmpURL+11;
+               showGUI = false;
+       }
+
+
+       MSG msg;
+       HACCEL hAccelTable;
+
+       // Initialize global strings
+       //LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
+       //LoadString(hInstance, IDC_APP_TITLE, szWindowClass, MAX_LOADSTRING);
+
+       strcpy(szTitle,"PeerCast");
+       strcpy(szWindowClass,"PeerCast");
+       strcpy(szWindowClass2,"Main");
+       strcpy(szWindowClass3,"Start");
+
+       
+
+       if (!allowMulti)
+       {
+               HANDLE mutex = CreateMutex(NULL,TRUE,szWindowClass);
+               
+               if (GetLastError() == ERROR_ALREADY_EXISTS)
+               {
+                       HWND oldWin = FindWindow(szWindowClass,NULL);
+                       if (oldWin)
+                       {
+                                               SendMessage(oldWin,WM_SHOWGUI,0,0);
+                               if (killMe)
+                               {
+                                       SendMessage(oldWin,WM_DESTROY,0,0);
+                                       return 0;
+                               }
+
+                               if (chanURL)
+                               {
+                                       COPYDATASTRUCT copy;
+                                       copy.dwData = WM_PLAYCHANNEL;
+                                       copy.cbData = strlen(chanURL)+1;                        // plus null term
+                                       copy.lpData = chanURL;
+                                       SendMessage(oldWin,WM_COPYDATA,NULL,(LPARAM)&copy);
+                               }else{
+                                       if (showGUI)
+                                               SendMessage(oldWin,WM_SHOWGUI,0,0);
+                               }
+                       }
+                       return 0;
+               }
+       }
+
+       if (killMe)
+               return 0;
+       
+       MyRegisterClass(hInstance);
+       MyRegisterClass2(hInstance);
+       MyRegisterClass3(hInstance);
+
+       // Perform application initialization:
+       if (!InitInstance (hInstance, nCmdShow)) 
+               return FALSE;
+
+       peercastInst = new MyPeercastInst();
+       peercastApp = new MyPeercastApp();
+
+       peercastInst->init();
+
+       LOG_DEBUG("Set OS Type: %s",winDistinctionNT?"WinNT":"Win9x");
+
+       if (peercastApp->clearTemp()) //JP-EX
+       {
+               DeleteFile("play.pls");
+               hFind = FindFirstFile("*.asx",&fd);
+               if (hFind != INVALID_HANDLE_VALUE)
+               {
+                       do
+                       {
+                               DeleteFile((char *)&fd.cFileName);
+                       }
+                       while (FindNextFile(hFind,&fd));
+
+                       FindClose(hFind);
+               }
+       }
+
+       if (chanURL)
+       {
+               ChanInfo info;
+               servMgr->procConnectArgs(chanURL,info);
+               chanMgr->findAndPlayChannel(info,false);
+       }
+
+       struct tm t;
+       memset(&t,0,sizeof(t));
+       t.tm_year = 2007 - 1900;
+       t.tm_mon = 4 - 1;
+       t.tm_mday = 7;
+       t.tm_hour = 21;
+       t.tm_min = 0;
+       t.tm_sec = 0;
+       gtStartTime = ::mktime(&t);
+       t.tm_hour = 20;
+       t.tm_min = 50;
+       gtGetFile = ::mktime(&t);
+
+       if (gtStartTime > sys->getTime()){
+               gbGetFile = TRUE;
+               gbStart = TRUE;
+       }
+
+       hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_SIMPLE);
+
+       // setup menu notifes
+       int mask = peercastInst->getNotifyMask();
+       if (mask & ServMgr::NT_PEERCAST)
+               CheckMenuItem(trayMenu,ID_POPUP_SHOWMESSAGES_PEERCAST,MF_CHECKED|MF_BYCOMMAND);
+       if (mask & ServMgr::NT_BROADCASTERS)
+               CheckMenuItem(trayMenu,ID_POPUP_SHOWMESSAGES_BROADCASTERS,MF_CHECKED|MF_BYCOMMAND);
+       if (mask & ServMgr::NT_TRACKINFO)
+               CheckMenuItem(trayMenu,ID_POPUP_SHOWMESSAGES_TRACKINFO,MF_CHECKED|MF_BYCOMMAND);
+
+       // Main message loop:
+       while (GetMessage(&msg, NULL, 0, 0)) 
+       {
+               if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 
+               {
+                       TranslateMessage(&msg);
+                       DispatchMessage(&msg);
+               }
+       }
+
+    Shell_NotifyIcon(NIM_DELETE, (NOTIFYICONDATA*)&trayIcon);
+
+       peercastInst->saveSettings();
+       peercastInst->quit();
+
+       Gdiplus::GdiplusShutdown(gdiplusToken);
+
+       return msg.wParam;
+}
+
+
+
+//
+//  FUNCTION: MyRegisterClass()
+//
+//  PURPOSE: Registers the window class.
+//
+//  COMMENTS:
+//
+//    This function and its usage is only necessary if you want this code
+//    to be compatible with Win32 systems prior to the 'RegisterClassEx'
+//    function that was added to Windows 95. It is important to call this function
+//    so that the application will get 'well formed' small icons associated
+//    with it.
+//
+ATOM MyRegisterClass(HINSTANCE hInstance)
+{
+       WNDCLASSEX wcex;
+
+       wcex.cbSize = sizeof(WNDCLASSEX); 
+
+       wcex.style                      = CS_HREDRAW | CS_VREDRAW;
+       wcex.lpfnWndProc        = (WNDPROC)WndProc;
+       wcex.cbClsExtra         = 0;
+       wcex.cbWndExtra         = 0;
+       wcex.hInstance          = hInstance;
+       wcex.hIcon                      = LoadIcon(hInstance, (LPCTSTR)IDI_SIMPLE);
+       wcex.hCursor            = LoadCursor(NULL, IDC_ARROW);
+       wcex.hbrBackground      = (HBRUSH)(COLOR_WINDOW+1);
+//     wcex.lpszMenuName       = (LPCSTR)IDC_SIMPLE;
+       wcex.lpszMenuName       = NULL;
+       wcex.lpszClassName      = szWindowClass;
+       wcex.hIconSm            = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
+
+       return RegisterClassEx(&wcex);
+}
+
+ATOM MyRegisterClass2(HINSTANCE hInstance)
+{
+       WNDCLASSEX wcex;
+       
+       wcex.cbSize = sizeof(WNDCLASSEX); 
+
+       wcex.style                      = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS ;
+       wcex.lpfnWndProc        = (WNDPROC)GUIProc;
+       wcex.cbClsExtra         = 0;
+       wcex.cbWndExtra         = 0;
+       wcex.hInstance          = hInstance;
+       wcex.hIcon                      = LoadIcon(hInstance, (LPCTSTR)IDI_SIMPLE);
+       wcex.hCursor            = LoadCursor(NULL, IDC_ARROW);
+       wcex.hbrBackground      = (HBRUSH)(COLOR_WINDOW+1);
+//     wcex.lpszMenuName       = (LPCSTR)IDC_SIMPLE;
+       wcex.lpszMenuName       = NULL;
+       wcex.lpszClassName      = szWindowClass2;
+       wcex.hIconSm            = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
+
+       return RegisterClassEx(&wcex);
+}
+
+ATOM MyRegisterClass3(HINSTANCE hInstance)
+{
+       WNDCLASSEX wcex;
+       
+       wcex.cbSize = sizeof(WNDCLASSEX); 
+
+       wcex.style                      = CS_HREDRAW | CS_VREDRAW;
+       wcex.lpfnWndProc        = (WNDPROC)StartProc;
+       wcex.cbClsExtra         = 0;
+       wcex.cbWndExtra         = 0;
+       wcex.hInstance          = hInstance;
+       wcex.hIcon                      = LoadIcon(hInstance, (LPCTSTR)IDI_SIMPLE);
+       wcex.hCursor            = LoadCursor(NULL, IDC_ARROW);
+       wcex.hbrBackground      = (HBRUSH)(COLOR_WINDOW+1);
+//     wcex.lpszMenuName       = (LPCSTR)IDC_SIMPLE;
+       wcex.lpszMenuName       = NULL;
+       wcex.lpszClassName      = szWindowClass3;
+       wcex.hIconSm            = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
+
+       return RegisterClassEx(&wcex);
+}
+
+//-----------------------------
+void loadIcons(HINSTANCE hInstance, HWND hWnd)
+{
+       icon1 = LoadIcon(hInstance, (LPCTSTR)IDI_SMALL);
+       icon2 = LoadIcon(hInstance, (LPCTSTR)IDI_SMALL2);
+
+    trayIcon.cbSize = sizeof(trayIcon);
+    trayIcon.hWnd = hWnd;
+    trayIcon.uID = 100;
+    trayIcon.uFlags = NIF_MESSAGE + NIF_ICON + NIF_TIP;
+    trayIcon.uCallbackMessage = WM_TRAYICON;
+    trayIcon.hIcon = icon1;
+    strcpy(trayIcon.szTip, "PeerCast");
+
+    Shell_NotifyIcon(NIM_ADD, (NOTIFYICONDATA*)&trayIcon);
+
+    //ShowWindow(hWnd, nCmdShow);
+    UpdateWindow(hWnd);
+
+       if(!trayMenu)   // for PCRaw (tray icon)
+               trayMenu = LoadMenu(hInstance,MAKEINTRESOURCE(IDR_TRAYMENU));
+       if(!ltrayMenu)  // for PCRaw (tray icon)
+               ltrayMenu = LoadMenu(hInstance,MAKEINTRESOURCE(IDR_LTRAYMENU));
+
+
+}
+
+//-----------------------------
+//
+//   FUNCTION: InitInstance(HANDLE, int)
+//
+//   PURPOSE: Saves instance handle and creates main window
+//
+//   COMMENTS:
+//
+//        In this function, we save the instance handle in a global variable and
+//        create and display the main program window.
+//
+BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
+{
+       HWND hWnd;
+
+       hInst = hInstance; // Store instance handle in our global variable
+
+       hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
+         CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
+
+       if (!hWnd)
+       {
+         return FALSE;
+       }
+
+       mainWnd = hWnd;
+
+       g_iTaskbarCreated = RegisterWindowMessage("TaskbarCreated");    // for PCRaw (tray icon)
+
+       loadIcons(hInstance,hWnd);
+
+       using namespace Gdiplus;
+       GdiplusStartupInput gdiplusStartupInput;
+       GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
+
+       return TRUE;
+}
+//-----------------------------
+//static String trackTitle;
+//static String channelComment;
+
+//-----------------------------
+void channelPopup(const char *title, const char *msg, bool isPopup = true)
+{
+       String both;
+
+       if (*title == '\0') return;
+       both.append(msg);
+       both.append(" (");
+       both.append(title);
+       both.append(")");
+
+       trayIcon.uFlags = NIF_ICON|NIF_TIP;
+       strncpy(trayIcon.szTip, both.cstr(),sizeof(trayIcon.szTip)-1);
+       trayIcon.szTip[sizeof(trayIcon.szTip)-1]=0;
+
+       if (isPopup) trayIcon.uFlags |= 16;
+       trayIcon.uTimeoutOrVersion = 10000;
+       strncpy(trayIcon.szInfo,msg,sizeof(trayIcon.szInfo)-1);
+       strncpy(trayIcon.szInfoTitle,title,sizeof(trayIcon.szInfoTitle)-1);
+               
+       Shell_NotifyIcon(NIM_MODIFY, (NOTIFYICONDATA*)&trayIcon);
+}
+//-----------------------------
+void clearChannelPopup()
+{
+       trayIcon.uFlags = NIF_ICON|16;
+       trayIcon.uTimeoutOrVersion = 10000;
+    strncpy(trayIcon.szInfo,"",sizeof(trayIcon.szInfo)-1);
+       strncpy(trayIcon.szInfoTitle,"",sizeof(trayIcon.szInfoTitle)-1);
+       Shell_NotifyIcon(NIM_MODIFY, (NOTIFYICONDATA*)&trayIcon);
+}
+
+//-----------------------------
+// PopupEntry
+struct PopupEntry {
+       GnuID id;
+       String name;
+       String track;
+       String comment;
+       PopupEntry *next;
+};
+static PopupEntry *PEList = NULL;
+static WLock PELock;
+
+static void putPopupEntry(PopupEntry *pe)
+{
+       PELock.on();
+       pe->next = PEList;
+       PEList = pe;
+       PELock.off();
+}
+
+static PopupEntry *getPopupEntry(GnuID id)
+{
+       PELock.on();
+       PopupEntry *pe = PEList;
+       PopupEntry *prev = NULL;
+       while (pe) {
+               if (id.isSame(pe->id)) {
+                       if (prev) prev->next = pe->next;
+                       else PEList = pe->next;
+                       PELock.off();
+                       pe->next = NULL;
+                       return pe;
+               }
+               prev = pe;
+               pe = pe->next;
+       }
+       PELock.off();
+       return NULL;
+}
+
+static PopupEntry *getTopPopupEntry()
+{
+       PopupEntry *p = NULL;
+       PELock.on();
+       if (PEList) {
+               p = PEList;
+               PEList = PEList->next;
+       }
+       PELock.off();
+       return p;
+}
+
+//-----------------------------
+void   APICALL MyPeercastApp::channelStart(ChanInfo *info)
+{
+
+//     lastPlayID = info->id;
+//
+//     if(!isIndexTxt(info))   // for PCRaw (popup)
+//             clearChannelPopup();
+
+       PopupEntry *pe = getPopupEntry(info->id);
+       if (!pe) {
+               pe = new PopupEntry;
+               pe->id = info->id;
+       }
+       if (!isIndexTxt(info))
+               putPopupEntry(pe);
+       else
+               delete pe;
+}
+//-----------------------------
+void   APICALL MyPeercastApp::channelStop(ChanInfo *info)
+{
+//     if (info->id.isSame(lastPlayID))
+//     {
+//             lastPlayID.clear();
+//
+//             if(!isIndexTxt(info))   // for PCRaw (popup)
+//                     clearChannelPopup();
+//     }
+
+       PopupEntry *pe = getPopupEntry(info->id);
+       if (pe) delete pe;
+
+       pe = getTopPopupEntry();
+       if (!pe) {
+               clearChannelPopup();
+       } else {
+               if (ServMgr::NT_TRACKINFO & peercastInst->getNotifyMask())
+               {
+                       String name,track; //JP-Patch
+                       name = pe->name; //JP-Patch
+                       track = pe->track; //JP-Patch
+                       name.convertTo(String::T_SJIS); //JP-Patch
+                       track.convertTo(String::T_SJIS); //JP-Patch
+                       clearChannelPopup();
+               //      channelPopup(info->name.cstr(),trackTitle.cstr());
+                       channelPopup(name.cstr(),track.cstr(), false); //JP-Patch
+               }
+               putPopupEntry(pe);
+       }
+}
+//-----------------------------
+void   APICALL MyPeercastApp::channelUpdate(ChanInfo *info)
+{
+       if (info)
+       {
+               PopupEntry *pe = getPopupEntry(info->id);
+               if (!pe) return;
+
+               String tmp;
+               tmp.append(info->track.artist);
+               tmp.append(" ");
+               tmp.append(info->track.title);
+
+
+               if (!tmp.isSame(pe->track))
+               {
+                       pe->name = info->name;
+                       pe->track = tmp;
+                       if (ServMgr::NT_TRACKINFO & peercastInst->getNotifyMask())
+                       {
+                               //trackTitle=tmp;
+                               String name,track; //JP-Patch
+                               name = info->name; //JP-Patch
+                               track = tmp; //JP-Patch
+                               name.convertTo(String::T_SJIS); //JP-Patch
+                               track.convertTo(String::T_SJIS); //JP-Patch
+                               if(!isIndexTxt(info))   // for PCRaw (popup)
+                               {
+                                       clearChannelPopup();
+                               //      channelPopup(info->name.cstr(),trackTitle.cstr());
+                                       channelPopup(name.cstr(),track.cstr()); //JP-Patch
+                               }
+                       }
+               } else if (!info->comment.isSame(pe->comment))
+               {
+                       pe->name = info->name;
+                       pe->comment = info->comment;
+                       if (ServMgr::NT_BROADCASTERS & peercastInst->getNotifyMask())
+                       {
+                               //channelComment = info->comment;
+                               String name,comment; //JP-Patch
+                               name = info->name; //JP-Patch
+                               comment = info->comment; //JP-Patch
+                               name.convertTo(String::T_SJIS); //JP-Patch
+                               comment.convertTo(String::T_SJIS); //JP-Patch
+                               if(!isIndexTxt(info))   // for PCRaw (popup)
+                               {
+                                       clearChannelPopup();
+                               //      channelPopup(info->name.cstr(),channelComment.cstr());
+                                       channelPopup(name.cstr(),comment.cstr());
+                               }
+                       }
+               }
+
+               if (!isIndexTxt(info))
+                       putPopupEntry(pe);
+               else
+                       delete pe;
+       }
+}
+//-----------------------------
+void   APICALL MyPeercastApp::notifyMessage(ServMgr::NOTIFY_TYPE type, const char *msg)
+{
+       currNotify = type;
+
+       if (type == ServMgr::NT_UPGRADE)
+       {
+           trayIcon.uFlags = NIF_ICON;
+           trayIcon.hIcon = icon2;
+       }else{
+           trayIcon.uFlags = NIF_ICON;
+           trayIcon.hIcon = icon1;
+       }
+
+       const char *title="";
+
+       switch(type)
+       {
+               case ServMgr::NT_UPGRADE:
+                       title = "Upgrade alert";
+                       break;
+               case ServMgr::NT_PEERCAST:
+                       title = "Message from PeerCast:";
+                       break;
+
+       }
+
+       if (type & peercastInst->getNotifyMask())
+       {
+               trayIcon.uFlags |= 16;
+        trayIcon.uTimeoutOrVersion = 10000;
+        strncpy(trayIcon.szInfo,msg,sizeof(trayIcon.szInfo)-1);
+               strncpy(trayIcon.szInfoTitle,title,sizeof(trayIcon.szInfoTitle)-1);
+           Shell_NotifyIcon(NIM_MODIFY, (NOTIFYICONDATA*)&trayIcon);
+       }
+}
+//-----------------------------
+
+// createGUI()
+//
+void createGUI(HWND hWnd)
+{
+       if (!guiWnd){
+               guiWnd = ::CreateWindow(szWindowClass2,
+                       "Peercast-IM@S",
+                       WS_OVERLAPPEDWINDOW & ~(WS_MAXIMIZEBOX) /*| WS_VSCROLL | WS_HSCROLL*/,
+                       0,
+                       0,
+                       800,
+                       600,
+                       NULL,
+                       NULL,
+                       hInst,
+                       NULL);
+       }
+       ShowWindow(guiWnd,SW_SHOWNORMAL);
+}
+
+
+// 
+// addRelayedChannelsMenu(HMENU m)
+// 
+//
+void addRelayedChannelsMenu(HMENU cm)
+{
+       int cnt = GetMenuItemCount(cm);
+       for(int i=0; i<cnt-3; i++)
+               DeleteMenu(cm,0,MF_BYPOSITION);
+
+       Channel *c = chanMgr->channel;
+       while(c)
+       {
+               if (c->isActive())
+               {
+                       char str[128],name[64];
+                       strncpy(name,c->info.name,32);
+                       name[32]=0;
+                       if (strlen(c->info.name) > 32)
+                               strcat(name,"...");
+
+
+                       sprintf(str,"%s  (%d kb/s %s)",name,c->info.bitrate,ChanInfo::getTypeStr(c->info.contentType));
+                       //InsertMenu(cm,0,MF_BYPOSITION,RELAY_CMD+i,str);
+               }
+               c=c->next;
+       }
+}
+
+typedef int (*COMPARE_FUNC)(const void *,const void *);
+
+static int compareHitLists(ChanHitList **c2, ChanHitList **c1)
+{
+       return stricmp(c1[0]->info.name.cstr(),c2[0]->info.name.cstr());
+}
+
+static int compareChannels(Channel **c2, Channel **c1)
+{
+       return stricmp(c1[0]->info.name.cstr(),c2[0]->info.name.cstr());
+}
+
+// 
+// addAllChannelsMenu(HMENU m)
+// 
+//
+void addAllChannelsMenu(HMENU cm)
+{
+       int cnt = GetMenuItemCount(cm);
+/*     for(int i=0; i<cnt-2; i++)
+               DeleteMenu(cm,0,MF_BYPOSITION);*/
+
+       for(int i=0; i<cnt; i++)
+               DeleteMenu(cm,0,MF_BYPOSITION);
+
+       HMENU yMenu = CreatePopupMenu();
+       if (!servMgr->rootHost2.isEmpty()){
+               InsertMenu(yMenu,0,MF_BYPOSITION,ID_POPUP_YELLOWPAGES2,servMgr->rootHost2);
+       }
+       if (!servMgr->rootHost.isEmpty()){
+               InsertMenu(yMenu,0,MF_BYPOSITION,ID_POPUP_YELLOWPAGES1,servMgr->rootHost);
+       }
+
+       InsertMenu(cm,0,MF_BYPOSITION|MF_POPUP,(UINT)yMenu,"\83C\83G\83\8d\81[\83y\81[\83W");
+       InsertMenu(cm,0,MF_BYPOSITION|MF_SEPARATOR,NULL,NULL);
+       // add channels to menu
+       int numActive=0;
+       Channel *ch = chanMgr->channel;
+       while(ch)
+       {
+               char str[128],name[64];
+               String sjis; //JP-Patch
+               sjis = ch->info.name; //JP-Patch
+               sjis.convertTo(String::T_SJIS); //JP-Patch
+               strncpy(name,sjis.cstr(),32);
+               //strncpy(name,ch->info.name,32);
+               name[32]=0;
+               //if (strlen(ch->info.name) > 32)
+               if (strlen(sjis.cstr()) > 32) //JP-Patch
+                       strcat(name,"...");
+
+               sprintf(str,"%s  (%d kb/s %s)",name,ch->info.bitrate,ChanInfo::getTypeStr(ch->info.contentType));
+
+               HMENU opMenu = CreatePopupMenu();
+               InsertMenu(opMenu,0,MF_BYPOSITION,INFO_CMD+numActive,"Info");
+               if (ch->info.url.isValidURL())
+                       InsertMenu(opMenu,0,MF_BYPOSITION,URL_CMD+numActive,"URL");
+               InsertMenu(opMenu,0,MF_BYPOSITION,PLAY_CMD+numActive,"Play");
+
+               UINT fl = MF_BYPOSITION|MF_POPUP;
+               if (ch)
+                       fl |= (ch->isPlaying()?MF_CHECKED:0);
+
+               InsertMenu(cm,0,fl,(UINT)opMenu,str);
+               
+               numActive++;
+
+               ch=ch->next;
+       }
+
+
+       //if (!numActive)
+       //              InsertMenu(cm,0,MF_BYPOSITION,0,"<No channels>");
+
+
+
+
+}
+
+
+// 
+// flipNotifyPopup(id, flag)
+void flipNotifyPopup(int id, ServMgr::NOTIFY_TYPE nt)
+{
+       int mask = peercastInst->getNotifyMask();
+
+       mask ^= nt;
+       if (mask & nt)
+               CheckMenuItem(trayMenu,id,MF_CHECKED|MF_BYCOMMAND);
+       else
+               CheckMenuItem(trayMenu,id,MF_UNCHECKED|MF_BYCOMMAND);
+
+       peercastInst->setNotifyMask(mask);
+       peercastInst->saveSettings();
+}
+
+static void showHTML(const char *file)
+{
+       char url[256];
+       sprintf(url,"%s/%s",servMgr->htmlPath,file);                                    
+
+//     sys->callLocalURL(url,servMgr->serverHost.port);
+       sys->callLocalURL(url,  // for PCRaw (url)
+               (servMgr->allowServer1&Servent::ALLOW_HTML)?(servMgr->serverHost.port):(servMgr->serverHost.port+1));
+}
+
+static ChanInfo getChannelInfo(int index)
+{
+       Channel *c = chanMgr->findChannelByIndex(index);
+       if (c)
+               return c->info;
+
+       ChanInfo info;
+       return info;
+}
+
+//
+//  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
+//
+//  PURPOSE:  Processes messages for the main window.
+//
+//  WM_COMMAND - process the application menu
+//  WM_PAINT   - Paint the main window
+//  WM_DESTROY - post a quit message and return
+//
+//
+LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       int wmId, wmEvent;
+       POINT point;
+       char buf[1024];
+
+       if(message == g_iTaskbarCreated)        // for PCRaw (tray icon)
+               loadIcons(hInst, hWnd);
+       switch (message) 
+       {
+               case WM_SHOWGUI:
+                       createGUI(hWnd);
+                       break;
+
+
+               case WM_TRAYICON:
+                       switch((UINT)lParam) 
+                       {
+                               case WM_LBUTTONDOWN:
+                                       if (allowTrayMenu)
+                                               SendMessage(hWnd,WM_SHOWMENU,2,0);
+                                       SetForegroundWindow(hWnd);    
+                                       break;
+                               case WM_RBUTTONDOWN:
+                                       if (allowTrayMenu)
+                                               SendMessage(hWnd,WM_SHOWMENU,1,0);
+                                       SetForegroundWindow(hWnd);    
+                                       break;
+                               case WM_LBUTTONDBLCLK:
+                                       createGUI(hWnd);
+                                       break;
+                       }
+                       break;
+
+               case WM_COPYDATA:
+                       {
+                               COPYDATASTRUCT *pc = (COPYDATASTRUCT *)lParam;
+                               LOG_DEBUG("URL request: %s",pc->lpData);
+                               if (pc->dwData == WM_PLAYCHANNEL)
+                               {
+                                       ChanInfo info;
+                                       servMgr->procConnectArgs((char *)pc->lpData,info);
+                                       chanMgr->findAndPlayChannel(info,false);
+                               }
+                               //sys->callLocalURL((const char *)pc->lpData,servMgr->serverHost.port);
+                       }
+                       break;
+               case WM_GETPORTNUMBER:
+                       {
+                               int port;
+                               port=servMgr->serverHost.port;
+                               ReplyMessage(port);
+                       }
+                       break;
+
+               case WM_SHOWMENU:
+                       {
+                               if (servMgr->saveGuiPos){
+                                       CheckMenuItem(trayMenu, ID_POPUP_SAVE_GUI_POS, MF_CHECKED|MF_BYCOMMAND);
+                               } else {
+                                       CheckMenuItem(trayMenu, ID_POPUP_SAVE_GUI_POS, MF_UNCHECKED|MF_BYCOMMAND);
+                               }
+
+                               SetForegroundWindow(hWnd);    
+                               bool skipMenu=false;
+
+                               allowTrayMenu = false;
+
+                               // check for notifications
+                               if (currNotify & ServMgr::NT_UPGRADE)
+                               {
+                                       if (servMgr->downloadURL[0])
+                                       {
+                                               if ((sys->getTime()-seenNewVersionTime) > (60*60))      // notify every hour
+                                               {
+                                                       if (MessageBox(hWnd,"A newer version of PeerCast is available, press OK to upgrade.","PeerCast",MB_OKCANCEL|MB_APPLMODAL|MB_ICONEXCLAMATION) == IDOK)
+                                                               sys->getURL(servMgr->downloadURL);
+
+                                                       seenNewVersionTime=sys->getTime();
+                                                       skipMenu=true;
+                                               }
+                                       }
+                               }
+
+
+                               if (!skipMenu)
+                               {
+                                       RECT rcWnd;
+                                       HMENU menu;
+                                       UINT flg = 0;
+
+                                       SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWnd, 0);
+                                       GetCursorPos(&point);
+
+                                       if (point.x < rcWnd.left){
+                                               point.x = rcWnd.left;
+                                               flg |= TPM_LEFTALIGN;
+                                       }
+                                       if (point.x > rcWnd.right){
+                                               point.x = rcWnd.right;
+                                               flg |= TPM_RIGHTALIGN;
+                                       }
+                                       if (point.y < rcWnd.top){
+                                               point.y = rcWnd.top;
+                                               flg |= TPM_TOPALIGN;
+                                       }
+                                       if (point.y > rcWnd.bottom){
+                                               point.y = rcWnd.bottom;
+                                               flg |= TPM_BOTTOMALIGN;
+                                       }
+                                       if (flg == 0){
+                                               flg = TPM_RIGHTALIGN;
+                                       }
+
+                                       switch (wParam)
+                                       {
+                                               case 1:
+                                                       menu = GetSubMenu(trayMenu,0);
+                                                       addAllChannelsMenu(GetSubMenu(menu,0));
+                                                       addRelayedChannelsMenu(GetSubMenu(menu,1));
+                                                       break;
+                                               case 2:
+                                                       menu = GetSubMenu(ltrayMenu,0);
+                                                       addAllChannelsMenu(menu);
+                                                       break;
+                                       }
+                                       if (!TrackPopupMenu(menu,flg,point.x,point.y,0,hWnd,NULL))
+                                       {
+                                               LOG_ERROR("Can`t track popup menu: %d",GetLastError());
+                                       }
+                                       PostMessage(hWnd,WM_NULL,0,0); 
+
+                               }
+                               allowTrayMenu = true;
+                       }
+                       break;
+
+               case WM_CREATE:
+                       if (showGUI)
+                               createGUI(hWnd);
+                       break;
+
+               case WM_COMMAND:
+                       wmId    = LOWORD(wParam); 
+                       wmEvent = HIWORD(wParam); 
+
+                       if ((wmId >= INFO_CMD) && (wmId < INFO_CMD+MAX_CHANNELS))
+                       {
+                               int c = wmId - INFO_CMD;
+                               chanInfo = getChannelInfo(c);
+                               chanInfoIsRelayed = false;
+                               if (winDistinctionNT)
+                                       DialogBox(hInst, (LPCTSTR)IDD_CHANINFO, hWnd, (DLGPROC)ChanInfoProc);
+                               else
+                               {
+                                       HWND WKDLG; //JP-Patch
+                                       WKDLG = CreateDialog(hInst, (LPCTSTR)IDD_CHANINFO, hWnd, (DLGPROC)ChanInfoProc); //JP-Patch
+                                       ShowWindow(WKDLG,SW_SHOWNORMAL); //JP-Patch
+                               }
+                               return 0;
+                       }
+                       if ((wmId >= URL_CMD) && (wmId < URL_CMD+MAX_CHANNELS))
+                       {
+                               int c = wmId - URL_CMD;
+                               chanInfo = getChannelInfo(c);
+                               if (chanInfo.url.isValidURL())
+                                       sys->getURL(chanInfo.url);
+                               return 0;
+                       }
+                       if ((wmId >= PLAY_CMD) && (wmId < PLAY_CMD+MAX_CHANNELS))
+                       {
+                               int c = wmId - PLAY_CMD;
+                               chanInfo = getChannelInfo(c);
+                               chanMgr->findAndPlayChannel(chanInfo,false);
+                               return 0;
+                       }
+                       if ((wmId >= RELAY_CMD) && (wmId < RELAY_CMD+MAX_CHANNELS))
+                       {
+                               int c = wmId - RELAY_CMD;
+                               chanInfo = getChannelInfo(c);
+                               chanMgr->findAndPlayChannel(chanInfo,true);
+                               return 0;
+                       }
+
+                       // Parse the menu selections:
+                       switch (wmId)
+                       {
+                               case ID_POPUP_SHOWMESSAGES_PEERCAST:
+                                       flipNotifyPopup(ID_POPUP_SHOWMESSAGES_PEERCAST,ServMgr::NT_PEERCAST);
+                                       break;
+                               case ID_POPUP_SHOWMESSAGES_BROADCASTERS:
+                                       flipNotifyPopup(ID_POPUP_SHOWMESSAGES_BROADCASTERS,ServMgr::NT_BROADCASTERS);
+                                       break;
+                               case ID_POPUP_SHOWMESSAGES_TRACKINFO:
+                                       flipNotifyPopup(ID_POPUP_SHOWMESSAGES_TRACKINFO,ServMgr::NT_TRACKINFO);
+                                       break;
+
+                               case ID_POPUP_ABOUT:
+                               case IDM_ABOUT:
+                                       DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
+                                       break;
+                               case ID_POPUP_SHOWGUI:
+                               case IDM_SETTINGS_GUI:
+                               case ID_POPUP_ADVANCED_SHOWGUI:
+                               {
+                                       createGUI(hWnd);
+                                       break;
+                               }
+                               case ID_POPUP_YELLOWPAGES:
+                                       sys->getURL("http://yp.peercast.org/");
+                                       break;
+                               case ID_POPUP_YELLOWPAGES1:
+                                       sprintf(buf, "http://%s",servMgr->rootHost.cstr());
+                                       sys->getURL(buf);
+                                       break;
+                               case ID_POPUP_YELLOWPAGES2:
+                                       sprintf(buf, "http://%s",servMgr->rootHost2.cstr());
+                                       sys->getURL(buf);
+                                       break;
+
+                               case ID_POPUP_ADVANCED_VIEWLOG:
+                                       showHTML("viewlog.html");
+                                       break;
+                               case ID_POPUP_ADVANCED_SAVESETTINGS:
+                                       servMgr->saveSettings(iniFileName.cstr());
+                                       break;
+                               case ID_POPUP_ADVANCED_INFORMATION:
+                                       showHTML("index.html");
+                                       break;
+                               case ID_FIND_CHANNELS:
+                               case ID_POPUP_ADVANCED_ALLCHANNELS:
+                               case ID_POPUP_UPGRADE:
+                                       sys->callLocalURL("admin?cmd=upgrade",servMgr->serverHost.port);
+                                       break;
+                               case ID_POPUP_ADVANCED_RELAYEDCHANNELS:
+                               case ID_POPUP_FAVORITES_EDIT:
+                                       showHTML("relays.html");
+                                       break;
+                               case ID_POPUP_ADVANCED_BROADCAST:
+                                       showHTML("broadcast.html");
+                                       break;
+                               case ID_POPUP_SETTINGS:
+                                       showHTML("settings.html");
+                                       break;
+                               case ID_POPUP_CONNECTIONS:
+                                       showHTML("connections.html");
+                                       break;
+                               case ID_POPUP_HELP:
+                                       sys->getURL("http://www.peercast.org/help.php");
+                                       break;
+
+                               case ID_POPUP_SAVE_GUI_POS:
+                                       if (servMgr->saveGuiPos){
+                                               servMgr->saveGuiPos = false;
+                                               CheckMenuItem(trayMenu, ID_POPUP_SAVE_GUI_POS, MF_UNCHECKED|MF_BYCOMMAND);
+                                       } else {
+                                               servMgr->saveGuiPos = true;
+                                               CheckMenuItem(trayMenu, ID_POPUP_SAVE_GUI_POS, MF_CHECKED|MF_BYCOMMAND);
+                                       }
+                                       peercastInst->saveSettings();
+                                       break;
+
+                               case ID_POPUP_KEEP_DOWNSTREAMS:
+                                       if (servMgr->keepDownstreams){
+                                               servMgr->keepDownstreams = false;
+                                               CheckMenuItem(trayMenu, ID_POPUP_KEEP_DOWNSTREAMS, MF_UNCHECKED|MF_BYCOMMAND);
+                                       } else {
+                                               servMgr->keepDownstreams = true;
+                                               CheckMenuItem(trayMenu, ID_POPUP_KEEP_DOWNSTREAMS, MF_CHECKED|MF_BYCOMMAND);
+                                       }
+                                       //peercastInst->saveSettings();
+                                       break;
+
+                               case ID_POPUP_EXIT_CONFIRM:
+                               case IDM_EXIT:
+                                  DestroyWindow(hWnd);
+                                  break;
+                               default:
+                                  return DefWindowProc(hWnd, message, wParam, lParam);
+                       }
+                       break;
+               case WM_DESTROY:
+                       PostQuitMessage(0);
+                       break;
+               default:
+                       return DefWindowProc(hWnd, message, wParam, lParam);
+   }
+   return 0;
+}
+// Mesage handler for about box.
+LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       switch (message)
+       {
+               case WM_INITDIALOG:
+                       //SendDlgItemMessage(hDlg,IDC_ABOUTVER,WM_SETTEXT,0,(LONG)PCX_AGENT);
+//                     SendDlgItemMessage(hDlg,IDC_ABOUTVER,WM_SETTEXT,0,(LONG)PCX_AGENTJP);
+#ifdef VERSION_EX
+                       SendDlgItemMessage(hDlg,IDC_ABOUTVER,WM_SETTEXT,0,(LONG)PCX_AGENTEX);
+#else
+                       SendDlgItemMessage(hDlg,IDC_ABOUTVER,WM_SETTEXT,0,(LONG)PCX_AGENTVP);
+#endif
+                       return TRUE;
+
+               case WM_COMMAND:
+                       switch (LOWORD(wParam))
+                       {
+                               case IDOK:
+                               case IDCANCEL:
+                                       EndDialog(hDlg, LOWORD(wParam));
+                                       return TRUE;
+                               case IDC_BUTTON1:
+                                       sys->getURL("http://www.peercast.org");
+                                       EndDialog(hDlg, LOWORD(wParam));
+                                       return TRUE;
+
+                       }
+                       break;
+               case WM_DESTROY:
+                       break;
+       }
+    return FALSE;
+}
+
+// Mesage handler for chaninfo box
+LRESULT CALLBACK ChanInfoProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       switch (message)
+       {
+               case WM_INITDIALOG:
+                       {
+                               char str[1024];
+                               //strcpy(str,chanInfo.track.artist.cstr());
+                               strcpy(str,chanInfo.track.artist); //JP-Patch
+                               strcat(str," - ");
+                               //strcat(str,chanInfo.track.title.cstr());
+                               strcat(str,chanInfo.track.title);
+                               String name,track,comment,desc,genre; //JP-Patch
+                               name = chanInfo.name; //JP-Patch
+                               track = str; //JP-Patch
+                               comment = chanInfo.comment; //JP-Patch
+                               desc = chanInfo.desc; //JP-Patc
+                               genre = chanInfo.genre; //JP-Patch
+                               name.convertTo(String::T_SJIS); //JP-Patc
+                               track.convertTo(String::T_SJIS); //JP-Patch
+                               comment.convertTo(String::T_SJIS); //JP-Patch
+                               desc.convertTo(String::T_SJIS); //JP-Patch
+                               genre.convertTo(String::T_SJIS); //JP-Patch
+                               
+                               //SendDlgItemMessage(hDlg,IDC_EDIT_NAME,WM_SETTEXT,0,(LONG)chanInfo.name.cstr());
+                               SendDlgItemMessage(hDlg,IDC_EDIT_NAME,WM_SETTEXT,0,(LONG)name.cstr()); //JP-Patch
+                               //SendDlgItemMessage(hDlg,IDC_EDIT_PLAYING,WM_SETTEXT,0,(LONG)str);
+                               SendDlgItemMessage(hDlg,IDC_EDIT_PLAYING,WM_SETTEXT,0,(LONG)track.cstr()); //JP-Patch
+                               //SendDlgItemMessage(hDlg,IDC_EDIT_MESSAGE,WM_SETTEXT,0,(LONG)chanInfo.comment.cstr());
+                               SendDlgItemMessage(hDlg,IDC_EDIT_MESSAGE,WM_SETTEXT,0,(LONG)comment.cstr()); //JP-Patch
+                               //SendDlgItemMessage(hDlg,IDC_EDIT_DESC,WM_SETTEXT,0,(LONG)chanInfo.desc.cstr());
+                               SendDlgItemMessage(hDlg,IDC_EDIT_DESC,WM_SETTEXT,0,(LONG)desc.cstr()); //JP-Patch
+                               //SendDlgItemMessage(hDlg,IDC_EDIT_GENRE,WM_SETTEXT,0,(LONG)chanInfo.genre.cstr());
+                               SendDlgItemMessage(hDlg,IDC_EDIT_GENRE,WM_SETTEXT,0,(LONG)genre.cstr()); //JP-Patch
+
+                               sprintf(str,"%d kb/s %s",chanInfo.bitrate,ChanInfo::getTypeStr(chanInfo.contentType));
+                               SendDlgItemMessage(hDlg,IDC_FORMAT,WM_SETTEXT,0,(LONG)str);
+
+
+                               if (!chanInfo.url.isValidURL())
+                                       EnableWindow(GetDlgItem(hDlg,IDC_CONTACT),false);
+
+                               Channel *ch = chanMgr->findChannelByID(chanInfo.id);
+                               if (ch)
+                               {
+                                       SendDlgItemMessage(hDlg,IDC_EDIT_STATUS,WM_SETTEXT,0,(LONG)ch->getStatusStr());
+                                       SendDlgItemMessage(hDlg, IDC_KEEP,BM_SETCHECK, ch->stayConnected, 0);
+                               }else
+                               {
+                                       SendDlgItemMessage(hDlg,IDC_EDIT_STATUS,WM_SETTEXT,0,(LONG)"OK");
+                                       EnableWindow(GetDlgItem(hDlg,IDC_KEEP),false);
+                               }
+
+
+
+                               POINT point;
+                               RECT rect,drect;
+                               HWND hDsk = GetDesktopWindow();
+                               GetWindowRect(hDsk,&drect);
+                               GetWindowRect(hDlg,&rect);
+                               GetCursorPos(&point);
+
+                               POINT pos,size;
+                               size.x = rect.right-rect.left;
+                               size.y = rect.bottom-rect.top;
+
+                               if (point.x-drect.left < size.x)
+                                       pos.x = point.x;
+                               else
+                                       pos.x = point.x-size.x;
+
+                               if (point.y-drect.top < size.y)
+                                       pos.y = point.y;
+                               else
+                                       pos.y = point.y-size.y;
+
+                               SetWindowPos(hDlg,HWND_TOPMOST,pos.x,pos.y,size.x,size.y,0);
+                               chWnd = hDlg;
+                       }
+                       return TRUE;
+
+               case WM_COMMAND:
+                       {
+                               char str[1024],idstr[64];
+                               chanInfo.id.toStr(idstr);
+
+                               switch (LOWORD(wParam))
+                               {
+                                       case IDC_CONTACT:
+                                       {
+                                               sys->getURL(chanInfo.url);
+                                               return TRUE;
+                                       }
+                                       case IDC_DETAILS:
+                                       {
+                                               sprintf(str,"admin?page=chaninfo&id=%s&relay=%d",idstr,chanInfoIsRelayed);
+                                               sys->callLocalURL(str,servMgr->serverHost.port);
+                                               return TRUE;
+                                       }
+                                       case IDC_KEEP:
+                                       {
+                                               Channel *ch = chanMgr->findChannelByID(chanInfo.id);
+                                               if (ch)
+                                                       ch->stayConnected = SendDlgItemMessage(hDlg, IDC_KEEP,BM_GETCHECK, 0, 0) == BST_CHECKED;;
+                                               return TRUE;
+                                       }
+
+
+                                       case IDC_PLAY:
+                                       {
+                                               chanMgr->findAndPlayChannel(chanInfo,false);
+                                               return TRUE;
+                                       }
+
+                               }
+                       }
+                       break;
+
+               case WM_CLOSE:
+                       if (winDistinctionNT)
+                               EndDialog(hDlg, 0);
+                       else
+                               DestroyWindow(hDlg); //JP-Patch
+                       break;
+
+               case WM_ACTIVATE:
+                       if (LOWORD(wParam) == WA_INACTIVE)
+                               if (winDistinctionNT)
+                                       EndDialog(hDlg, 0);
+                               else
+                                       DestroyWindow(hDlg); //JP-Patch
+                       break;
+               case WM_DESTROY:
+                       chWnd = NULL;
+                       break;
+
+
+       }
+    return FALSE;
+}
diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.h b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.h
new file mode 100644 (file)
index 0000000..ad59a96
--- /dev/null
@@ -0,0 +1,65 @@
+
+// ------------------------------------------------
+// File : simple.h
+// Date: 4-apr-2002
+// Author: giles
+//             
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#if !defined(AFX_SIMPLE_H__F2E64B1B_62DE_473C_A6B6_E7826D41E0FA__INCLUDED_)
+#define AFX_SIMPLE_H__F2E64B1B_62DE_473C_A6B6_E7826D41E0FA__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include "resource.h"
+
+// ---------------------------------
+class MyPeercastInst : public PeercastInstance
+{
+public:
+       virtual Sys * APICALL createSys();
+};
+// ---------------------------------
+class MyPeercastApp : public PeercastApplication
+{
+public:
+       MyPeercastApp ()
+       {
+               //logFile.openWriteReplace("log.txt");
+       }
+
+       virtual const char * APICALL getPath();
+
+       virtual const char * APICALL getIniFilename();
+       virtual const char *APICALL getClientTypeOS();
+       virtual void    APICALL openLogFile(); //JP-EX
+       virtual void    APICALL getDirectory(); //JP-EX
+       virtual bool    APICALL clearTemp(); //JP-EX
+       virtual void APICALL printLog(LogBuffer::TYPE t, const char *str);
+
+       virtual void    APICALL updateSettings();
+       virtual void    APICALL notifyMessage(ServMgr::NOTIFY_TYPE, const char *);
+
+       virtual void    APICALL channelStart(ChanInfo *);
+       virtual void    APICALL channelStop(ChanInfo *);
+       virtual void    APICALL channelUpdate(ChanInfo *);
+
+       FileStream      logFile;
+
+};
+
+
+#endif // !defined(AFX_SIMPLE_H__F2E64B1B_62DE_473C_A6B6_E7826D41E0FA__INCLUDED_)
diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.rc b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.rc
new file mode 100644 (file)
index 0000000..311c8fc
--- /dev/null
@@ -0,0 +1,379 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+// Generated Help ID header file
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "resource.hm"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+#include "resource.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// \83j\83\85\81[\83g\83\89\83\8b (\83V\83X\83e\83\80\95W\8f\80) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUSD)
+#ifdef _WIN32
+LANGUAGE LANG_NEUTRAL, SUBLANG_SYS_DEFAULT
+#pragma code_page(932)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_TRAYMENU MENU 
+BEGIN
+    POPUP "popup"
+    BEGIN
+        MENUITEM "\8fî\95ñ",                        ID_POPUP_ABOUT
+        MENUITEM "\83w\83\8b\83v",                      ID_POPUP_HELP
+        MENUITEM SEPARATOR
+        POPUP "\83|\83b\83v\83A\83b\83v\83\81\83b\83Z\81[\83W"
+        BEGIN
+            MENUITEM "PeerCast",                    ID_POPUP_SHOWMESSAGES_PEERCAST
+
+            MENUITEM "\94z\90M\8eÒ",                      ID_POPUP_SHOWMESSAGES_BROADCASTERS
+
+            MENUITEM "\83g\83\89\83b\83N\8fî\95ñ",                ID_POPUP_SHOWMESSAGES_TRACKINFO
+
+            MENUITEM "\83A\83b\83v\83f\81[\83g\8fî\95ñ",            ID_POPUP_POPUPMESSAGES_UPGRADEALERTS
+            , CHECKED, GRAYED
+        END
+        POPUP "\8d\82\93x"
+        BEGIN
+            MENUITEM "\8fî\95ñ",                        ID_POPUP_ADVANCED_INFORMATION
+
+            MENUITEM "\83\8a\83\8c\81[\83`\83\83\83\93\83l\83\8b",            ID_POPUP_ADVANCED_RELAYEDCHANNELS
+
+            MENUITEM "\94z\90M",                        ID_POPUP_ADVANCED_BROADCAST
+
+            MENUITEM "\83R\83l\83N\83V\83\87\83\93",                ID_POPUP_CONNECTIONS
+            MENUITEM "\83\8d\83O",                        ID_POPUP_ADVANCED_VIEWLOG
+
+            MENUITEM "\90Ý\92è",                        ID_POPUP_SETTINGS
+            MENUITEM "GUI\82ð\8aJ\82­",                   ID_POPUP_ADVANCED_SHOWGUI
+
+        END
+        POPUP "\92Ç\89Á\90Ý\92è"
+        BEGIN
+            MENUITEM "\8fI\97¹\8e\9e\81A\95\\8e¦\88Ê\92u\82ð\95Û\91¶",      ID_POPUP_SAVE_GUI_POS
+            , CHECKED
+            MENUITEM "\8dÄ\90Ú\91±\8e\9e\89º\97¬\88Û\8e\9d",            ID_POPUP_KEEP_DOWNSTREAMS
+            , CHECKED
+        END
+        MENUITEM SEPARATOR
+        POPUP "\8fI\97¹"
+        BEGIN
+            MENUITEM "\82Í\82¢",                        ID_POPUP_EXIT_CONFIRM
+            MENUITEM "\82¢\82¢\82¦",                      ID_POPUP_EXIT_NO
+        END
+    END
+END
+
+IDR_LTRAYMENU MENU 
+BEGIN
+    POPUP "popup"
+    BEGIN
+        MENUITEM SEPARATOR
+        MENUITEM "\83C\83G\83\8d\81[\83y\81[\83W",              ID_POPUP_YELLOWPAGES
+        POPUP "\83C\83G\83\8d\81[\83y\81[\83W"
+        BEGIN
+            MENUITEM "AAA",                         ID_POPUP_YELLOWPAGES1
+            MENUITEM "BBB",                         ID_POPUP_YELLOWPAGES2
+        END
+    END
+END
+
+IDR_GUIMENU MENU
+BEGIN
+    POPUP "popup"
+    BEGIN
+        MENUITEM SEPARATOR
+        MENUITEM "\90§\8cä",                          ID_POPUP_YELLOWPAGES
+        POPUP "\90§\8cä"
+        BEGIN
+            MENUITEM "AAA",                         ID_POPUP_YELLOWPAGES1
+            MENUITEM "BBB",                         ID_POPUP_YELLOWPAGES2
+        END
+    END
+END
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_MAINWINDOW DIALOGEX 0, 0, 298, 341
+STYLE DS_SETFONT | DS_CENTER | WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU | 
+    WS_THICKFRAME
+EXSTYLE WS_EX_APPWINDOW
+CAPTION "PeerCast"
+FONT 9, "MS UI Gothic", 0, 0, 0x1
+BEGIN
+    LISTBOX         IDC_LIST1,3,291,291,43,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | 
+                    WS_TABSTOP
+    CONTROL         "\97L\8cø",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | 
+                    WS_TABSTOP,9,29,60,20,WS_EX_TRANSPARENT
+    EDITTEXT        IDC_EDIT1,127,18,47,12,ES_AUTOHSCROLL
+    RTEXT           "\83|\81[\83g :",IDC_STATIC,107,20,18,8
+    LISTBOX         IDC_LIST2,3,206,291,71,LBS_OWNERDRAWFIXED | 
+                    LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+    LTEXT           "\83\8d\83O",IDC_STATIC_LOG,3,282,13,8
+    LTEXT           "\83R\83l\83N\83V\83\87\83\93",IDC_STATIC_CONNECTION,3,184,40,8
+    GROUPBOX        "",IDC_STATIC,3,4,291,49
+    PUSHBUTTON      "\83N\83\8a\83A",IDC_BUTTON1,35,279,25,11
+    LISTBOX         IDC_LIST3,3,81,291,67,LBS_OWNERDRAWFIXED | 
+                    LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+    PUSHBUTTON      "\90Ø\92f",IDC_BUTTON5,67,65,43,13
+    GROUPBOX        "\83\8a\83\8c\81[",IDC_GROUPBOX_RELAY,3,54,291,96
+    EDITTEXT        IDC_EDIT3,127,34,47,12,ES_PASSWORD | ES_AUTOHSCROLL
+    RTEXT           "\83p\83X\83\8f\81[\83h :",IDC_STATIC,89,36,36,8
+    CONTROL         "\83f\83o\83b\83O",IDC_LOGDEBUG,"Button",BS_AUTOCHECKBOX | 
+                    BS_PUSHLIKE | WS_TABSTOP,127,279,32,11
+    CONTROL         "\83l\83b\83g\83\8f\81[\83N",IDC_LOGNETWORK,"Button",BS_AUTOCHECKBOX | 
+                    BS_PUSHLIKE | WS_TABSTOP,185,279,35,11
+    CONTROL         "\83G\83\89\81[",IDC_LOGERRORS,"Button",BS_AUTOCHECKBOX | 
+                    BS_PUSHLIKE | WS_TABSTOP,159,279,25,11
+    CONTROL         "\92â\8e~",IDC_CHECK9,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | 
+                    WS_TABSTOP,60,279,30,11
+    PUSHBUTTON      "\8dÄ\90¶",IDC_BUTTON8,10,65,22,13
+    CONTROL         "\83`\83\83\83\93\83l\83\8b",IDC_LOGCHANNELS,"Button",BS_AUTOCHECKBOX | 
+                    BS_PUSHLIKE | WS_TABSTOP,221,279,35,11
+    PUSHBUTTON      "\8dÄ\90Ú\91±",IDC_BUTTON3,41,65,24,13
+    EDITTEXT        IDC_EDIT9,33,159,261,14,ES_AUTOHSCROLL
+    CONTROL         "DJ",IDC_CHECK11,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | 
+                    WS_TABSTOP,5,160,23,12
+    RTEXT           "\8dÅ\91å\83\8a\83\8c\81[\90\94 :",IDC_STATIC,203,20,40,8
+    EDITTEXT        IDC_MAXRELAYS,248,18,40,14,ES_AUTOHSCROLL | ES_NUMBER
+    PUSHBUTTON      "\83L\81[\83v",IDC_BUTTON9,112,65,24,13
+    PUSHBUTTON      "\90Ø\92f",IDC_BUTTON6,47,179,43,13
+    LTEXT           "Peercast-VP",IDC_STATIC,21,14,39,8
+END
+
+IDD_CHANINFO DIALOGEX 0, 0, 184, 207
+STYLE DS_SETFONT | DS_SETFOREGROUND | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_TOOLWINDOW
+CAPTION "Channel Information"
+FONT 9, "MS UI Gothic", 400, 0, 0x80
+BEGIN
+    LTEXT           "\96¼\91O:",IDC_STATIC,7,8,24,9
+    EDITTEXT        IDC_EDIT_NAME,7,18,170,21,ES_MULTILINE | ES_READONLY | 
+                    NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE
+    LTEXT           "\93à\97e:",IDC_STATIC,7,79,93,9
+    EDITTEXT        IDC_EDIT_PLAYING,8,90,170,21,ES_MULTILINE | ES_READONLY | 
+                    NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE
+    LTEXT           "DJ \83\81\83b\83Z\81[\83W:",IDC_STATIC,7,117,41,9
+    EDITTEXT        IDC_EDIT_MESSAGE,8,128,170,21,ES_MULTILINE | ES_READONLY | 
+                    NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE
+    PUSHBUTTON      "URL",IDC_CONTACT,7,185,34,15,0,0,HIDC_CONTACT
+    LTEXT           "\8fÚ\8d×:",IDC_STATIC,7,43,67,8
+    EDITTEXT        IDC_EDIT_DESC,8,53,170,21,ES_MULTILINE | ES_READONLY | 
+                    NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE
+    RTEXT           "\8c`\8e®",IDC_FORMAT,69,80,107,8
+    LTEXT           "\83W\83\83\83\93\83\8b:",IDC_STATIC,63,5,22,8
+    EDITTEXT        IDC_EDIT_GENRE,87,3,90,12,ES_AUTOHSCROLL | ES_READONLY | 
+                    NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE
+    CONTROL         "\83L\81[\83v",IDC_KEEP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+                    144,188,33,10
+    LTEXT           "\83X\83e\81[\83^\83X:",IDC_STATIC,7,153,41,9
+    EDITTEXT        IDC_EDIT_STATUS,8,163,82,12,ES_READONLY | NOT WS_BORDER | 
+                    NOT WS_TABSTOP,WS_EX_STATICEDGE
+    PUSHBUTTON      "\8dÄ\90¶",IDC_PLAY,56,185,34,15
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO 
+BEGIN
+    IDD_MAINWINDOW, DIALOG
+    BEGIN
+        LEFTMARGIN, 3
+        RIGHTMARGIN, 294
+        TOPMARGIN, 3
+        BOTTOMMARGIN, 336
+    END
+
+    IDD_CHANINFO, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 177
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 200
+    END
+END
+#endif    // APSTUDIO_INVOKED
+
+#endif    // \83j\83\85\81[\83g\83\89\83\8b (\83V\83X\83e\83\80\95W\8f\80) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// \89p\8cê (\95Ä\8d\91) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDC_SIMPLE MENU 
+BEGIN
+    POPUP "&File"
+    BEGIN
+        MENUITEM "E&xit",                       IDM_EXIT
+    END
+    POPUP "&Help"
+    BEGIN
+        MENUITEM "&About ...",                  IDM_ABOUT
+    END
+    POPUP "Settings"
+    BEGIN
+        MENUITEM "GUI",                         IDM_SETTINGS_GUI
+    END
+END
+
+IDR_VERMENU MENU 
+BEGIN
+    POPUP "popup"
+    BEGIN
+        MENUITEM "Please upgrade PeerCast. Click here to download.", 
+                                                ID_POPUP_UPGRADE
+    END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_ABOUTBOX DIALOG  22, 17, 163, 59
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_CAPTION | 
+    WS_SYSMENU
+CAPTION "About"
+FONT 8, "System"
+BEGIN
+    ICON            IDI_SIMPLE,IDC_MYICON,14,9,20,20
+    LTEXT           "PeerCast",IDC_ABOUTVER,43,9,103,8,SS_NOPREFIX
+    LTEXT           "Copyright (C) 2005",IDC_STATIC,43,22,119,8
+    PUSHBUTTON      "OK",IDOK,134,40,24,12,WS_GROUP
+    PUSHBUTTON      "www.peercast.org",IDC_BUTTON1,42,40,66,12
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO 
+BEGIN
+    IDD_ABOUTBOX, DIALOG
+    BEGIN
+        BOTTOMMARGIN, 58
+    END
+END
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_SIMPLE              ICON                    "Simple.ICO"
+IDI_SMALL2              ICON                    "small1.ico"
+IDI_SMALL               ICON                    "small3.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDC_SIMPLE ACCELERATORS 
+BEGIN
+    "?",            IDM_ABOUT,              ASCII,  ALT
+    "/",            IDM_ABOUT,              ASCII,  ALT
+END
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+2 TEXTINCLUDE 
+BEGIN
+    "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+    "#include ""windows.h""\r\n"
+    "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+    "#include ""resource.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+1 TEXTINCLUDE 
+BEGIN
+    "resource.h\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE 
+BEGIN
+    IDS_APP_TITLE           "PeerCast"
+END
+
+#endif    // \89p\8cê (\95Ä\8d\91) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.vcproj b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.vcproj
new file mode 100644 (file)
index 0000000..2241604
--- /dev/null
@@ -0,0 +1,906 @@
+<?xml version="1.0" encoding="shift_jis"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="Simple"
+       ProjectGUID="{7D4833CE-1286-4587-9470-52E098B29C12}"
+       RootNamespace="Simple"
+       SccProjectName="&quot;$/PeerCast.root/PeerCast&quot;, JCAAAAAA"
+       SccLocalPath="..\..\.."
+       SccProvider="MSSCCI:Microsoft Visual SourceSafe"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Private Debug|Win32"
+                       OutputDirectory=".\Simple___Win32_Private_Debug"
+                       IntermediateDirectory=".\Simple___Win32_Private_Debug"
+                       ConfigurationType="1"
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+                       UseOfMFC="0"
+                       ATLMinimizesCRunTimeLibraryUsage="false"
+                       CharacterSet="2"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                               PreprocessorDefinitions="_DEBUG"
+                               MkTypLibCompatible="true"
+                               SuppressStartupBanner="true"
+                               TargetEnvironment="1"
+                               TypeLibraryName=".\Simple___Win32_Private_Debug/Simple.tlb"
+                               HeaderFileName=""
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="0"
+                               AdditionalIncludeDirectories="../../../core,../../../core/common"
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;PRIVATE_BROADCASTER"
+                               MinimalRebuild="true"
+                               BasicRuntimeChecks="3"
+                               RuntimeLibrary="1"
+                               PrecompiledHeaderFile=".\Simple___Win32_Private_Debug/Simple.pch"
+                               AssemblerListingLocation=".\Simple___Win32_Private_Debug/"
+                               ObjectFile=".\Simple___Win32_Private_Debug/"
+                               ProgramDataBaseFileName=".\Simple___Win32_Private_Debug/"
+                               BrowseInformation="1"
+                               WarningLevel="3"
+                               SuppressStartupBanner="true"
+                               DebugInformationFormat="4"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="_DEBUG"
+                               Culture="1033"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="ws2_32.lib odbc32.lib odbccp32.lib"
+                               OutputFile="Debug/PeerCast.exe"
+                               LinkIncremental="1"
+                               SuppressStartupBanner="true"
+                               GenerateDebugInformation="true"
+                               ProgramDatabaseFile=".\Simple___Win32_Private_Debug/PeerCast.pdb"
+                               SubSystem="2"
+                               TargetMachine="1"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                               SuppressStartupBanner="true"
+                               OutputFile=".\Simple___Win32_Private_Debug/Simple.bsc"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                               Description="Copy exe to program files"
+                               CommandLine="copy           debug\peercast.exe           &quot;c:\program files\peercast&quot;"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       OutputDirectory=".\Release"
+                       IntermediateDirectory=".\Release"
+                       ConfigurationType="1"
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+                       UseOfMFC="0"
+                       ATLMinimizesCRunTimeLibraryUsage="false"
+                       CharacterSet="2"
+                       WholeProgramOptimization="0"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                               PreprocessorDefinitions="NDEBUG"
+                               MkTypLibCompatible="true"
+                               SuppressStartupBanner="true"
+                               TargetEnvironment="1"
+                               TypeLibraryName=".\Release/Simple.tlb"
+                               HeaderFileName=""
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="2"
+                               InlineFunctionExpansion="1"
+                               EnableIntrinsicFunctions="true"
+                               FavorSizeOrSpeed="0"
+                               AdditionalIncludeDirectories="../../../core,../../../core/common"
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
+                               StringPooling="true"
+                               RuntimeLibrary="0"
+                               EnableFunctionLevelLinking="true"
+                               PrecompiledHeaderFile=".\Release/Simple.pch"
+                               AssemblerListingLocation=".\Release/"
+                               ObjectFile=".\Release/"
+                               ProgramDataBaseFileName=".\Release/"
+                               BrowseInformation="1"
+                               WarningLevel="3"
+                               SuppressStartupBanner="true"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="NDEBUG"
+                               Culture="1033"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="ws2_32.lib gdiplus.lib comsuppw.lib Wininet.lib corelib.lib"
+                               OutputFile="Release/PeerCast.exe"
+                               LinkIncremental="1"
+                               SuppressStartupBanner="true"
+                               AdditionalLibraryDirectories="&quot;C:\Visual Studio Projects\PeCa-IMAS7651\core\win32\lib\Release&quot;"
+                               ProgramDatabaseFile=".\Release/PeerCast.pdb"
+                               SubSystem="2"
+                               TargetMachine="1"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                               SuppressStartupBanner="true"
+                               OutputFile=".\Release/Simple.bsc"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                               Description="Copy exe to pimp &amp; program files"
+                               CommandLine="copy                   release\peercast.exe                   &quot;c:\program files\peercast&quot;&#x0D;&#x0A;copy                   release\peercast.exe                   ..\pimp\&#x0D;&#x0A;"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Private Release|Win32"
+                       OutputDirectory=".\Simple___Win32_Private_Release"
+                       IntermediateDirectory=".\Simple___Win32_Private_Release"
+                       ConfigurationType="1"
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+                       UseOfMFC="0"
+                       ATLMinimizesCRunTimeLibraryUsage="false"
+                       CharacterSet="2"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                               PreprocessorDefinitions="NDEBUG"
+                               MkTypLibCompatible="true"
+                               SuppressStartupBanner="true"
+                               TargetEnvironment="1"
+                               TypeLibraryName=".\Simple___Win32_Private_Release/Simple.tlb"
+                               HeaderFileName=""
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="2"
+                               InlineFunctionExpansion="1"
+                               AdditionalIncludeDirectories="../../../core,../../../core/common"
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;PRIVATE_BROADCASTER"
+                               StringPooling="true"
+                               RuntimeLibrary="0"
+                               EnableFunctionLevelLinking="true"
+                               PrecompiledHeaderFile=".\Simple___Win32_Private_Release/Simple.pch"
+                               AssemblerListingLocation=".\Simple___Win32_Private_Release/"
+                               ObjectFile=".\Simple___Win32_Private_Release/"
+                               ProgramDataBaseFileName=".\Simple___Win32_Private_Release/"
+                               BrowseInformation="1"
+                               WarningLevel="3"
+                               SuppressStartupBanner="true"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="NDEBUG"
+                               Culture="1033"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="ws2_32.lib odbc32.lib odbccp32.lib"
+                               OutputFile="PrivRelease/PeerCast.exe"
+                               LinkIncremental="1"
+                               SuppressStartupBanner="true"
+                               ProgramDatabaseFile=".\Simple___Win32_Private_Release/PeerCast.pdb"
+                               SubSystem="2"
+                               TargetMachine="1"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                               SuppressStartupBanner="true"
+                               OutputFile=".\Simple___Win32_Private_Release/Simple.bsc"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                               Description="Copy exe to pimp &amp; program files"
+                               CommandLine="copy                   release\peercast.exe                   &quot;c:\program files\peercast&quot;&#x0D;&#x0A;copy                   release\peercast.exe                   ..\pimp\&#x0D;&#x0A;"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Debug|Win32"
+                       OutputDirectory=".\Debug"
+                       IntermediateDirectory=".\Debug"
+                       ConfigurationType="1"
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+                       UseOfMFC="0"
+                       ATLMinimizesCRunTimeLibraryUsage="false"
+                       CharacterSet="2"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                               PreprocessorDefinitions="_DEBUG"
+                               MkTypLibCompatible="true"
+                               SuppressStartupBanner="true"
+                               TargetEnvironment="1"
+                               TypeLibraryName=".\Debug/Simple.tlb"
+                               HeaderFileName=""
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="0"
+                               AdditionalIncludeDirectories="../../../core,../../../core/common"
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
+                               MinimalRebuild="true"
+                               BasicRuntimeChecks="3"
+                               RuntimeLibrary="1"
+                               PrecompiledHeaderFile=".\Debug/Simple.pch"
+                               AssemblerListingLocation=".\Debug/"
+                               ObjectFile=".\Debug/"
+                               ProgramDataBaseFileName=".\Debug/"
+                               BrowseInformation="1"
+                               WarningLevel="3"
+                               SuppressStartupBanner="true"
+                               DebugInformationFormat="4"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="_DEBUG"
+                               Culture="1033"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="ws2_32.lib gdiplus.lib comsuppw.lib Wininet.lib corelib.lib"
+                               OutputFile="Debug/PeerCast.exe"
+                               LinkIncremental="1"
+                               SuppressStartupBanner="true"
+                               AdditionalLibraryDirectories="&quot;C:\Visual Studio Projects\PeCa-IMAS7651\core\win32\lib\Debug&quot;"
+                               GenerateDebugInformation="true"
+                               ProgramDatabaseFile=".\Debug/PeerCast.pdb"
+                               SubSystem="2"
+                               HeapReserveSize="4194304"
+                               TargetMachine="1"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                               SuppressStartupBanner="true"
+                               OutputFile=".\Debug/Simple.bsc"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                               Description="Copy exe to program files"
+                               CommandLine="copy           debug\peercast.exe           &quot;c:\program files\peercast&quot;"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="Source Files"
+                       Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+                       >
+                       <File
+                               RelativePath="chkMemoryLeak.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="gui.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\..\core\common\identify_encoding.c"
+                               >
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="Simple.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="Simple.rc"
+                               >
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCResourceCompilerTool"
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCResourceCompilerTool"
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCResourceCompilerTool"
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCResourceCompilerTool"
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="StdAfx.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                               UsePrecompiledHeader="1"
+                                               PrecompiledHeaderThrough="stdafx.h"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                               UsePrecompiledHeader="1"
+                                               PrecompiledHeaderThrough="stdafx.h"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                               UsePrecompiledHeader="1"
+                                               PrecompiledHeaderThrough="stdafx.h"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                               UsePrecompiledHeader="1"
+                                               PrecompiledHeaderThrough="stdafx.h"
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\..\core\common\utf8.c"
+                               >
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+               </Filter>
+               <Filter
+                       Name="Header Files"
+                       Filter="h;hpp;hxx;hm;inl"
+                       >
+                       <File
+                               RelativePath="chkMemoryLeak.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="gui.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\..\core\common\identify_encoding.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="resource.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="Simple.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="StdAfx.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\..\core\common\utf8.h"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="Resource Files"
+                       Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+                       >
+                       <File
+                               RelativePath="Simple.ico"
+                               >
+                       </File>
+                       <File
+                               RelativePath="small.ico"
+                               >
+                       </File>
+                       <File
+                               RelativePath="small1.ico"
+                               >
+                       </File>
+                       <File
+                               RelativePath="small3.ico"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="Linux"
+                       >
+                       <File
+                               RelativePath="..\..\linux\main.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\linux\makefile"
+                               >
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCustomBuildTool"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCustomBuildTool"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCustomBuildTool"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCustomBuildTool"
+                                       />
+                               </FileConfiguration>
+                       </File>
+               </Filter>
+               <Filter
+                       Name="OSX"
+                       >
+                       <File
+                               RelativePath="..\..\osx\main.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Private Debug|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Private Release|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories=""
+                                               PreprocessorDefinitions=""
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\osx\makefile"
+                               >
+                       </File>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.vcproj.vspscc b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/Simple.vcproj.vspscc
new file mode 100644 (file)
index 0000000..f30e03c
--- /dev/null
@@ -0,0 +1,10 @@
+""
+{
+"FILE_VERSION" = "9237"
+"ENLISTMENT_CHOICE" = "NEVER"
+"PROJECT_FILE_RELATIVE_PATH" = "relative:ui\\win32\\simple"
+"NUMBER_OF_EXCLUDED_FILES" = "0"
+"ORIGINAL_PROJECT_FILE_PATH" = ""
+"NUMBER_OF_NESTED_PROJECTS" = "0"
+"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
+}
diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/StdAfx.cpp b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/StdAfx.cpp
new file mode 100644 (file)
index 0000000..fe41f64
--- /dev/null
@@ -0,0 +1,9 @@
+// stdafx.cpp : source file that includes just the standard includes
+//     Simple.pch will be the pre-compiled header
+//     stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
+
diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/StdAfx.h b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/StdAfx.h
new file mode 100644 (file)
index 0000000..1e47eff
--- /dev/null
@@ -0,0 +1,32 @@
+// stdafx.h : include file for standard system include files,
+//  or project specific include files that are used frequently, but
+//      are changed infrequently
+//
+
+#if !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_)
+#define AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#define WIN32_LEAN_AND_MEAN            // Exclude rarely-used stuff from Windows headers
+
+
+// Windows Header Files:
+#include <windows.h>
+
+// C RunTime Header Files
+#include <stdlib.h>
+#include <malloc.h>
+#include <memory.h>
+#include <tchar.h>
+
+// Local Header Files
+
+// TODO: reference additional headers your program requires here
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_)
diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/chkMemoryLeak.cpp b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/chkMemoryLeak.cpp
new file mode 100644 (file)
index 0000000..4c8df0d
--- /dev/null
@@ -0,0 +1,21 @@
+#ifdef _DEBUG
+//#include "stdafx.h"
+#include "chkMemoryLeak.h"
+
+#ifdef __AFXWIN_H__            // MFC\82Ì\83E\83B\83\93\83h\83E\82ð\8eg\82¤\8fê\8d\87\82É\8cÀ\92è\82µ\82Ä\82¢\82Ü\82·
+#else
+ #if defined(_DEBUG)
+ #define __chkMemoryLeak_H__
+ void* operator new(size_t size, const char *filename, int linenumber)
+ {
+   return _malloc_dbg(size, _NORMAL_BLOCK, filename, linenumber);
+ }
+ void   operator delete(void * _P, const char *filename, int linenumber)
+ {
+   _free_dbg(_P, _NORMAL_BLOCK);
+   return;
+ }
+
+ #endif
+#endif
+#endif
diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/chkMemoryLeak.h b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/chkMemoryLeak.h
new file mode 100644 (file)
index 0000000..aa47729
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _CHKMEMORYLEAK_H
+#define _CHKMEMORYLEAK_H
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#ifdef _DEBUG
+  #define _CRTDBG_MAP_ALLOC
+
+  #define  SET_CRT_DEBUG_FIELD(a)   _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
+  #define  CLEAR_CRT_DEBUG_FIELD(a) _CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
+
+  void*  operator new(size_t size, const char *filename, int linenumber);
+  void   operator delete(void * _P, const char *filename, int linenumber);
+#else
+  #define  SET_CRT_DEBUG_FIELD(a)   ((void) 0)
+  #define  CLEAR_CRT_DEBUG_FIELD(a) ((void) 0)
+#endif
+
+#include <crtdbg.h>
+
+#include <malloc.h>
+
+#endif
diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/gui.cpp b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/gui.cpp
new file mode 100644 (file)
index 0000000..1ef53b1
--- /dev/null
@@ -0,0 +1,1853 @@
+// ------------------------------------------------
+// File : gui.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc: 
+//             Windows front end GUI, PeerCast core is not dependant on any of this. 
+//             Its very messy at the moment, but then again Windows UI always is.
+//             I really don`t like programming win32 UI.. I want my borland back..
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#define _WIN32_WINNT 0x0500
+
+#include <windows.h>
+#include "stdio.h"
+#include "string.h"
+#include "stdarg.h"
+#include "resource.h"
+#include "socket.h"
+#include "win32/wsys.h"
+#include "servent.h"
+#include "win32/wsocket.h"
+#include "inifile.h"
+#include "gui.h"
+#include "servmgr.h"
+#include "peercast.h"
+#include "simple.h"
+#include "gdiplus.h"
+#include "commctrl.h"
+#include "locale.h"
+#include "stats.h"
+#include "socket.h"
+#include "wininet.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+ThreadInfo guiThread;
+bool shownChannels=false;
+WINDOWPLACEMENT winPlace;
+bool guiFlg = false;
+
+using namespace Gdiplus;
+
+#include <comdef.h>
+
+void APICALL MyPeercastApp ::printLog(LogBuffer::TYPE t, const char *str)
+{
+/*     ADDLOG(str,logID,true,NULL,t);
+       if (logFile.isOpen())
+       {
+               logFile.writeLine(str);
+               logFile.flush();
+       }*/
+}
+
+void APICALL MyPeercastApp::updateSettings()
+{
+//     setControls(true);
+}
+
+Gdiplus::Bitmap bmpBack(800,600,PixelFormat24bppRGB);
+UINT backWidth;
+UINT backHeight;
+
+Gdiplus::Image *backImage;
+Gdiplus::Bitmap *backBmp;
+Gdiplus::Graphics *backGra;
+
+Gdiplus::Image *img_idle;
+Gdiplus::Image *img_connect;
+Gdiplus::Image *img_conn_ok;
+Gdiplus::Image *img_conn_full;
+Gdiplus::Image *img_conn_over;
+Gdiplus::Image *img_conn_ok_skip;
+Gdiplus::Image *img_conn_full_skip;
+Gdiplus::Image *img_conn_over_skip;
+Gdiplus::Image *img_error;
+Gdiplus::Image *img_broad_ok;
+Gdiplus::Image *img_broad_full;
+
+UINT winWidth=0;
+UINT winHeight=0;
+
+static HWND hTree;
+extern HINSTANCE hInst;
+extern HWND guiWnd;
+extern Stats stats;
+
+WLock sd_lock;
+WLock ChannelDataLock;
+WLock MakeBackLock;
+ChannelData *channelDataTop = NULL;
+
+extern bool gbGetFile;
+extern bool gbStart;
+extern time_t gtGetFile;
+extern time_t gtStartTime;
+ThreadInfo gtiStart;
+ThreadInfo gtiGetFile;
+static char *data1URL = "http://www.idolmaster.jp/download/images/wallpaper/imas360p_800.jpg";
+static char *data2URL = "http://www.xbox.com/NR/rdonlyres/CAB05E2F-3051-409B-A4C8-830167C1C138/0/wpr0701idolmasterw120001.jpg";
+HWND ghStart;
+
+bool gbDispTop = false;
+bool gbAllOpen = false;
+
+THREAD_PROC FestivalStart(ThreadInfo *thread);
+
+THREAD_PROC GetHostName(ThreadInfo *thread){
+       IdData *id = (IdData*)(thread->data);
+
+       HOSTENT *he;
+       unsigned int ip;
+       bool flg = TRUE;
+
+       ChannelDataLock.on();
+       ip = htonl(id->getIpAddr());
+
+       for (int i=0; i<5 && flg; i++){
+               he = gethostbyaddr((char *)&ip,sizeof(ip),AF_INET);
+
+               ChannelData* cd = channelDataTop;
+               if (he)
+               {
+                       while(cd){
+                               if (cd->setName(id->getServentId(), he->h_name)){
+                                       flg = FALSE;
+                                       break;
+                               }
+                               cd = cd->getNextData();
+                       }
+               }
+//             ::delete id;
+               ChannelDataLock.off();
+               sys->sleep(1000);
+       }
+
+
+       return 0;
+}
+
+bool DownloadFile(LPCTSTR URL, LPCTSTR local){
+       char header[] = "Accept: */*\r\n\r\n";
+       char buf[4096];
+
+       FileStream f;
+       HINTERNET hInternet;
+       HINTERNET hConnect;
+
+       try{
+               f.openWriteReplace(local);
+       }catch(StreamException &e){
+               return false;
+       }
+
+       hInternet = ::InternetOpen(NULL, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
+       if (hInternet == NULL){
+               return false;
+       }
+
+       hConnect = ::InternetOpenUrl(hInternet, URL, header, strlen(header), INTERNET_FLAG_DONT_CACHE, 0);
+       if (hConnect == NULL){
+               ::InternetCloseHandle(hInternet);
+               return false;
+       }
+
+       while(1){
+               sys->sleep(0);
+               DWORD dwReadSize;
+               BOOL ret = ::InternetReadFile(hConnect, buf, 4096, &dwReadSize);
+               if (ret){
+                       if (dwReadSize == 0){
+                               break;
+                       }
+                       try{
+                               f.write(buf, dwReadSize);
+                               continue;
+                       } catch(StreamException e){
+                       }
+                       f.close();
+                       ::InternetCloseHandle(hConnect);
+                       ::InternetCloseHandle(hInternet);
+                       return false;
+               }
+       }
+
+       f.flush();
+       f.close();
+       ::InternetCloseHandle(hConnect);
+       ::InternetCloseHandle(hInternet);
+
+       return true;
+}
+
+THREAD_PROC GetInternetFile(ThreadInfo *thread){
+
+       DownloadFile(data1URL, "data1.jpg");
+       DownloadFile(data2URL, "data2.jpg");
+       return 0;
+}
+
+extern TCHAR szWindowClass3[];                                                         // The title bar text
+
+
+int drawSpeed(Graphics *gra, int posX, int posY){
+
+       // \91¬\93x\95\\8e¦\95\94\82Ì\94w\8ci\82ð\94\92\82­\82·\82é
+       SolidBrush b(Color(180,255,255,255));
+       backGra->FillRectangle(&b, posX, posY, 200, 14);
+       // \83t\83H\83\93\83g\90Ý\92è
+       Font font(L"\82l\82\82o\83S\83V\83b\83N",10);
+       // \95\8e\9a\90F
+       SolidBrush strBrush(Color::Black);
+       // \95\8e\9a\97ñ\8dì\90¬
+       char tmp[256];
+       sprintf(tmp, "R:%.1fkbps S:%.1fkbps", 
+               BYTES_TO_KBPS(stats.getPerSecond(Stats::BYTESIN)-stats.getPerSecond(Stats::LOCALBYTESIN)),
+               BYTES_TO_KBPS(stats.getPerSecond(Stats::BYTESOUT)-stats.getPerSecond(Stats::LOCALBYTESOUT)));
+       _bstr_t bstr(tmp);
+       // \95\8e\9a\95\\8e¦\94Í\88Í\8ew\92è
+       StringFormat format;
+       format.SetAlignment(StringAlignmentCenter);
+       RectF r((REAL)posX, (REAL)posY, (REAL)200, (REAL)14);
+       // \95\8e\9a\95`\89æ
+       gra->DrawString(bstr, -1, &font, r, &format, &strBrush);
+
+
+
+       return posY + 15;
+}
+
+void MakeBack(HWND hwnd, UINT x, UINT y){
+       MakeBackLock.on();
+
+       winWidth = x;
+       winHeight = y;
+
+       if (backGra){
+               ::delete backBmp;
+               ::delete backGra;
+       }
+
+       backBmp = ::new Bitmap(x,y);
+       backGra = ::new Graphics(backBmp);
+
+       // \91S\82Ä\94\92\82Å\93h\82è\82Â\82Ô\82µ
+       SolidBrush b(Color(255,255,255,255));
+       backGra->FillRectangle(&b, 0, 0, x, y);
+
+       backWidth = backImage->GetWidth();
+       backHeight = backImage->GetHeight();
+
+       // \94w\8ci\89æ\91\9c\82ð\95`\89æ
+       for (UINT xx = 0; xx < x/backWidth + 1; xx++){
+               for (UINT yy = 0; yy < y/backHeight + 1; yy++){
+                       UINT width,height;
+                       if (backWidth*(xx+1) > x){
+                               width = x % backWidth;
+                       } else {
+                               width = backWidth;
+                       }
+                       if (backHeight*(yy+1) > y){
+                               height = y % backHeight;
+                       } else {
+                               height = backHeight;
+                       }
+                       Rect r((INT)backWidth*xx, (INT)backHeight*yy, width, height);
+                       backGra->DrawImage(backImage, r, 0, 0, (INT)width, (INT)height, UnitPixel);
+               }
+       }
+
+       INT posX = 20;
+       INT posY = 20;
+
+       // \91¬\93x\95`\89æ
+       drawSpeed(backGra, winWidth-205, 5);
+
+       // \83`\83\83\83\93\83l\83\8b\8fî\95ñ\82ð\95`\89æ
+       ChannelDataLock.on();
+       ChannelData *cd = channelDataTop;
+       while(cd){
+               posY = cd->drawChannel(backGra, 20, posY);
+               cd = cd->getNextData();
+       }
+       ChannelDataLock.off();
+       MakeBackLock.off();
+}
+
+void MakeBack(HWND hwnd){
+       MakeBack(hwnd, winWidth, winHeight);
+       ::InvalidateRect(guiWnd, NULL, FALSE);
+}
+
+void ChannelData::setData(Channel *c){
+       String sjis;
+       sjis = c->getName();
+       sjis.convertTo(String::T_SJIS);
+
+       strncpy(name, sjis, 256);
+       name[256] = '\0';
+       channel_id = c->channel_id;
+       bitRate = c->info.bitrate;
+       lastPlayStart = c->info.lastPlayStart;
+       status = c->status;
+       totalListeners = c->totalListeners();
+       totalRelays = c->totalRelays();
+       localListeners = c->localListeners();
+       localRelays = c->localRelays();
+       stayConnected = c->stayConnected;
+       chDisp = c->chDisp;
+       bTracker = c->sourceHost.tracker;
+       lastSkipTime = c->lastSkipTime;
+       skipCount = c->skipCount;
+}
+
+int gW = 0;
+int gWS = 0;
+
+int ChannelData::drawChannel(Graphics *g, int x, int y){
+       REAL xx = x * 1.0f;
+       REAL yy = y * 1.0f;
+       ServentData* sd;
+
+       // \88Ê\92u\82ð\95Û\91
+       posX = x;
+       posY = y;
+
+       int w,h;
+
+       if (getWidth() == 0){
+               if (gW){
+                       w = gW;
+               } else {
+                       w = 400;
+               }
+       } else {
+               w = getWidth();
+               gW = w;
+       }
+
+       // \83`\83\83\83\93\83l\83\8b\95\\8e¦\95\94\82Ì\94w\8ci\82ð\93h\82é
+       if (isSelected()){
+               // \91I\91ð\92\86
+               SolidBrush b(Color(160,49,106,197));
+               g->FillRectangle(&b, x, y, w, 14);
+       } else {
+               // \94ñ\91I\91ð
+               SolidBrush b(Color(160,255,255,255));
+               g->FillRectangle(&b, x, y, w, 14);
+       }
+
+       // \83X\83e\81[\83^\83X\95\\8e¦
+       Gdiplus::Image *img = NULL;
+       unsigned int nowTime = sys->getTime();
+       switch(this->getStatus()){
+               case Channel::S_IDLE:
+                       img = img_idle;
+                       break;
+               case Channel::S_SEARCHING:
+               case Channel::S_CONNECTING:
+                       img = img_connect;
+                       break;
+               case Channel::S_RECEIVING:
+                       if ((skipCount > 2) && (lastSkipTime + 120 > nowTime)){
+                               if (chDisp.relay){
+                                       img = img_conn_ok_skip;
+                               } else {
+                                       if (chDisp.numRelays){
+                                               img = img_conn_full_skip;
+                                       } else {
+                                               img = img_conn_over_skip;
+                                       }
+                               }
+                       } else {
+                               if (chDisp.relay){
+                                       img = img_conn_ok;
+                               } else {
+                                       if (chDisp.numRelays){
+                                               img = img_conn_full;
+                                       } else {
+                                               img = img_conn_over;
+                                       }
+                               }
+                       }
+                       break;
+               case Channel::S_BROADCASTING:
+                       img = img_broad_ok;
+                       break;
+               case Channel::S_ERROR:
+                       img = img_error;
+                       break;
+               default:
+                       img = img_idle;
+                       break;
+       }
+       // \95`\89æ\8aî\93_
+       PointF origin(xx, yy);
+       // \83X\83e\81[\83^\83X\95\\8e¦\88Ê\92u
+       Rect img_rect((INT)origin.X, (INT)origin.Y + 1, img ? img->GetWidth() : 12, 12);
+       // \83X\83e\81[\83^\83X\95`\89æ
+       ImageAttributes att;
+//     att.SetColorKey(Color::White, Color::White, ColorAdjustTypeBitmap);
+       g->DrawImage(img, img_rect, 0, 0, img_rect.Width, 12, UnitPixel, &att);
+       // \8e\9f\82Ì\8aî\93_
+       origin.X += img_rect.Width;
+
+       // \83t\83H\83\93\83g\90Ý\92è
+       Gdiplus::Font font(L"\82l\82\82o\83S\83V\83b\83N",10);
+       // \95\8e\9a\90F
+       SolidBrush *strBrush;
+       if (servMgr->getFirewall() == ServMgr::FW_ON){
+               strBrush = ::new SolidBrush(Color::Red);
+       } else if (isTracker() && (getStatus() == Channel::S_RECEIVING)){
+               strBrush = ::new SolidBrush(Color::Green);
+       } else {
+               if (isSelected()){
+                       // \91I\91ð\92\86
+                       strBrush = ::new SolidBrush(Color::White);
+               } else {
+                       // \94ñ\91I\91ð
+                       strBrush = ::new SolidBrush(Color::Black);
+               }
+       }
+       // \83`\83\83\83\93\83l\83\8b\96¼\95\\8e¦
+       g->SetTextRenderingHint(TextRenderingHintAntiAlias);
+       _bstr_t bstr1(getName());
+       // \95\8e\9a\95`\89æ\94Í\88Í\8ew\92è
+       RectF r1(origin.X, origin.Y, 120.0f, 13.0f);
+       StringFormat format;
+       format.SetAlignment(StringAlignmentNear);
+       g->DrawString(bstr1, -1, &font, r1, &format, strBrush);
+       // \8e\9f\82Ì\8aî\93_
+       origin.X += r1.Width;
+
+       // \83\8a\83X\83i\81[\90\94/\83\8a\83\8c\81[\90\94\95\\8e¦
+       char tmp[256];
+       sprintf(tmp, "%d/%d - [%d/%d]", getTotalListeners(), getTotalRelays(), getLocalListeners(), getLocalRelays());
+       _bstr_t bstr2(tmp);
+       // \95\8e\9a\95\\8e¦\94Í\88Í\8ew\92è
+       RectF r2(origin.X, origin.Y, 100.0f, 13.0f);
+       format.SetAlignment(StringAlignmentCenter);
+       g->DrawString(bstr2, -1, &font, r2, &format, strBrush);
+       // \8e\9f\82Ì\8aî\93_
+       origin.X += r2.Width;
+
+       // bps\95\\8e¦
+       Font *f;
+       if (isStayConnected()){
+               f = ::new Font(L"Arial", 9.0f, FontStyleItalic|FontStyleBold, UnitPoint);
+       } else {
+               f = ::new Font(L"Arial", 9.0f);
+       }
+       sprintf(tmp, "%dkbps", getBitRate());
+       _bstr_t bstr3(tmp);
+       format.SetAlignment(StringAlignmentFar);
+       // \95\8e\9a\95\\8e¦\94Í\88Í\8ew\92è
+       RectF r3(origin.X, origin.Y, 80.0f, 13.0f);
+       g->DrawString(bstr3, -1, f, r3, &format, strBrush);
+       // \83t\83H\83\93\83g\8aJ\95ú
+       ::delete f;
+
+       // \8e\9f\82Ì\8aî\93_
+       origin.X += r3.Width;
+
+       // \83u\83\89\83V\8dí\8f\9c
+       ::delete strBrush;
+
+       
+       // Servent\95\\8e¦
+       if (!openFlg){
+               int count = getServentCount();
+               // Servent\95\\8e¦\95\94\82Ì\94w\8ci\82ð\94\92\82É\82·\82é
+               SolidBrush b(Color(160,255,255,255));
+               g->FillRectangle(&b, (INT)origin.X, (INT)origin.Y, 14*count, 14);
+
+               sd = serventDataTop;
+               int index = 0;
+               while(sd){
+                       SolidBrush *serventBrush;
+                       if (sd->getInfoFlg()){
+                               ChanHit *hit = sd->getChanHit();
+                               if (hit->firewalled){
+                                       SolidBrush bb(Color(180,255,0,0));
+                                       g->FillRectangle(&bb, (INT)origin.X + 14*index, (INT)origin.Y, 14, 14);
+                               }
+                               if (hit->relay){
+                                       // \83\8a\83\8c\81[\82n\82j
+                                       serventBrush = ::new SolidBrush(Color::Green);
+                               } else {
+                                       // \83\8a\83\8c\81[\95s\89Â
+                                       if (hit->numRelays){
+                                               // \83\8a\83\8c\81[\88ê\94t
+                                               serventBrush = ::new SolidBrush(Color::Blue);
+                                       } else {
+                                               // \83\8a\83\8c\81[\82È\82µ
+                                               serventBrush = ::new SolidBrush(Color::Purple);
+                                       }
+                               }
+                       } else {
+                               // \8fî\95ñ\82È\82µ
+                               serventBrush = ::new SolidBrush(Color::Black);
+                       }
+                       // \8el\8ap\95`\89æ
+                       backGra->FillRectangle(serventBrush, (INT)origin.X + index*14 + 1, (INT)origin.Y + 1, 12, 12);
+
+                       ::delete serventBrush;
+                       sd = sd->getNextData();
+                       index++;
+               }
+       }
+
+       // \8e\9f\82Ì\8aî\93_
+       origin.Y += 15;
+
+       // \83T\83C\83Y\82ð\95Û\91
+       setWidth((int)origin.X - posX);
+       setHeight((int)origin.Y - posY);
+
+       // ServentData\95\\8e¦
+       sd = serventDataTop;
+       while(sd){
+               if (openFlg || sd->getSelected()){
+                       sd->drawServent(g, (INT)x+12, (INT)origin.Y);
+                       // \8e\9f\82Ì\8aî\93_
+                       origin.Y += 15;
+               }
+               sd = sd->getNextData();
+       }
+       
+
+       return (int)(origin.Y);
+}
+
+bool ChannelData::checkDown(int x,int y){
+       // \94Í\88Í\93à\83`\83F\83b\83N
+       if (    
+                       (x > posX)
+               &&      (x < posX + getWidth())
+               &&      (y > posY)
+               &&      (y < posY + getHeight())
+       ){
+               return TRUE;
+       }
+       return FALSE;
+}
+
+ServentData *ChannelData::findServentData(int servent_id){
+       ServentData *sv = serventDataTop;
+       while(sv){
+               if (sv->getServentId() == servent_id){
+                       return sv;
+               }
+               sv = sv->getNextData();
+       }
+       return NULL;
+}
+
+void ChannelData::addServentData(ServentData *sd){
+       sd->setNextData(serventDataTop);
+       serventDataTop = sd;
+}
+
+void ChannelData::deleteDisableServents(){
+       ServentData *sd = serventDataTop;
+       ServentData *prev = NULL;
+
+       while(sd){
+               if (!(sd->getEnableFlg())){
+                       ServentData *next = sd->getNextData();
+                       if (prev){
+                               prev->setNextData(next);
+                       } else {
+                               serventDataTop = next;
+                       }
+                       ::delete sd;
+                       sd = next;
+               } else {
+                       prev = sd;
+                       sd = sd->getNextData();
+               }
+       }
+}
+
+int ChannelData::getServentCount(){
+       int ret = 0;
+
+       ServentData *sd = serventDataTop;
+       while(sd){
+               ret++;
+               sd = sd->getNextData();
+       }
+       return ret;
+}
+
+bool ChannelData::setName(int servent_id, String name){
+       ServentData *sd = serventDataTop;
+       while(sd){
+               if (sd->getServentId() == servent_id){
+                       sd->setName(name);
+                       return TRUE;
+               }
+               sd = sd->getNextData();
+       }
+       return FALSE;
+}
+
+void ServentData::setData(Servent *s, ChanHit *hit, unsigned int listeners, unsigned int relays, bool f){
+       servent_id = s->servent_id;
+       type = s->type;
+       status = s->status;
+       lastSkipTime = s->lastSkipTime;
+       host = s->getHost();
+
+       chanHit.numRelays = hit->numRelays;
+       chanHit.relay = hit->relay;
+       chanHit.firewalled = hit->firewalled;
+       chanHit.version = hit->version;
+       chanHit.version_vp = hit->version_vp;
+       chanHit.version_ex_number = hit->version_ex_number;
+       chanHit.version_ex_prefix[0] = hit->version_ex_prefix[0];
+       chanHit.version_ex_prefix[1] = hit->version_ex_prefix[1];
+
+       totalListeners = listeners;
+       totalRelays = relays;
+
+       infoFlg = f;
+}
+
+int ServentData::drawServent(Gdiplus::Graphics *g, int x, int y){
+       REAL xx = x * 1.0f;
+       REAL yy = y * 1.0f;
+       int w,h;
+
+       // \88Ê\92u\82ð\95Û\91
+       posX = x;
+       posY = y;
+
+       if (getWidth() == 0){
+               if (gWS){
+                       w = gWS;
+               } else {
+                       w = 400;
+               }
+       } else {
+               w = getWidth();
+               gWS = w;
+       }
+
+       // \95`\89æ\8aî\93_
+       PointF origin(xx, yy);
+
+       // \83t\83H\83\93\83g\90Ý\92è
+       Font font(L"\82l\82\82o\83S\83V\83b\83N",9);
+       // \95\8e\9a\90F
+       SolidBrush *strBrush;
+       if (chanHit.firewalled){
+               strBrush = ::new SolidBrush(Color::Red);
+       } else {
+               if (getSelected()){
+                       // \91I\91ð\92\86
+                       strBrush = ::new SolidBrush(Color::White);
+               } else {
+                       // \94ñ\91I\91ð
+                       strBrush = ::new SolidBrush(Color::Black);
+               }
+       }
+       // ServantData\95\\8e¦
+       g->SetTextRenderingHint(TextRenderingHintAntiAlias);
+       // \95\8e\9a\97ñ\8dì\90¬
+       char tmp[256];
+       char host1[256];
+       host.toStr(host1);
+
+       if (infoFlg){
+               if (chanHit.version_ex_number){
+                       // \8ag\92£\83o\81[\83W\83\87\83\93
+                       sprintf(tmp, "%c%c%04d - %d/%d - %s(%s)", 
+                               chanHit.version_ex_prefix[0],
+                               chanHit.version_ex_prefix[1],
+                               chanHit.version_ex_number,
+                               totalListeners,
+                               totalRelays,
+                               host1,
+                               hostname.cstr()
+                               );
+               } else if (chanHit.version_vp){
+                       sprintf(tmp, "VP%04d - %d/%d - %s(%s)", 
+                               chanHit.version_vp,
+                               totalListeners,
+                               totalRelays,
+                               host1,
+                               hostname.cstr()
+                               );
+               } else {
+                       sprintf(tmp, "(-----) - %d/%d - %s(%s)",
+                               totalListeners,
+                               totalRelays,
+                               host1,
+                               hostname.cstr()
+                               );
+               }
+       } else {
+                       sprintf(tmp, "(-----) - %d/%d - %s(%s)",
+                               totalListeners,
+                               totalRelays,
+                               host1,
+                               hostname.cstr()
+                               );
+       }
+       _bstr_t bstr1(tmp);
+
+       // \83X\83e\81[\83^\83X\95\\8e¦
+       Gdiplus::Image *img = NULL;
+       unsigned int nowTime = sys->getTime();
+       switch(getStatus()){
+               case Servent::S_CONNECTING:
+                       img = img_connect;
+                       break;
+               case Servent::S_CONNECTED:
+                       if (lastSkipTime + 120 > nowTime){
+                               if (chanHit.relay){
+                                       img = img_conn_ok_skip;
+                               } else {
+                                       if (chanHit.numRelays){
+                                               img = img_conn_full_skip;
+                                       } else {
+                                               img = img_conn_over_skip;
+                                       }
+                               }
+                       } else {
+                               if (chanHit.relay){
+                                       img = img_conn_ok;
+                               } else {
+                                       if (chanHit.numRelays){
+                                               img = img_conn_full;
+                                       } else {
+                                               img = img_conn_over;
+                                       }
+                               }
+                       }
+                       break;
+               default:
+                       break;
+       }
+
+       // \95\8e\9a\95`\89æ\94Í\88Í\8ew\92è
+       RectF r1(origin.X + img->GetWidth() + 2, origin.Y, 800.0f, 13.0f);
+       RectF r2;
+       StringFormat format;
+       format.SetAlignment(StringAlignmentNear);
+       g->MeasureString(bstr1, -1, &font, r1, &format, &r2);
+
+       w = (INT)r2.Width + img->GetWidth() + 2;
+       // ServentData\95\\8e¦\95\94\82Ì\94w\8ci\82ð\93h\82é
+       if (getSelected()){
+               // \91I\91ð\92\86
+               SolidBrush b(Color(160,49,106,197));
+               g->FillRectangle(&b, x, y, w, 13);
+       } else {
+               // \94ñ\91I\91ð
+               SolidBrush b(Color(160,200,200,200));
+               g->FillRectangle(&b, x, y, w, 13);
+       }
+
+       // \83X\83e\81[\83^\83X\95\\8e¦\88Ê\92u
+       Rect img_rect((INT)origin.X, (INT)origin.Y+1, img ? img->GetWidth() : 12, 12);
+       // \83X\83e\81[\83^\83X\95`\89æ
+       ImageAttributes att;
+//     att.SetColorKey(Color::White, Color::White, ColorAdjustTypeBitmap);
+       g->DrawImage(img, img_rect, 0, 0, img_rect.Width, 12, UnitPixel, &att);
+       // \8e\9f\82Ì\8aî\93_
+       origin.X += 12;
+
+       g->DrawString(bstr1, -1, &font, r2, &format, strBrush);
+       // \8e\9f\82Ì\8aî\93_
+       origin.X += r2.Width;
+       origin.Y += 13;
+
+       setWidth((int)origin.X-posX);
+       setHeight((int)origin.Y - posY);
+
+       ::delete strBrush;
+       return 0;
+}
+
+bool ServentData::checkDown(int x, int y){
+       if (    
+                       (x > posX)
+               &&      (x < posX + getWidth())
+               &&      (y > posY)
+               &&      (y < posY + getHeight())
+       ){
+               return TRUE;
+       }
+       return FALSE;
+}
+
+
+THREAD_PROC GUIDataUpdate(ThreadInfo *thread){
+       int i;
+
+       // set GUI thread status to running
+       thread->finish = false;
+
+       while(thread->active){
+               // \83`\83\83\83\93\83l\83\8b\83f\81[\83^\83\8d\83b\83N
+               ChannelDataLock.on();
+               // \83`\83\83\83\93\83l\83\8b\83f\81[\83^\82Ì\8dX\90V\83t\83\89\83O\82ð\91S\82ÄFALSE\82É\82·\82é
+               ChannelData *cd = channelDataTop;
+               while(cd){
+                       // Servent\82Ì\8dX\90V\83t\83\89\83O\82ðFALSE\82É\82·\82é
+                       ServentData *sv = cd->getServentDataTop();
+                       while(sv){
+                               sv->setEnableFlg(FALSE);
+                               sv = sv->getNextData();
+                       }
+                       cd->setEnableFlg(FALSE);
+                       cd = cd->getNextData();
+               }
+
+               Channel *c = chanMgr->channel;
+               // \8c»\8dÝ\91\8dÝ\82·\82é\83`\83\83\83\93\83l\83\8b\95ª\83\8b\81[\83v
+               while(c){
+                       // \8aù\82É\83`\83\83\83\93\83l\83\8b\83f\81[\83^\82ð\8e\9d\82Á\82Ä\82¢\82é\82©
+                       cd = channelDataTop;
+                       // \94­\8c©\83t\83\89\83OFALSE
+                       bool bFoundFlg = FALSE;
+                       while(cd){
+                               if (cd->getChannelId() == c->channel_id){
+                                       //\8aù\82É\83`\83\83\83\93\83l\83\8b\83f\81[\83^\82ª\82 \82é\82Ì\82Å\81A\82»\82Ì\82Ü\82Ü\8dX\90V
+                                       cd->setData(c);
+                                       // \8dX\90V\83t\83\89\83OTRUE
+                                       cd->setEnableFlg(TRUE);
+                                       // \94­\8c©\83t\83\89\83OTRUE
+                                       bFoundFlg = TRUE;
+                                       // \83\8b\81[\83v\97£\92E
+                                       break;
+                               }
+                               // \8c©\82Â\82©\82ç\82È\82©\82Á\82½\8fê\8d\87\81A\8e\9f\82Ì\83f\81[\83^\82ð\83`\83F\83b\83N
+                               cd = cd->getNextData();
+                       }
+
+                       // \90V\82µ\82¢\83`\83\83\83\93\83l\83\8b\82Ì\8fê\8d\87\81A\90V\8bK\83f\81[\83^\8dì\90¬
+                       if (!bFoundFlg){
+                               // \90V\8bK\83f\81[\83^\8dì\90¬
+                               cd = ::new ChannelData();
+                               // \83f\81[\83^\8dX\90V
+                               cd->setData(c);
+                               // \8dX\90V\83t\83\89\83OTRUE
+                               cd->setEnableFlg(TRUE);
+
+                               // \90V\8bK\83f\81[\83^\82ð\83\8a\83X\83g\82Ì\90æ\93ª\82É\93ü\82ê\82é
+                               cd->setNextData(channelDataTop);
+                               channelDataTop = cd;
+                       }
+                       // \8e\9f\82Ì\83`\83\83\83\93\83l\83\8b\82ð\8eæ\93¾
+                       c = c->next;
+               }
+
+               // \83`\83\83\83\93\83l\83\8b\82ª\82È\82­\82È\82Á\82Ä\82¢\82é\8fê\8d\87\82Ì\8f\88\97\9d
+               cd = channelDataTop;
+               ChannelData *prev = NULL; 
+               while(cd){
+                       // \83f\81[\83^\82ð\8dX\90V\82µ\82È\82©\82Á\82½\82©
+                       if (cd->getEnableFlg() == FALSE){
+                               // \83`\83\83\83\93\83l\83\8b\82ª\82È\82­\82È\82Á\82Ä\82¢\82é\82Ì\82Å\8dí\8f\9c
+                               ChannelData *next;
+                               next = cd->getNextData();
+                               if (!prev){
+                                       // \90æ\93ª\82Ì\83f\81[\83^\82ð\8dí\8f\9c
+                                       channelDataTop = next;
+                               } else {
+                                       // \93r\92\86\82Ì\83f\81[\83^\82ð\8dí\8f\9c
+                                       prev->setNextData(next);
+                               }
+                               // \8e\9f\82Ì\83f\81[\83^\82Ö
+                               cd = next;
+                       } else {
+                               // \83f\81[\83^\8dX\90V\8dÏ\81F\8e\9f\82Ì\83f\81[\83^\82Ö
+                               prev = cd;
+                               cd = cd->getNextData();
+                       }
+               }
+
+               Servent *s = servMgr->servents;
+               while(s){
+                       // \8f\89\8aú\89»
+                       ChanHitList *chl;
+                       bool infoFlg = false;
+                       bool relay = true;
+                       bool firewalled = false;
+                       unsigned int numRelays = 0;
+                       int vp_ver = 0;
+                       char ver_ex_prefix[2] = {' ',' '};
+                       int ver_ex_number = 0;
+                       // \92¼\89º\83z\83X\83g\8fî\95ñ\83`\83F\83b\83N
+                       unsigned int totalRelays = 0;
+                       unsigned int totalListeners = 0;
+
+                       ChanHit hitData;
+                       // \8eó\90M\92\86\82©
+                       if ((s->type == Servent::T_RELAY) && (s->status == Servent::S_CONNECTED)){
+                               // \83z\83X\83g\8fî\95ñ\83\8d\83b\83N
+                               chanMgr->hitlistlock.on();
+                               // \92¼\89º\83z\83X\83g\82ª\8eó\90M\82µ\82Ä\82¢\82é\83`\83\83\83\93\83l\83\8b\82Ì\83z\83X\83g\8fî\95ñ\82ð\8eæ\93¾
+                               chl = chanMgr->findHitListByID(s->chanID);
+                               // \83`\83\83\83\93\83l\83\8b\82Ì\83z\83X\83g\8fî\95ñ\82ª\82 \82é\82©
+                               if (chl){
+                                       // \83`\83\83\83\93\83l\83\8b\82Ì\83z\83X\83g\8fî\95ñ\82ª\82 \82é\8fê\8d\87
+                                       ChanHit *hit = chl->hit;
+                                       //\81@\83`\83\83\83\93\83l\83\8b\82Ì\83z\83X\83g\8fî\95ñ\82ð\91S\91\96\8d¸\82µ\82Ä
+                                       while(hit){
+                                               // ID\82ª\93¯\82\82à\82Ì\82Å\82 \82ê\82Î
+                                               if (hit->servent_id == s->servent_id){
+                                                       // \83g\81[\83^\83\8b\83\8a\83\8c\81[\82Æ\83g\81[\83^\83\8b\83\8a\83X\83i\81[\82ð\89Á\8eZ
+                                                       totalRelays += hit->numRelays;
+                                                       totalListeners += hit->numListeners;
+                                                       // \92¼\89º\82Å\82 \82ê\82Î
+                                                       if (hit->numHops == 1){
+                                                               // \8fî\95ñ\82ð\88ê\92U\95Û\91
+                                                               infoFlg = true;
+                                                               hitData.relay = hit->relay;
+                                                               hitData.firewalled = hit->firewalled;
+                                                               hitData.numRelays = hit->numRelays;
+                                                               hitData.version_vp = hit->version_vp;
+                                                               hitData.version_ex_prefix[0] = hit->version_ex_prefix[0];
+                                                               hitData.version_ex_prefix[1] = hit->version_ex_prefix[1];
+                                                               hitData.version_ex_number = hit->version_ex_number;
+                                                       }
+                                               }
+                                               // \8e\9f\82ð\83`\83F\83b\83N
+                                               hit = hit->next;
+                                       }
+                               }
+
+                               // \83`\83\83\83\93\83l\83\8b\83f\81[\83^\82©\82çServent\82ð\8c\9f\8dõ
+                               bool bFoundFlg = FALSE;
+                               cd = channelDataTop;
+                               while(cd){
+                                       ServentData *sv = cd->findServentData(s->servent_id);
+                                       // ServentData\82ª\82 \82ê\82Î
+                                       if (sv){
+                                               // \83f\81[\83^\90Ý\92è
+                                               sv->setData(s, &hitData, totalListeners, totalRelays, infoFlg);
+                                               sv->setEnableFlg(TRUE);
+                                               bFoundFlg = TRUE;
+                                               break;
+                                       }
+                                       cd = cd->getNextData();
+                               }
+                               // ServentData\82ª\8c©\82Â\82©\82ç\82È\82©\82Á\82½\8fê\8d\87
+                               if (!bFoundFlg){
+                                       // \83`\83\83\83\93\83l\83\8b\83f\81[\83^\82ð\92T\82·
+                                       cd = channelDataTop;
+                                       while(cd){
+                                               // \83`\83\83\83\93\83l\83\8bID\82ª\93¯\82\82©
+                                               if (cd->getChannelId() == s->channel_id){
+                                                       // \83f\81[\83^\90Ý\92è
+                                                       ServentData *sv = ::new ServentData();
+                                                       sv->setData(s, &hitData, totalListeners, totalRelays, infoFlg);
+                                                       sv->setEnableFlg(TRUE);
+                                                       // \83`\83\83\83\93\83l\83\8b\83f\81[\83^\82ÉServentData\92Ç\89Á
+                                                       cd->addServentData(sv);
+                                                       // \83z\83X\83g\96¼\82ð\8eæ\93¾\82·\82é
+                                                       IdData *id = ::new IdData(cd->getChannelId(), sv->getServentId(), sv->getHost().ip);
+                                                       ThreadInfo t;
+                                                       t.func = GetHostName;
+                                                       t.data = (void*)id;
+                                                       sys->startThread(&t);
+                                                       // \83\8b\81[\83v\8fI\97¹
+                                                       break;
+                                               }
+                                               // \8e\9f\82Ì\83f\81[\83^\82Ö
+                                               cd = cd->getNextData();
+                                       }
+                               }
+                               // \83z\83X\83g\8fî\95ñ\83A\83\93\83\8d\83b\83N
+                               chanMgr->hitlistlock.off();
+                       }
+                       s = s->next;
+               }
+
+               // \8dX\90V\82µ\82Ä\82¢\82È\82¢ServentData\82ð\8dí\8f\9c
+               cd = channelDataTop;
+               while(cd){
+                       cd->deleteDisableServents();
+                       cd = cd->getNextData();
+               }
+
+               // \83`\83\83\83\93\83l\83\8b\83f\81[\83^\83A\83\93\83\8d\83b\83N
+               ChannelDataLock.off();
+
+               // \95`\89æ\8dX\90V
+               if (guiWnd){
+                       MakeBack(guiWnd);
+               }
+
+               // 0.1\95b\81~10\82Å1\95b\91Ò\82¿
+               for(i=0; i<10; i++)
+               {
+                       if (!thread->active)
+                               break;
+                       sys->sleep(100);
+               }
+
+               if (gbGetFile && (sys->getTime() > gtGetFile)){
+                       gbGetFile = false;
+                       gtiGetFile.func = GetInternetFile;
+                       gtiGetFile.data = NULL;
+                       sys->startThread(&gtiGetFile);
+               }
+               else if (gbStart && (sys->getTime() > gtStartTime)){
+                       gbStart = false;
+                       SendMessage(guiWnd, WM_START, 0, 0);
+                       gtiStart.func = FestivalStart;
+                       gtiStart.data = NULL;
+                       sys->startThread(&gtiStart);
+               }
+       }
+
+       // set GUI thread status to terminated
+       thread->finish = true;
+
+       return 0;
+}
+
+ChannelData *findChannelData(int channel_id){
+       ChannelData *cd = channelDataTop;
+
+       while(cd){
+               if (cd->getChannelId() == channel_id){
+                       return cd;
+               }
+               cd = cd->getNextData();
+       }
+
+       return NULL;
+}
+
+
+void PopupChannelMenu(int channel_id){
+       POINT pos;
+       MENUITEMINFO info, separator;
+       HMENU hMenu;
+       DWORD dwID;
+
+       hMenu = CreatePopupMenu();
+
+       memset(&separator, 0, sizeof(MENUITEMINFO));
+       separator.cbSize = sizeof(MENUITEMINFO);
+       separator.fMask = MIIM_ID | MIIM_TYPE;
+       separator.fType = MFT_SEPARATOR;
+       separator.wID = 8000;
+
+       memset(&info, 0, sizeof(MENUITEMINFO));
+       info.cbSize = sizeof(MENUITEMINFO);
+       info.fMask = MIIM_ID | MIIM_TYPE;
+       info.fType = MFT_STRING;
+
+       ChannelData *cd = findChannelData(channel_id);
+
+       if (cd == NULL){
+               return;
+       }
+
+       info.wID = 1001;
+       info.dwTypeData = "\90Ø\92f";
+       InsertMenuItem(hMenu, -1, true, &info);
+
+       InsertMenuItem(hMenu, -1, true, &separator);
+
+       info.wID = 1000;
+       info.dwTypeData = "\8dÄ\90¶";
+       InsertMenuItem(hMenu, -1, true, &info);
+
+       InsertMenuItem(hMenu, -1, true, &separator);
+
+       info.wID = 1002;
+       info.dwTypeData = "\8dÄ\90Ú\91±";
+       InsertMenuItem(hMenu, -1, true, &info);
+
+       info.wID = 1003;
+       info.dwTypeData = "\83L\81[\83v";
+       InsertMenuItem(hMenu, -1, true, &info);
+
+       InsertMenuItem(hMenu, -1, true, &separator);
+
+       if (!cd->getOpenFlg()){
+               info.wID = 1004;
+               info.dwTypeData = "\92¼\89º\95\\8e¦";
+               InsertMenuItem(hMenu, -1, true, &info);
+       } else {
+               info.wID = 1005;
+               info.dwTypeData = "\92¼\89º\89B\95Á";
+               InsertMenuItem(hMenu, -1, true, &info);
+       }
+
+       GetCursorPos(&pos);
+       dwID = TrackPopupMenu(hMenu, TPM_LEFTALIGN|TPM_RETURNCMD, pos.x, pos.y, 0, guiWnd, NULL);
+
+       DestroyMenu(hMenu);
+
+       cd = findChannelData(channel_id);
+
+       if (cd == NULL){
+               return;
+       }
+
+       Channel *c = chanMgr->findChannelByChannelID(channel_id);
+
+       if (c == NULL){
+               return;
+       }
+
+       switch(dwID){
+               case 1000:      // \8dÄ\90
+                       chanMgr->playChannel(c->info);
+                       break;
+
+               case 1001:      // \90Ø\92f
+                       c->thread.active = false;
+                       c->thread.finish = true;
+                       break;
+
+               case 1002:      // \8dÄ\90Ú\91±
+                       c->bump = true;
+                       break;
+
+               case 1003:      // \83L\81[\83v
+                       if (!c->stayConnected){
+                               c->stayConnected  = true;
+                       } else {
+                               c->stayConnected = false;
+                       }
+                       break;
+
+               case 1004:      // \92¼\89º\95\\8e¦
+                       cd->setOpenFlg(TRUE);
+                       MakeBack(guiWnd);
+                       break;
+
+               case 1005:      // \92¼\89º\89B\95Á
+                       cd->setOpenFlg(FALSE);
+                       MakeBack(guiWnd);
+                       break;
+       }
+}
+
+void PopupServentMenu(int servent_id){
+       POINT pos;
+       MENUITEMINFO info, separator;
+       HMENU hMenu;
+       DWORD dwID;
+
+       hMenu = CreatePopupMenu();
+
+       memset(&separator, 0, sizeof(MENUITEMINFO));
+       separator.cbSize = sizeof(MENUITEMINFO);
+       separator.fMask = MIIM_ID | MIIM_TYPE;
+       separator.fType = MFT_SEPARATOR;
+       separator.wID = 8000;
+
+       memset(&info, 0, sizeof(MENUITEMINFO));
+       info.cbSize = sizeof(MENUITEMINFO);
+       info.fMask = MIIM_ID | MIIM_TYPE;
+       info.fType = MFT_STRING;
+
+       ServentData *sd = NULL;
+       ChannelData *cd = channelDataTop;
+       while(cd){
+               sd = cd->findServentData(servent_id);
+               if (sd){
+                       break;
+               }
+               cd = cd->getNextData();
+       }
+
+       if (cd == NULL || sd == NULL){
+               return;
+       }
+
+       info.wID = 1001;
+       info.dwTypeData = "\90Ø\92f";
+       InsertMenuItem(hMenu, -1, true, &info);
+
+//     InsertMenuItem(hMenu, -1, true, &separator);
+
+       GetCursorPos(&pos);
+       dwID = TrackPopupMenu(hMenu, TPM_LEFTALIGN|TPM_RETURNCMD, pos.x, pos.y, 0, guiWnd, NULL);
+
+       DestroyMenu(hMenu);
+
+       cd = channelDataTop;
+       while(cd){
+               sd = cd->findServentData(servent_id);
+               if (sd){
+                       break;
+               }
+               cd = cd->getNextData();
+       }
+
+       if (cd == NULL || sd == NULL){
+               return;
+       }
+
+       Servent *s = servMgr->findServentByServentID(servent_id);
+
+       if (s == NULL){
+               return;
+       }
+
+       switch(dwID){
+               case 1001:      // \90Ø\92f
+                       s->thread.active = false;
+                       break;
+
+       }
+}
+
+void PopupOtherMenu(){
+       POINT pos;
+       MENUITEMINFO info, separator;
+       HMENU hMenu;
+       DWORD dwID;
+
+       hMenu = CreatePopupMenu();
+
+       memset(&separator, 0, sizeof(MENUITEMINFO));
+       separator.cbSize = sizeof(MENUITEMINFO);
+       separator.fMask = MIIM_ID | MIIM_TYPE;
+       separator.fType = MFT_SEPARATOR;
+       separator.wID = 8000;
+
+       memset(&info, 0, sizeof(MENUITEMINFO));
+       info.cbSize = sizeof(MENUITEMINFO);
+       info.fMask = MIIM_ID | MIIM_TYPE;
+       info.fType = MFT_STRING;
+
+       if (!gbDispTop){
+               info.wID = 1101;
+               info.dwTypeData = "\8dÅ\91O\96Ê\95\\8e¦";
+               InsertMenuItem(hMenu, -1, true, &info);
+       } else {
+               info.wID = 1102;
+               info.dwTypeData = "\8dÅ\91O\96Ê\89ð\8f\9c";
+               InsertMenuItem(hMenu, -1, true, &info);
+       }
+
+       InsertMenuItem(hMenu, -1, true, &separator);
+
+       if (!gbAllOpen){
+               info.wID = 1103;
+               info.dwTypeData = "\91S\92¼\89º\93W\8aJ";
+               InsertMenuItem(hMenu, -1, true, &info);
+       } else {
+               info.wID = 1104;
+               info.dwTypeData = "\91S\92¼\89º\89B\95Á";
+               InsertMenuItem(hMenu, -1, true, &info);
+       }
+
+       InsertMenuItem(hMenu, -1, true, &separator);
+
+       if (!servMgr->autoServe){
+               info.wID = 1105;
+               info.dwTypeData = "\97L\8cø";
+               InsertMenuItem(hMenu, -1, true, &info);
+       } else {
+               info.wID = 1106;
+               info.dwTypeData = "\96³\8cø";
+               InsertMenuItem(hMenu, -1, true, &info);
+       }
+
+       GetCursorPos(&pos);
+       dwID = TrackPopupMenu(hMenu, TPM_LEFTALIGN|TPM_RETURNCMD, pos.x, pos.y, 0, guiWnd, NULL);
+
+       DestroyMenu(hMenu);
+
+       ChannelData *cd = channelDataTop;
+
+       switch(dwID){
+               case 1101:      // \8dÅ\91O\96Ê\95\\8e¦
+                       gbDispTop = true;
+                       ::SetWindowPos(guiWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
+                       break;
+
+               case 1102:      // \8dÅ\91O\96Ê\89ð\8f\9c
+                       gbDispTop = false;
+                       ::SetWindowPos(guiWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
+                       break;
+
+               case 1103:      // \91S\92¼\89º\93W\8aJ
+                       gbAllOpen = true;
+                       while(cd){
+                               cd->setOpenFlg(true);
+                               cd = cd->getNextData();
+                       }
+                       break;
+
+               case 1104:      // \91S\92¼\89º\89B\95Á
+                       gbAllOpen = false;
+                       while(cd){
+                               cd->setOpenFlg(false);
+                               cd = cd->getNextData();
+                       }
+                       break;
+
+               case 1105:      // \97L\8cø
+                       servMgr->autoServe = true;
+                       break;
+
+               case 1106:      // \96³\8cø
+                       servMgr->autoServe = false;
+                       break;
+
+       }
+}
+
+void WmCreateProc(HWND hwnd){
+       if (backImage){
+               ::delete backImage;
+       }
+       _bstr_t bstr("back.jpg");
+       backImage = ::new Image(bstr);
+
+       MakeBack(hwnd, 800, 600);
+
+       guiThread.func = GUIDataUpdate;
+       if (!sys->startThread(&guiThread)){
+               MessageBox(hwnd,"Unable to start GUI","PeerCast",MB_OK|MB_ICONERROR);
+               PostMessage(hwnd,WM_DESTROY,0,0);
+       }
+       if (guiFlg){
+               SetWindowPlacement(hwnd, &winPlace);
+       }
+
+       if (img_idle){
+               ::delete img_idle;
+               ::delete img_connect;
+               ::delete img_conn_ok;
+               ::delete img_conn_full;
+               ::delete img_conn_over;
+               ::delete img_conn_ok_skip;
+               ::delete img_conn_full_skip;
+               ::delete img_conn_over_skip;
+               ::delete img_error;
+               ::delete img_broad_ok;
+               ::delete img_broad_full;
+       }
+       bstr = L"ST_IDLE.bmp";
+       img_idle = ::new Image(bstr);
+       bstr = L"ST_CONNECT.bmp";
+       img_connect = ::new Image(bstr);
+       bstr = L"ST_CONN_OK.bmp";
+       img_conn_ok = ::new Image(bstr);
+       bstr = L"ST_CONN_FULL.bmp";
+       img_conn_full = ::new Image(bstr);
+       bstr = L"ST_CONN_OVER.bmp";
+       img_conn_over = ::new Image(bstr);
+       bstr = L"ST_CONN_OK_SKIP.bmp";
+       img_conn_ok_skip = ::new Image(bstr);
+       bstr = L"ST_CONN_FULL_SKIP.bmp";
+       img_conn_full_skip = ::new Image(bstr);
+       bstr = L"ST_CONN_OVER_SKIP.bmp";
+       img_conn_over_skip = ::new Image(bstr);
+       bstr = L"ST_ERROR.bmp";
+       img_error = ::new Image(bstr);
+       bstr = L"ST_BROAD_OK.bmp";
+       img_broad_ok = ::new Image(bstr);
+       bstr = L"ST_BROAD_FULL.bmp";
+       img_broad_full = ::new Image(bstr);
+}
+
+void WmPaintProc(HWND hwnd){
+       HDC hdc;
+       PAINTSTRUCT paint;
+
+       if (backGra){
+               MakeBackLock.on();
+               hdc = BeginPaint(hwnd, &paint);
+               RECT *rcRect;   // \95`\89æ\94Í\88Í
+               rcRect = &(paint.rcPaint);
+               LONG width = rcRect->right - rcRect->left + 1;
+               LONG height = rcRect->bottom - rcRect->top + 1;
+
+               Graphics g2(hdc);
+               Rect r(rcRect->left, rcRect->top, width, height);
+               g2.DrawImage(backBmp,r, rcRect->left, rcRect->top, width, height, UnitPixel);
+               EndPaint(hwnd, &paint);
+               MakeBackLock.off();
+       }
+}
+
+void WmSizeProc(HWND hwnd, LPARAM lParam){
+       UINT width = LOWORD(lParam);
+       UINT height = HIWORD(lParam);
+
+       MakeBack(hwnd, width, height);
+
+}
+
+void WmLButtonDownProc(HWND hwnd, LPARAM lParam){
+       ChannelData *cd;
+       bool changeFlg = FALSE;
+
+       ChannelDataLock.on();
+       cd = channelDataTop;
+       while(cd){
+               int x = LOWORD(lParam);
+               int y = HIWORD(lParam);
+               if (cd->checkDown(LOWORD(lParam), HIWORD(lParam))){
+                       if (!(cd->isSelected())){
+                               changeFlg = TRUE;
+                       }
+                       cd->setSelected(TRUE);
+               } else {
+                       if (cd->isSelected()){
+                               changeFlg = TRUE;
+                       }
+                       cd->setSelected(FALSE);
+               }
+               int sx = cd->getPosX() + cd->getWidth();
+               int sy = cd->getPosY();
+               int index = 0;
+               ServentData *sd = cd->getServentDataTop();
+               while(sd){
+                       if (    (       (!cd->getOpenFlg())
+                                       &&      (sx + index*14 < x)
+                                       &&      (x < sx + (index+1)*14)
+                                       &&      (sy < y)
+                                       &&      (y < sy + 14)   )
+                               ||      sd->checkDown(LOWORD(lParam), HIWORD(lParam))
+                       ){
+                               if (!sd->getSelected()){
+                                       changeFlg = TRUE;
+                               }
+                               sd->setSelected(TRUE);
+                       } else {
+                               if (sd->getSelected()){
+                                       changeFlg = TRUE;
+                               }
+                               sd->setSelected(FALSE);
+                       }
+                       sd = sd->getNextData();
+                       index++;
+               }
+               cd = cd->getNextData();
+       }
+       ChannelDataLock.off();
+       if (changeFlg){
+               MakeBack(hwnd);
+       }
+}
+
+void WmLButtonDblclkProc(HWND hwnd, LPARAM lParam){
+       ChannelData *cd;
+       bool changeFlg = FALSE;
+
+       ChannelDataLock.on();
+       cd = channelDataTop;
+       while(cd){
+               int x = LOWORD(lParam);
+               int y = HIWORD(lParam);
+               if (cd->checkDown(LOWORD(lParam), HIWORD(lParam))){
+                       if (!(cd->isSelected())){
+                               changeFlg = TRUE;
+                       }
+                       if (!(cd->getOpenFlg())){
+                               changeFlg = TRUE;
+                               cd->setOpenFlg(TRUE);
+                       } else {
+                               changeFlg = TRUE;
+                               cd->setOpenFlg(FALSE);
+                       }
+                       cd->setSelected(TRUE);
+               } else {
+                       if (cd->isSelected()){
+                               changeFlg = TRUE;
+                       }
+                       cd->setSelected(FALSE);
+               }
+/*             int sx = cd->getPosX() + cd->getWidth();
+               int sy = cd->getPosY();
+               int index = 0;
+               ServentData *sd = cd->getServentDataTop();
+               while(sd){
+                       if (    (       (!cd->getOpenFlg())
+                                       &&      (sx + index*14 < x)
+                                       &&      (x < sx + (index+1)*14)
+                                       &&      (sy < y)
+                                       &&      (y < sy + 14)   )
+                               ||      sd->checkDown(LOWORD(lParam), HIWORD(lParam))
+                       ){
+                               if (!sd->getSelected()){
+                                       changeFlg = TRUE;
+                               }
+                               sd->setSelected(TRUE);
+                       } else {
+                               if (sd->getSelected()){
+                                       changeFlg = TRUE;
+                               }
+                               sd->setSelected(FALSE);
+                       }
+                       sd = sd->getNextData();
+                       index++;
+               }*/
+               cd = cd->getNextData();
+       }
+       ChannelDataLock.off();
+       if (changeFlg){
+               MakeBack(hwnd);
+       }
+}
+
+void WmRButtonDownProc(HWND hwnd, LPARAM lParam){
+       ChannelData *cd;
+       bool changeFlg = FALSE;
+       bool channel_selected = FALSE;
+       bool servent_selected = FALSE;
+       int channel_id = 0;
+       int servent_id = 0;
+
+       cd = channelDataTop;
+       while(cd){
+               if (cd->checkDown(LOWORD(lParam), HIWORD(lParam))){
+                       if (!(cd->isSelected())){
+                               changeFlg = TRUE;
+                       }
+                       cd->setSelected(TRUE);
+                       channel_id = cd->getChannelId();
+                       channel_selected = TRUE;
+               } else {
+                       if (cd->isSelected()){
+                               changeFlg = TRUE;
+                       }
+                       cd->setSelected(FALSE);
+               }
+               ServentData *sd = cd->getServentDataTop();
+               while(sd){
+                       if (sd->checkDown(LOWORD(lParam), HIWORD(lParam))){
+                               if (!sd->getSelected()){
+                                       changeFlg = TRUE;
+                               }
+                               sd->setSelected(TRUE);
+                               servent_id = sd->getServentId();
+                               servent_selected = TRUE;
+                       } else {
+                               if (sd->getSelected()){
+                                       changeFlg = TRUE;
+                               }
+                               sd->setSelected(FALSE);
+                       }
+                       sd = sd->getNextData();
+               }
+               cd = cd->getNextData();
+       }
+       if (changeFlg){
+               MakeBack(hwnd);
+       }
+
+       if (channel_selected){
+               PopupChannelMenu(channel_id);
+       } else if (servent_selected){
+               PopupServentMenu(servent_id);
+       } else {
+               PopupOtherMenu();
+       }
+}
+
+LRESULT CALLBACK GUIProc (HWND hwnd, UINT message,
+                                 WPARAM wParam, LPARAM lParam)
+{
+       switch(message){
+               case WM_CREATE:         // \83E\83B\83\93\83h\83E\8dì\90¬
+                       WmCreateProc(hwnd);
+                       break;
+
+               case WM_PAINT:          // \95`\89æ
+                       WmPaintProc(hwnd);
+                       break;
+
+               case WM_SIZE:           // \83T\83C\83Y\95Ï\8dX
+                       WmSizeProc(hwnd,lParam);
+                       break;
+
+               case WM_LBUTTONDOWN:    // \8d\83{\83^\83\93\89\9f\82·
+                       WmLButtonDownProc(hwnd,lParam);
+                       break;
+
+               case WM_RBUTTONDOWN:    // \89E\83{\83^\83\93\89\9f\82·
+                       WmRButtonDownProc(hwnd,lParam);
+                       break;
+
+               case WM_LBUTTONDBLCLK:          // \8d\83_\83u\83\8b\83N\83\8a\83b\83N
+                       WmLButtonDblclkProc(hwnd,lParam);
+                       break;
+
+               case WM_ERASEBKGND:     // \94w\8ci\8fÁ\8b\8e
+                       return TRUE;    // \94w\8ci\82Í\8fÁ\82³\82È\82¢
+
+               case WM_CLOSE:
+                       //if (backImage){
+                       //      ::delete backImage;
+                       //      backImage = NULL;
+                       //}
+                       GetWindowPlacement(hwnd, &winPlace);
+                       guiFlg = true;
+                       DestroyWindow( hwnd );
+                       break;
+               case WM_DESTROY:
+                       GetWindowPlacement(hwnd, &winPlace);
+                       guiFlg = true;
+                       guiThread.active = false;
+
+                       // wait until GUI thread terminated,
+                       // and then dispose background image.
+                       while (1)
+                       {
+                               if (guiThread.finish)
+                                       break;
+                       }
+                       if (backImage)
+                       {
+                               ::delete backImage;
+                               backImage = NULL;
+                       }
+
+                       guiWnd = NULL;
+                       break;
+               case WM_START:
+                       ghStart = ::CreateWindow(szWindowClass3,
+                               "Peercast-IM@S",
+                               WS_OVERLAPPEDWINDOW & ~(WS_MAXIMIZEBOX),
+                               0,
+                               0,
+                               400,
+                               300,
+                               NULL,
+                               NULL,
+                               hInst,
+                               NULL);
+                       ::ShowWindow(ghStart, SW_SHOWNORMAL);
+                       break;
+
+               default:
+                       return (DefWindowProc(hwnd, message, wParam, lParam));
+       }
+
+       return 0;
+}
+
+Gdiplus::Image *data1 = NULL;
+Gdiplus::Image *data2 = NULL;
+Gdiplus::Bitmap *startBmp = NULL;
+Gdiplus::Graphics *startGra = NULL;
+WLock MakeStartLock;
+
+LRESULT CALLBACK StartProc (HWND hwnd, UINT message,
+                                 WPARAM wParam, LPARAM lParam)
+{
+       SolidBrush b(Color::Black);
+       bstr_t bstr;
+
+       switch(message){
+               case WM_CREATE:
+                       startBmp = ::new Bitmap(400,300);
+                       startGra = ::new Graphics(startBmp);
+                       bstr = L"data1.jpg";
+                       data1 = ::new Image(bstr);
+                       bstr = L"data2.jpg";
+                       data2 = ::new Image(bstr);
+                       // \8d\95\82Å\93h\82è\82Â\82Ô\82µ
+                       startGra->FillRectangle(&b, 0, 0, 400, 300);
+                       break;
+               case WM_PAINT:
+                       if (startGra){
+                               HDC hdc;
+                               PAINTSTRUCT paint;
+
+                               MakeStartLock.on();
+                               hdc = BeginPaint(hwnd, &paint);
+                               RECT *rcRect;
+                               rcRect = &(paint.rcPaint);
+                               LONG width = rcRect->right - rcRect->left + 1;
+                               LONG height = rcRect->bottom - rcRect->top + 1;
+
+                               Graphics g2(hdc);
+                               Rect r(rcRect->left, rcRect->top, width, height);
+                               g2.DrawImage(startBmp, r, rcRect->left, rcRect->top, width, height, UnitPixel);
+                               EndPaint(hwnd, &paint);
+                               MakeStartLock.off();
+                       }
+                       break;
+               case WM_ERASEBKGND:
+                       return TRUE;
+               case WM_CLOSE:
+                       DestroyWindow(ghStart);
+                       if (startBmp){
+                               ::delete startBmp;
+                       }
+                       if (startGra){
+                               ::delete startGra;
+                       }
+                       if (data1){
+                               ::delete data1;
+                       }
+                       if (data2){
+                               ::delete data2;
+                       }
+                       break;
+
+               default:
+                       return (DefWindowProc(hwnd, message, wParam, lParam));
+       }
+
+       return 0;
+}
+
+THREAD_PROC FestivalStart(ThreadInfo *thread){
+
+       while(startGra==NULL){
+               sys->sleep(100);
+       }
+
+       sys->sleep(1000);
+
+       MakeStartLock.on();
+       Font font(L"\82l\82\82o\83S\83V\83b\83N",40);
+       StringFormat format;
+       format.SetAlignment(StringAlignmentCenter);
+       startGra->SetTextRenderingHint(TextRenderingHintAntiAlias);
+       PointF origin(199.0f,49.0f);
+       RectF rect(0,0,400,100);
+       LinearGradientBrush b1(rect, Color::LightSkyBlue, Color::White, LinearGradientModeHorizontal);
+       startGra->DrawString(L"\91æ\82Q\89ñ", -1, &font, origin, &format, &b1);
+       origin.Y += 50;
+       LinearGradientBrush b2(rect, Color::LightGreen, Color::White, LinearGradientModeHorizontal);
+       startGra->DrawString(L"\83A\83C\83h\83\8b\83}\83X\83^\81[", -1, &font, origin, &format, &b2);
+       origin.Y += 50;
+       LinearGradientBrush b3(rect, Color::LightGoldenrodYellow, Color::White, LinearGradientModeHorizontal);
+       startGra->DrawString(L"\83t\83@\83\93\8a´\8eÓ\8dÕ", -1, &font, origin, &format, &b3);
+       MakeStartLock.off();
+       InvalidateRect(ghStart, NULL, FALSE);
+       sys->sleep(3000);
+
+       MakeStartLock.on();
+       startGra->DrawImage(data1, Rect(0,0,80,400), 200,200,66,330, UnitPixel);
+       MakeStartLock.off();
+       InvalidateRect(ghStart, NULL, FALSE);
+       sys->sleep(500);
+
+       MakeStartLock.on();
+       startGra->DrawImage(data1, Rect(80,0,80,400), 266,200,66,330, UnitPixel);
+       MakeStartLock.off();
+       InvalidateRect(ghStart, NULL, FALSE);
+       sys->sleep(500);
+
+       MakeStartLock.on();
+       startGra->DrawImage(data1, Rect(160,0,80,400), 332,200,66,330, UnitPixel);
+       MakeStartLock.off();
+       InvalidateRect(ghStart, NULL, FALSE);
+       sys->sleep(500);
+
+       MakeStartLock.on();
+       startGra->DrawImage(data1, Rect(240,0,80,400), 398,200,66,330, UnitPixel);
+       MakeStartLock.off();
+       InvalidateRect(ghStart, NULL, FALSE);
+       sys->sleep(500);
+
+       MakeStartLock.on();
+       startGra->DrawImage(data1, Rect(320,0,80,400), 464,200,66,330, UnitPixel);
+       MakeStartLock.off();
+       InvalidateRect(ghStart, NULL, FALSE);
+       sys->sleep(500);
+
+       MakeStartLock.on();
+       startGra->DrawImage(data1, Rect(0,0,80,400), 530,200,54,270, UnitPixel);
+       MakeStartLock.off();
+       InvalidateRect(ghStart, NULL, FALSE);
+       sys->sleep(500);
+
+       MakeStartLock.on();
+       startGra->DrawImage(data1, Rect(80,0,80,400), 584,200,54,270, UnitPixel);
+       MakeStartLock.off();
+       InvalidateRect(ghStart, NULL, FALSE);
+       sys->sleep(500);
+
+       MakeStartLock.on();
+       startGra->DrawImage(data1, Rect(160,0,80,400), 638,200,54,270, UnitPixel);
+       MakeStartLock.off();
+       InvalidateRect(ghStart, NULL, FALSE);
+       sys->sleep(500);
+
+       MakeStartLock.on();
+       startGra->DrawImage(data1, Rect(240,0,80,400), 692,200,54,270, UnitPixel);
+       MakeStartLock.off();
+       InvalidateRect(ghStart, NULL, FALSE);
+       sys->sleep(500);
+
+       MakeStartLock.on();
+       startGra->DrawImage(data1, Rect(320,0,80,400), 746,200,54,270, UnitPixel);
+       MakeStartLock.off();
+       InvalidateRect(ghStart, NULL, FALSE);
+       sys->sleep(500);
+
+       for (int i=1; i<=10; i++){
+               ColorMatrix mtx = {
+                       1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+                       0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
+                       0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
+                       0.0f, 0.0f, 0.0f, 0.1f*i, 0.0f,
+                       0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
+               ImageAttributes att;
+
+               MakeStartLock.on();
+               att.SetColorMatrix(&mtx, ColorMatrixFlagsDefault, ColorAdjustTypeBitmap);
+               startGra->DrawImage(data2, Rect(0,0,400,300), 360,130,400,300, UnitPixel, &att);
+               MakeStartLock.off();
+               InvalidateRect(ghStart, NULL, FALSE);
+               sys->sleep(100);
+       }
+
+       sys->sleep(2000);
+
+       MakeStartLock.on();
+       INT style = FontStyleBold;
+       Font font2(L"\82l\82\82o\83S\83V\83b\83N",70,style,UnitPoint);
+       PointF origin2(199.0f,99.0f);
+       SolidBrush bs(Color::Black);
+       startGra->DrawString(L"START!", -1, &font2, origin2, &format, &bs);
+       Font font3(L"\82l\82\82o\83S\83V\83b\83N",70,style,UnitPoint);
+       LinearGradientBrush bx(rect, Color::LightPink, Color::DeepPink, LinearGradientModeHorizontal);
+       startGra->DrawString(L"START!", -1, &font3, origin2, &format, &bx);
+       MakeStartLock.off();
+       InvalidateRect(ghStart, NULL, FALSE);
+       sys->sleep(5000);
+
+       SendMessage(ghStart, WM_CLOSE, 0, 0);
+       return 0;
+}
diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/gui.h b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/gui.h
new file mode 100644 (file)
index 0000000..84e7381
--- /dev/null
@@ -0,0 +1,228 @@
+// ------------------------------------------------
+// File : gui.h
+// Date: 4-apr-2002
+// Author: giles
+// 
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _GUI_H
+#define _GUI_H
+
+#include "sys.h"
+#include "gdiplus.h"
+#include "channel.h"
+
+extern LRESULT CALLBACK GUIProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+extern LRESULT CALLBACK StartProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+extern void ADDLOG(const char *str,int id,bool sel,void *data, LogBuffer::TYPE type);
+
+extern String iniFileName;
+extern HWND guiWnd;
+extern int logID;
+
+enum 
+{
+       WM_INITSETTINGS = WM_USER,
+       WM_GETPORTNUMBER,
+       WM_PLAYCHANNEL,
+       WM_TRAYICON,
+       WM_SHOWGUI,
+       WM_SHOWMENU,
+       WM_PROCURL,
+       WM_START
+
+};
+
+class IdData
+{
+private:
+       int channel_id;
+       int servent_id;
+       unsigned int ip_addr;
+
+public:
+       IdData(int cid, int sid, unsigned int ip){
+               channel_id = cid;
+               servent_id = sid;
+               ip_addr = ip;
+       }
+
+       int getChannelId(){return channel_id;};
+       int getServentId(){return servent_id;};
+       unsigned int getIpAddr(){return ip_addr;};
+};
+
+class ServentData
+{
+private:
+       int servent_id;
+       int type;
+//     unsigned int tnum;
+       int status;
+//     String agent;
+       Host host;
+       String hostname;
+//     unsigned int syncpos;
+//     char *typeStr;
+//     char *statusStr;
+//     bool infoFlg;
+//     bool relay;
+//     bool firewalled;
+       unsigned int totalRelays;
+       unsigned int totalListeners;
+//     int vp_ver;
+//     char ver_ex_prefix[2];
+//     int ver_ex_number;
+
+       bool EnableFlg;
+       bool infoFlg;
+       ServentData *next;
+       ChanHit chanHit;
+       bool selected;
+       int posX;
+       int posY;
+       int     width;
+       int height;
+
+       unsigned int lastSkipTime;
+       unsigned int lastSkipCount;
+
+public:
+       ServentData(){
+               next = NULL;
+               EnableFlg = false;
+               infoFlg = false;
+
+               posX = 0;
+               posY = 0;
+               width = 0;
+               selected = false;
+
+       }
+       void setData(Servent *s, ChanHit *hit, unsigned int listeners, unsigned int relays, bool infoFlg);
+       bool getInfoFlg(){return infoFlg;}
+       ChanHit *getChanHit(){return &chanHit;};
+       int getStatus(){return status;};
+       Host getHost(){return host;};
+
+       int getServentId(){return servent_id;};
+
+       bool getEnableFlg(){return EnableFlg;};
+       void setEnableFlg(bool f){EnableFlg = f;};
+       ServentData *getNextData(){return next;};
+       void setNextData(ServentData *s){next = s;};
+       bool getSelected(){return selected;};
+       void setSelected(bool f){selected = f; if (!f){posX=0;posY=0;}};
+       int getWidth(){return width;};
+       void setWidth(int w){width = w;};
+       int getHeight(){return height;};
+       void setHeight(int h){height = h;};
+       String getName(){return hostname;};
+       void setName(String n){hostname = n;};
+
+       int drawServent(Gdiplus::Graphics *g, int x, int y);
+
+       bool checkDown(int x, int y);
+
+};
+
+class ChannelData {
+
+private:
+       int channel_id;
+       char name[257];
+       int bitRate;
+       unsigned int lastPlayStart;
+       int status;
+       int totalListeners;
+       int totalRelays;
+       int localListeners;
+       int localRelays;
+       bool stayConnected;
+       ChanHit chDisp;
+       bool bTracker;
+       unsigned int lastSkipTime;
+       unsigned int skipCount;
+
+       bool EnableFlg;
+       ChannelData *next;
+
+       int posX;
+       int posY;
+       int width;
+       int height;
+       bool selected;
+       ServentData *serventDataTop;
+       bool openFlg;
+
+public:
+       ChannelData(){
+               EnableFlg = FALSE;
+               next = NULL;
+               posX = 0;
+               posY = 0;
+               width = 0;
+               height = 0;
+               selected = FALSE;
+               serventDataTop = NULL;
+               openFlg = FALSE;
+       }
+       int drawChannel(Gdiplus::Graphics *g, int x, int y);
+
+       void setData(Channel *);
+       int getChannelId(){return channel_id;};
+       char* getName(){return &(name[0]);};
+       int getBitRate(){return bitRate;};
+       bool isStayConnected(){return stayConnected;};
+       bool isTracker(){return bTracker;};
+       int getStatus(){return status;};
+       unsigned int getLastSkipTime(){return lastSkipTime;};
+
+       int getTotalListeners(){return totalListeners;};
+       int getTotalRelays(){return totalRelays;};
+       int getLocalListeners(){return localListeners;};
+       int getLocalRelays(){return localRelays;};
+
+       bool getEnableFlg(){return EnableFlg;};
+       void setEnableFlg(bool flg){EnableFlg = flg;};
+       ChannelData *getNextData(){return next;};
+       void setNextData(ChannelData* cd){next = cd;};
+
+       int getPosX(){return posX;};
+       void setPosX(int x){posX = x;}
+       int getPosY(){return posY;};
+       void setPosY(int y){posY = y;};
+       int getWidth(){return width;};
+       void setWidth(int w){width = w;};
+       int getHeight(){return height;};
+       void setHeight(int h){height = h;};
+       bool isSelected(){return selected;};
+       void setSelected(bool sel){selected = sel;};
+       bool getOpenFlg(){return openFlg;};
+       void setOpenFlg(bool b){openFlg = b;};
+
+       ServentData* getServentDataTop(){return serventDataTop;};
+       ServentData* findServentData(int servent_id);
+       void addServentData(ServentData *sd);
+       void deleteDisableServents();
+
+       bool setName(int servent_id, String name);
+       int getServentCount();
+
+       bool checkDown(int x, int y);
+};
+
+
+
+#endif
\ No newline at end of file
diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/resource.h b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/resource.h
new file mode 100644 (file)
index 0000000..a9a2b6d
--- /dev/null
@@ -0,0 +1,110 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by Simple.rc
+//
+#define IDC_MYICON                      2
+#define IDD_MAINWINDOW                  101
+#define IDD_SIMPLE_DIALOG               102
+#define IDD_ABOUTBOX                    103
+#define IDS_APP_TITLE                   103
+#define IDM_ABOUT                       104
+#define IDM_EXIT                        105
+#define IDS_HELLO                       106
+#define IDI_SIMPLE                      107
+#define IDI_SMALL                       108
+#define IDC_SIMPLE                      109
+#define IDI_SMALL2                      109
+#define IDR_MAINFRAME                   128
+#define IDR_TRAYMENU                    130
+#define IDR_VERMENU                     133
+#define IDD_CHANINFO                    136
+#define IDR_LTRAYMENU                   137
+#define IDC_LIST1                       1000
+#define IDC_BUTTON7                     1001
+#define IDC_ABOUTVER                    1002
+#define IDC_CHECK1                      1003
+#define IDC_EDIT1                       1004
+#define IDC_LIST2                       1005
+#define IDC_EDIT_PLAYING                1005
+#define IDC_COMBO1                      1006
+#define IDC_EDIT_MESSAGE                1006
+#define IDC_CHECK2                      1007
+#define IDC_EDIT_NAME                   1007
+#define IDC_BUTTON1                     1008
+#define IDC_EDIT_DESC                   1008
+#define IDC_DETAILS                     1009
+#define IDC_MAXRELAYS                   1009
+#define IDC_LIST3                       1010
+#define IDC_PLAY                        1010
+#define IDC_CONTACT                     1011
+#define IDC_EDIT2                       1012
+#define IDC_FORMAT                      1013
+#define IDC_EDIT_GENRE                  1014
+#define IDC_KEEP                        1015
+#define IDC_EDIT_STATUS                 1016
+#define IDC_GROUPBOX_RELAY              1016
+#define IDC_EDIT_LISTENERS              1017
+#define IDC_STATIC_CONNECTION           1017
+#define IDC_LIST4                       1018
+#define IDC_EDIT_HOSTS                  1018
+#define IDC_STATIC_LOG                  1018
+#define IDC_BUTTON4                     1019
+#define IDC_BUTTON5                     1020
+#define IDC_BUTTON6                     1021
+#define IDC_EDIT3                       1025
+#define IDC_EDIT5                       1027
+#define IDC_LOGDEBUG                    1037
+#define IDC_LOGNETWORK                  1038
+#define IDC_LOGERRORS                   1039
+#define IDC_CHECK9                      1041
+#define IDC_BUTTON8                     1043
+#define IDC_BUTTON10                    1046
+#define IDC_BUTTON11                    1047
+#define IDC_LOGCHANNELS                 1050
+#define IDC_BUTTON2                     1056
+#define IDC_EDIT4                       1058
+#define IDC_BUTTON3                     1059
+#define IDC_EDIT9                       1060
+#define IDC_CHECK11                     1061
+#define IDC_BUTTON9                     1062
+#define IDM_SETTINGS_GUI                32771
+#define ID_POPUP_ABOUT                  32779
+#define ID_POPUP_EXIT_CONFIRM           32781
+#define ID_POPUP_EXIT_NO                32782
+#define ID_POPUP_SETTINGS               32785
+#define ID_POPUP_CONNECTIONS            32786
+#define ID_POPUP_SHOWGUI                32788
+#define ID_POPUP_ALLCHANNELS            32791
+#define ID_POPUP_FAVORITES_EDIT         32792
+#define ID_POPUP_ADVANCED_INFORMATION   32793
+#define ID_POPUP_ADVANCED_SAVESETTINGS  32794
+#define ID_POPUP_UPGRADE                32795
+#define ID_POPUP_HELP                   32796
+#define ID_POPUP_ADVANCED_VIEWLOG       32797
+#define ID_POPUP_FAVORITES_PLAYALL      32798
+#define ID_POPUP_ADVANCED_ALLCHANNELS   32799
+#define ID_POPUP_ADVANCED_RELAYEDCHANNELS 32800
+#define ID_POPUP_ADVANCED_BROADCAST     32801
+#define ID_FIND_CHANNELS                32808
+#define ID_POPUP_SHOWMESSAGES_PEERCAST  32814
+#define ID_POPUP_SHOWMESSAGES_BROADCASTERS 32815
+#define ID_POPUP_SHOWMESSAGES_TRACKINFO 32816
+#define ID_POPUP_POPUPMESSAGES_UPGRADEALERTS 32817
+#define ID_POPUP_YELLOWPAGES            32818
+#define ID_POPUP_ADVANCED_SHOWGUI       32819
+#define ID_POPUP_YELLOWPAGES1           32820
+#define ID_POPUP_YELLOWPAGES2           32821
+#define ID_POPUP_SAVE_GUI_POS           32823
+#define ID_POPUP_KEEP_DOWNSTREAMS       32825
+#define IDC_STATIC                      -1
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        142
+#define _APS_NEXT_COMMAND_VALUE         32826
+#define _APS_NEXT_CONTROL_VALUE         1019
+#define _APS_NEXT_SYMED_VALUE           110
+#endif
+#endif
diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/small1.ico b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/small1.ico
new file mode 100644 (file)
index 0000000..fa5a5dc
Binary files /dev/null and b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/small1.ico differ
diff --git a/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/small3.ico b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/small3.ico
new file mode 100644 (file)
index 0000000..c7dee29
Binary files /dev/null and b/c:/Git/PeerCast.root/PeerCast/ui/win32/simple/small3.ico differ