Update EPG Cache(thanks to open source community)
authorhschang <chang@dev3>
Mon, 27 Aug 2018 06:52:33 +0000 (15:52 +0900)
committerhschang <chang@dev3>
Mon, 27 Aug 2018 06:52:33 +0000 (15:52 +0900)
29 files changed:
data/encoding.conf [changed mode: 0755->0644]
data/menu.xml [changed mode: 0755->0644]
data/setup.xml [changed mode: 0755->0644]
lib/base/Makefile.am
lib/base/encoding.cpp
lib/base/encoding.h
lib/base/estring.cpp
lib/base/estring.h
lib/base/freesatv2.cpp [new file with mode: 0644]
lib/base/freesatv2.h [new file with mode: 0644]
lib/dvb/db.cpp [changed mode: 0755->0644]
lib/dvb/db.h
lib/dvb/dvbtime.cpp
lib/dvb/dvbtime.h
lib/dvb/epgcache.cpp
lib/dvb/epgcache.h
lib/dvb/lowlevel/eit.h
lib/dvb/lowlevel/mhw.h
lib/python/Components/Converter/EventName.py
lib/python/Components/Converter/Makefile.am
lib/python/Components/Converter/genre.py [new file with mode: 0644]
lib/python/Components/UsageConfig.py
lib/python/Screens/InfoBarGenerics.py [changed mode: 0755->0644]
lib/service/event.cpp
lib/service/event.h
lib/service/iservice.h
lib/service/servicedvbrecord.cpp
lib/service/servicemp3.cpp [changed mode: 0755->0644]
lib/service/servicemp3.h

old mode 100755 (executable)
new mode 100644 (file)
index 36f619d..7e900e9
@@ -1,41 +1,56 @@
 #Fallback encoding when in dvb-text no encoding table is given
 #Fallback encoding when in dvb-text no encoding table is given
-#Countycode ISO8859-X or ISO6397
+#Countycode encoding, encoding may be ISO8859-X, ISO6937, UTF8, 
+#                  UTF-8,GB18030(GB2312/GBK/CP936), BIG5(CP950),
+#                  UNICODE(UTF16BE), UTF16LE
 ara ISO8859-6
 tur ISO8859-9
 gre ISO8859-7
 ara ISO8859-6
 tur ISO8859-9
 gre ISO8859-7
+ell ISO8859-7
 pol ISO8859-2
 rus ISO8859-5
 bul ISO8859-5
 tha ISO8859-11
 pol ISO8859-2
 rus ISO8859-5
 bul ISO8859-5
 tha ISO8859-11
-cze ISO6397
-ces ISO6397
-slo ISO6397
-slk ISO6397
+cze ISO6937
+ces ISO6937
+slo ISO6937
+slk ISO6937
+chi GB18030
+zho GB18030
+chn GB18030
+
+#Fallback encoding when in dvb-text no encoding table is given
+#and no Countrycode  and no transponders configs in this config file
+*   ISO8859-1
+
 #Sorry for that.. in DVB Spec this is the default behavior 
 #when no other encoding is given in dvb-texts..
 #but this breaks too much providers yet.. 
 #so our default is ISO8859-1 without two char byte encoding
 #So all transponders which needs this must be listed here
 #TSID ONID
 #Sorry for that.. in DVB Spec this is the default behavior 
 #when no other encoding is given in dvb-texts..
 #but this breaks too much providers yet.. 
 #so our default is ISO8859-1 without two char byte encoding
 #So all transponders which needs this must be listed here
 #TSID ONID
-0x447 0x1 # Astra 19.2°E 12.304 H - UPC Direct 
-0x427 0x1 # Astra 19.2°E 10.920 H - UPC Direct 
-0x44b 0x1 # Astra 19.2°E 12.382 H - UPC Direct
-0x4ff 0x1 # Astra 19.2°E 11.992 H - UPC Direct 
-0x407 0x1 # Astra 19.2°E 11.671 H - UPC Direct 
+0x2c1 0x600 #Thor 0.8°W
+0x2c2 0x600 #Thor 0.8°W
+0x2c3 0x600 #Thor 0.8°W
+0x2c4 0x600 #Thor 0.8°W
+0x2be 0x600 #Thor 0.8°W
+0x2bf 0x600 #Thor 0.8°W
+0x2bd 0x600 #Thor 0.8°W
+0x2c0 0x600 #Thor 0.8°W
+0x2c2 0x600 #Thor 0.8°W
+0x2c3 0x600 #Thor 0.8°W
+0x2c4 0x600 #Thor 0.8°W
+0x2c5 0x600 #Thor 0.8°W
+0x2c6 0x600 #Thor 0.8°W
+0x2c8 0x600 #Thor 0.8°W
+0xaf2 0xbb #Thor 0.8°W
 0x436 0x1 # Astra 19.2°E 11.973 V - MTV Networks Europe
 0x42a 0x1 # Astra 19.2°E 11.739 V - MTV Networks Europe
 0x436 0x1 # Astra 19.2°E 11.973 V - MTV Networks Europe
 0x42a 0x1 # Astra 19.2°E 11.739 V - MTV Networks Europe
-0xc23 0x3 # Astra 23.5°E 10.803 H - CS Link / SkyLink
-0xc85 0x3 # Astra 23.5°E 11.797 H - CS Link / SkyLink
-0xc89 0x3 # Astra 23.5°E 11.876 H - CS Link / SkyLink
-0xc8f 0x3 # Astra 23.5°E 11.992 H - CS Link / SkyLink
-0xc93 0x3 # Astra 23.5°E 12.070 H - CS Link / SkyLink
-0xc95 0x3 # Astra 23.5°E 12.109 H - SkyLink
-0xbc6 0x3 # Astra 23.5°E 12.525 V - CS Link / SkyLink
-0xbc7 0x3 # Astra 23.5°E 12.565 H - SkyLink
 200 318 #Hotbird Eutelsat (Eurosport)
 300 318 #Hotbird Eutelsat (Eurosport, Animal Pl.HD)
 400 318 #Hotbird 13.0 Cyfra+
 200 318 #Hotbird Eutelsat (Eurosport)
 300 318 #Hotbird Eutelsat (Eurosport, Animal Pl.HD)
 400 318 #Hotbird 13.0 Cyfra+
+700 318 #Hotbird 13.0 Cyfrowy Polsat
 1000 318 #Hotbird 13.0 Grupa ITI
 1000 318 #Hotbird 13.0 Grupa ITI
+1100 318 #Hotbird 13.0 Cyfra+
 1500 318 #Hotbird 13.0 Cyfra+
 1600 318 #Hotbird 13.0 Cyfra+
 2800 318 #Hotbird 13.0 MTV Networks (Comedy Central)
 1500 318 #Hotbird 13.0 Cyfra+
 1600 318 #Hotbird 13.0 Cyfra+
 2800 318 #Hotbird 13.0 MTV Networks (Comedy Central)
@@ -44,6 +59,7 @@ slk ISO6397
 7900 113 #Hotbird 13.0 Cyfrowy Polsat
 8100 113 #Hotbird 13.0 Universal (Cyfra+)
 8100 318 #Hotbird 13.0 Eutelsat (Universal)
 7900 113 #Hotbird 13.0 Cyfrowy Polsat
 8100 113 #Hotbird 13.0 Universal (Cyfra+)
 8100 318 #Hotbird 13.0 Eutelsat (Universal)
+8900 318 #Hotbird 13.0 BBC Brit HD Poland
 11000 318 #Hotbird 13.0 Cyfra+
 11400 318 #Hotbird 13.0 Cyfra+
 11600 318 #Hotbird 13.0 BBC HD, ITI
 11000 318 #Hotbird 13.0 Cyfra+
 11400 318 #Hotbird 13.0 Cyfra+
 11600 318 #Hotbird 13.0 BBC HD, ITI
@@ -54,19 +70,49 @@ slk ISO6397
 13000 318 #Hotbird 13.0 BBC Polska and other
 13100 318 #Hotbird 13.0 Crime and Investigation
 13200 113 #Hotbird 13.0 Cyfrowy Polsat
 13000 318 #Hotbird 13.0 BBC Polska and other
 13100 318 #Hotbird 13.0 Crime and Investigation
 13200 113 #Hotbird 13.0 Cyfrowy Polsat
+15700 318 #Hotbird 13.0 Belgium Satellite Services - TV DISCO
+0x801 0x600 # Ziggo NL
+0x802 0x600 # Ziggo NL
+0x803 0x600 # Ziggo NL
+0x806 0x600 # Ziggo NL
+0x809 0x600 # Ziggo NL
+0x80a 0x600 # Ziggo NL
+0x80d 0x600 # Ziggo NL
+0x80e 0x600 # Ziggo NL
+0x80f 0x600 # Ziggo NL
+0x810 0x600 # Ziggo NL
+0x812 0x600 # Ziggo NL
+0x813 0x600 # Ziggo NL
+0x815 0x600 # Ziggo NL
+0x817 0x600 # Ziggo NL
+0x819 0x600 # Ziggo NL
+0x81a 0x600 # Ziggo NL
+0x81c 0x600 # Ziggo NL
+0x831 0x600 # Ziggo NL
+0x832 0x600 # Ziggo NL
+0x833 0x600 # Ziggo NL
+0x834 0x600 # Ziggo NL
+0x835 0x600 # Ziggo NL
+0x836 0x600 # Ziggo NL
+0x83a 0x600 # Ziggo NL
+0x840 0x600 # Ziggo NL
 #Fallback encoding table for single transponders
 #Fallback encoding table for single transponders
-#ISO6397 also enables two byte char encoding
+#ISO6937 also enables two byte char encoding
 #TSID ONID ISO8859-X
 #TSID ONID ISO8859-X
-#12800 318 ISO6397 #Viacom ... MTV / VH1 Polska
-21100 126 ISO8859-9 # Digital Platform 7°E 10.928 H 30.000 2/3 8PSK
-41200 126 ISO8859-9 # Digital Platform 7°E 11.451 V 25.066 2/3
-50100 126 ISO8859-9 # Digital Platform 7°E 11.471 H 30.000 3/4
-50200 126 ISO8859-9 # Digital Platform 7°E 11.492 V 30.000 3/4
-50300 126 ISO8859-9 # Digital Platform 7°E 11.639 H 30.000 3/4
-50400 126 ISO8859-9 # Digital Platform 7°E 11.534 V 30.000 3/4
-50500 126 ISO8859-9 # Digital Platform 7°E 11.262 H 27.500 3/4
-50600 126 ISO8859-9 # Digital Platform 7°E 11.575 V and 42°E 11.729 V 15.555 5/6
-50700 126 ISO8859-9 # Digital Platform 7°E 11.596 H 30.000 3/4
-50800 126 ISO8859-9 # Digital Platform 7°E 11.678 H 30.000 3/4
-50900 126 ISO8859-9 # Digital Platform 7°E 11.513 H 27.500 3/4
-51000 126 ISO8859-9 # Digital Platform 7°E 11.617 V 30.000 3/4
+20600 126 ISO8859-9 # Digital Platform 7°E
+20700 126 ISO8859-9 # Digital Platform 7°E
+20800 126 ISO8859-9 # Digital Platform 7°E
+20900 126 ISO8859-9 # Digital Platform 7°E
+21000 126 ISO8859-9 # Digital Platform 7°E
+21100 126 ISO8859-9 # Digital Platform 7°E
+41200 126 ISO8859-9 # Digital Platform 7°E
+50100 126 ISO8859-9 # Digital Platform 7°E
+50200 126 ISO8859-9 # Digital Platform 7°E
+50300 126 ISO8859-9 # Digital Platform 7°E
+50400 126 ISO8859-9 # Digital Platform 7°E
+50500 126 ISO8859-9 # Digital Platform 7°E
+50600 126 ISO8859-9 # Digital Platform 7°E
+50700 126 ISO8859-9 # Digital Platform 7°E
+50800 126 ISO8859-9 # Digital Platform 7°E
+50900 126 ISO8859-9 # Digital Platform 7°E
+51000 126 ISO8859-9 # Digital Platform 7°E
old mode 100755 (executable)
new mode 100644 (file)
index ed0b415..7ab36e7
@@ -54,6 +54,7 @@
                                <item level="0" entryID="av_setup"><setup id="avsetup"/></item>
                                <!--<item level="0" text="Video Setup" entryID="video_setup"><screen module="VideoSetup" /></item>-->
                                <item level="1" entryID="rfmod_setup" requires="RfModulator"><setup id="RFmod"/></item>
                                <item level="0" entryID="av_setup"><setup id="avsetup"/></item>
                                <!--<item level="0" text="Video Setup" entryID="video_setup"><screen module="VideoSetup" /></item>-->
                                <item level="1" entryID="rfmod_setup" requires="RfModulator"><setup id="RFmod"/></item>
+                               <item level="2" entryID="epg_settings"><setup id="epgsettings"/></item>
                                <menu level="0" text="Harddisk" entryID="hardisk_selection" requires="Harddisk">
                                        <id val="harddisk" />
                                        <item level="1" entryID="harddisk_setup"><setup id="harddisk"/></item>
                                <menu level="0" text="Harddisk" entryID="hardisk_selection" requires="Harddisk">
                                        <id val="harddisk" />
                                        <item level="1" entryID="harddisk_setup"><setup id="harddisk"/></item>
old mode 100755 (executable)
new mode 100644 (file)
index 9fb4a56..aabb58f
                        <item level="2" text="Always include ECM in recordings" requires="ScrambledPlayback" description="Always include ECM messages in recordings. This overrides the individual timer settings globally. It allows recordings to be always decrypted afterwards (sometimes called offline decoding), if supported by your receiver. Default: off.">config.recording.always_ecm</item>
                        <item level="2" text="Never decrypt while recording" requires="ScrambledPlayback" description="Never decrypt the content while recording. This overrides the individual timer settings globally. If enabled, recordings are stored in crypted presentation and must be decrypted afterwards (sometimes called offline decoding). Default: off.">config.recording.never_decrypt</item>
                </setup>
                        <item level="2" text="Always include ECM in recordings" requires="ScrambledPlayback" description="Always include ECM messages in recordings. This overrides the individual timer settings globally. It allows recordings to be always decrypted afterwards (sometimes called offline decoding), if supported by your receiver. Default: off.">config.recording.always_ecm</item>
                        <item level="2" text="Never decrypt while recording" requires="ScrambledPlayback" description="Never decrypt the content while recording. This overrides the individual timer settings globally. If enabled, recordings are stored in crypted presentation and must be decrypted afterwards (sometimes called offline decoding). Default: off.">config.recording.never_decrypt</item>
                </setup>
+               <setup key="epgsettings" title="EPG settings">
+                       <item level="1" text="EPG language selection 1" description="Configure the primary EPG language.">config.autolanguage.epglanguage</item>
+                       <item level="1" text="EPG language selection 2" description="Configure the secondary EPG language.">config.autolanguage.epglanguage_alternative</item>
+                       <item level="0" text="Enable EIT EPG" description="Use EIT EPG information when it is available.">config.epg.eit</item>
+                       <item level="2" text="Enable MHW EPG" description="Use MHW EPG information when it is available.">config.epg.mhw</item>
+                       <item level="1" text="Enable freesat EPG" description="Use FreeSat EPG information when it is available.">config.epg.freesat</item>
+                       <item level="1" text="Enable ViaSat EPG" description="Use ViaSat EPG information when it is available.">config.epg.viasat</item>
+                       <item level="1" text="Enable Netmed EPG" description="Use Netmed EPG information when it is available.">config.epg.netmed</item>
+                       <item level="1" text="Enable Virgin EPG" description="Use Virgin EPG information when it is available.">config.epg.virgin</item>
+                       <item level="2" text="Maintain old EPG data for (min)" description="Configure for how many minutes finished events should remain visible in the EPG. Useful when you need information about an event which has just finished, or has been delayed.">config.epg.histminutes</item>
+               </setup>
                <setup key="subtitlesetup" title="Subtitle settings">
                        <item level="2" text="Subtitle font color" description="Configure the color of the subtitles.">config.subtitles.subtitle_fontcolor</item>
                        <item level="2" text="Subtitle font size" description="Configure the font size of the subtitles.">config.subtitles.subtitle_fontsize</item>
                <setup key="subtitlesetup" title="Subtitle settings">
                        <item level="2" text="Subtitle font color" description="Configure the color of the subtitles.">config.subtitles.subtitle_fontcolor</item>
                        <item level="2" text="Subtitle font size" description="Configure the font size of the subtitles.">config.subtitles.subtitle_fontsize</item>
index ca9483d..bbd8434 100644 (file)
@@ -26,7 +26,8 @@ libenigma_base_a_SOURCES = \
        smartptr.cpp \
        thread.cpp \
        httpstream.cpp \
        smartptr.cpp \
        thread.cpp \
        httpstream.cpp \
-       socketbase.cpp
+       socketbase.cpp \
+       freesatv2.cpp
 
 EXTRA_DIST = \
        eenv.cpp.in
 
 EXTRA_DIST = \
        eenv.cpp.in
@@ -57,4 +58,5 @@ baseinclude_HEADERS = \
        smartptr.h \
        thread.h \
        httpstream.h \
        smartptr.h \
        thread.h \
        httpstream.h \
-       socketbase.h
+       socketbase.h \
+       freesatv2.h 
index 361acce..5609be4 100644 (file)
@@ -5,15 +5,16 @@
 #include <lib/base/eenv.h>
 
 eDVBTextEncodingHandler encodingHandler;  // the one and only instance
 #include <lib/base/eenv.h>
 
 eDVBTextEncodingHandler encodingHandler;  // the one and only instance
+int defaultEncodingTable = 1; // ISO8859-1 / Latin1
 
 inline char toupper(char c)
 {
 
 inline char toupper(char c)
 {
-       switch (c)
-       {
-               case 'a' ... 'z':
-                       return c-32;
-       }
-       return c;
+       return (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c;
+}
+
+inline char tolower(char c)
+{
+       return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c;
 }
 
 eDVBTextEncodingHandler::eDVBTextEncodingHandler()
 }
 
 eDVBTextEncodingHandler::eDVBTextEncodingHandler()
@@ -41,10 +42,10 @@ eDVBTextEncodingHandler::eDVBTextEncodingHandler()
                                countrycode[2]=toupper(countrycode[2]);
                                m_CountryCodeDefaultMapping[countrycode]=encoding;
                        }
                                countrycode[2]=toupper(countrycode[2]);
                                m_CountryCodeDefaultMapping[countrycode]=encoding;
                        }
-                       else if ( (sscanf( line, "0x%x 0x%x ISO%d", &tsid, &onid, &encoding ) == 3 && encoding == 6397 )
-                                       ||(sscanf( line, "%d %d ISO%d", &tsid, &onid, &encoding ) == 3 && encoding == 6397 ) )
+                       else if ( (sscanf( line, "0x%x 0x%x ISO%d", &tsid, &onid, &encoding ) == 3 && encoding == 6937 )
+                                       ||(sscanf( line, "%d %d ISO%d", &tsid, &onid, &encoding ) == 3 && encoding == 6937 ) )
                                m_TransponderDefaultMapping[(tsid<<16)|onid]=0;
                                m_TransponderDefaultMapping[(tsid<<16)|onid]=0;
-                       else if ( sscanf( line, "%s ISO%d", countrycode, &encoding ) == 2 && encoding == 6397 )
+                       else if ( sscanf( line, "%s ISO%d", countrycode, &encoding ) == 2 && encoding == 6937 )
                        {
                                m_CountryCodeDefaultMapping[countrycode]=0;
                                countrycode[0]=toupper(countrycode[0]);
                        {
                                m_CountryCodeDefaultMapping[countrycode]=0;
                                countrycode[0]=toupper(countrycode[0]);
@@ -67,7 +68,7 @@ eDVBTextEncodingHandler::eDVBTextEncodingHandler()
 
 void eDVBTextEncodingHandler::getTransponderDefaultMapping(int tsidonid, int &table)
 {
 
 void eDVBTextEncodingHandler::getTransponderDefaultMapping(int tsidonid, int &table)
 {
-       std::map<int, int>::iterator it =
+       std::map<unsigned int, int>::iterator it =
                m_TransponderDefaultMapping.find(tsidonid);
        if ( it != m_TransponderDefaultMapping.end() )
                table = it->second;
                m_TransponderDefaultMapping.find(tsidonid);
        if ( it != m_TransponderDefaultMapping.end() )
                table = it->second;
@@ -84,5 +85,5 @@ int eDVBTextEncodingHandler::getCountryCodeDefaultMapping( const std::string &co
                m_CountryCodeDefaultMapping.find(country_code);
        if ( it != m_CountryCodeDefaultMapping.end() )
                return it->second;
                m_CountryCodeDefaultMapping.find(country_code);
        if ( it != m_CountryCodeDefaultMapping.end() )
                return it->second;
-       return 1;  // ISO8859-1 / Latin1
+       return defaultEncodingTable;
 }
 }
index 2a58da2..76f9393 100644 (file)
@@ -5,10 +5,30 @@
 #include <set>
 #include <map>
 
 #include <set>
 #include <map>
 
+#define ISO8859_5                      0x01    // Latin/Cyrillic
+#define ISO8859_6                      0x02    // Latin/Arabic
+#define ISO8859_7                      0x03    // Latin/Greek
+#define ISO8859_8                      0x04    // Latin/Gebrew
+#define ISO8859_9                      0x05    // Latin 5
+#define ISO8859_10                     0x06    // Latin 6
+#define ISO8859_11                     0x07    // Latin/Thai
+#define ISO8859_12                     0x08    // Reserved
+#define ISO8859_13                     0x09    // Latin 7
+#define ISO8859_14                     0x0A    // Latin 8 (Celtic)
+#define ISO8859_15                     0x0B    // Latin 9
+#define ISO8859_xx                     0x10    // encoded in next two bytes
+#define UNICODE_ENCODING               0x11    // ISO10646 Basic Multilingual Plane
+#define KSX1001_ENCODING               0x12    // KSX1001 Korean
+#define GB18030_ENCODING               0x13    // ISO10646 Simplified Chinese
+#define BIG5_ENCODING                  0x14    // ISO10646 Big5 Traditional Chineese
+#define UTF8_ENCODING                  0x15    // ISO10646 Basic Multilingual Plane in UTF8 encoding
+#define UTF16BE_ENCODING               0x16
+#define UTF16LE_ENCODING               0x17
+
 class eDVBTextEncodingHandler
 {
        std::map<std::string, int> m_CountryCodeDefaultMapping;
 class eDVBTextEncodingHandler
 {
        std::map<std::string, int> m_CountryCodeDefaultMapping;
-       std::map<int, int> m_TransponderDefaultMapping;
+       std::map<unsigned int, int> m_TransponderDefaultMapping;
        std::set<int> m_TransponderUseTwoCharMapping;
 public:
        eDVBTextEncodingHandler();
        std::set<int> m_TransponderUseTwoCharMapping;
 public:
        eDVBTextEncodingHandler();
@@ -18,5 +38,5 @@ public:
 };
 
 extern eDVBTextEncodingHandler encodingHandler;
 };
 
 extern eDVBTextEncodingHandler encodingHandler;
-
+extern int defaultEncodingTable;
 #endif // __lib_base_encoding_h__
 #endif // __lib_base_encoding_h__
index f2ac732..10bc89c 100644 (file)
@@ -5,18 +5,19 @@
 #include <lib/base/eerror.h>
 #include <lib/base/encoding.h>
 #include <lib/base/estring.h>
 #include <lib/base/eerror.h>
 #include <lib/base/encoding.h>
 #include <lib/base/estring.h>
+#include "freesatv2.h"
 
 std::string buildShortName( const std::string &str )
 {
        std::string tmp;
 
 std::string buildShortName( const std::string &str )
 {
        std::string tmp;
-       static char stropen[3] = { 0xc2, 0x86, 0x00 };
-       static char strclose[3] = { 0xc2, 0x87, 0x00 };
-       size_t open=std::string::npos-1;
-       while ( (open = str.find(stropen, open+2)) != std::string::npos )
+       static char stropen[] = "\xc2\x86";
+       static char strclose[] = "\xc2\x87";
+       size_t open = std::string::npos-1;
+       while ((open = str.find(stropen, open+2)) != std::string::npos)
        {
                size_t close = str.find(strclose, open);
        {
                size_t close = str.find(strclose, open);
-               if ( close != std::string::npos )
-                       tmp+=str.substr( open+2, close-(open+2) );
+               if (close != std::string::npos)
+                       tmp += str.substr(open+2, close-(open+2));
        }
        return tmp.length() ? tmp : str;
 }
        }
        return tmp.length() ? tmp : str;
 }
@@ -30,8 +31,8 @@ std::string getNum(int val, int sys)
        if (sys == 10)
                snprintf(buf, 12, "%i", val);
        else if (sys == 16)
        if (sys == 10)
                snprintf(buf, 12, "%i", val);
        else if (sys == 16)
-               snprintf(buf, 12, "%X", val);           
-       
+               snprintf(buf, 12, "%X", val);
+
        std::string res;
        res.assign(buf);
        return res;
        std::string res;
        res.assign(buf);
        return res;
@@ -151,7 +152,9 @@ static unsigned long c885916[96]={
 0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x0107, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
 0x0111, 0x0144, 0x00F2, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x015B, 0x0171, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0119, 0x021B, 0x00FF};
 
 0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x0107, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
 0x0111, 0x0144, 0x00F2, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x015B, 0x0171, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0119, 0x021B, 0x00FF};
 
-static unsigned long iso6397[96]={
+static freesatHuffmanDecoder huffmanDecoder;
+
+static unsigned long iso6937[96]={
 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AC, 0x00A5, 0x0000, 0x00A7, 0x00A4, 0x2018, 0x201C, 0x00AB, 0x2190, 0x2191, 0x2192, 0x2193,
 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00D7, 0x00B5, 0x00B6, 0x00B7, 0x00F7, 0x2019, 0x201D, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
 0x0000, 0xE002, 0xE003, 0xE004, 0xE005, 0xE006, 0xE007, 0xE008, 0xE009, 0xE00C, 0xE00A, 0xE00B, 0x0000, 0xE00D, 0xE00E, 0xE00F,
 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AC, 0x00A5, 0x0000, 0x00A7, 0x00A4, 0x2018, 0x201C, 0x00AB, 0x2190, 0x2191, 0x2192, 0x2193,
 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00D7, 0x00B5, 0x00B6, 0x00B7, 0x00F7, 0x2019, 0x201D, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
 0x0000, 0xE002, 0xE003, 0xE004, 0xE005, 0xE006, 0xE007, 0xE008, 0xE009, 0xE00C, 0xE00A, 0xE00B, 0x0000, 0xE00D, 0xE00E, 0xE00F,
@@ -159,7 +162,7 @@ static unsigned long iso6397[96]={
 0x2126, 0x00C6, 0x0110, 0x00AA, 0x0126, 0x0000, 0x0132, 0x013F, 0x0141, 0x00D8, 0x0152, 0x00BA, 0x00DE, 0x0166, 0x014A, 0x0149,
 0x0138, 0x00E6, 0x0111, 0x00F0, 0x0127, 0x0131, 0x0133, 0x0140, 0x0142, 0x00F8, 0x0153, 0x00DF, 0x00FE, 0x0167, 0x014B, 0x00AD};
 
 0x2126, 0x00C6, 0x0110, 0x00AA, 0x0126, 0x0000, 0x0132, 0x013F, 0x0141, 0x00D8, 0x0152, 0x00BA, 0x00DE, 0x0166, 0x014A, 0x0149,
 0x0138, 0x00E6, 0x0111, 0x00F0, 0x0127, 0x0131, 0x0133, 0x0140, 0x0142, 0x00F8, 0x0153, 0x00DF, 0x00FE, 0x0167, 0x014B, 0x00AD};
 
-// Two Char Mapping (aka ISO6397) ( many polish services and UPC Direct/HBO services)
+// Two Char Mapping (aka ISO6937) ( many polish services and UPC Direct/HBO services)
 // get from http://mitglied.lycos.de/buran/charsets/videotex-suppl.html
 static inline unsigned int doVideoTexSuppl(int c1, int c2)
 {
 // get from http://mitglied.lycos.de/buran/charsets/videotex-suppl.html
 static inline unsigned int doVideoTexSuppl(int c1, int c2)
 {
@@ -325,43 +328,49 @@ static inline unsigned int recode(unsigned char d, int cp)
                return d;
        switch (cp)
        {
                return d;
        switch (cp)
        {
-       case 0:         // ISO6397
-               return iso6397[d-0xA0];
-       case 1:         // 8859-1 <-> unicode mapping
-               return d;
-       case 2:         // 8859-2 -> unicode mapping
-               return c88592[d-0xA0];
-       case 3:         // 8859-3 -> unicode mapping
-               return c88593[d-0xA0];
-       case 4:         // 8859-2 -> unicode mapping
-               return c88594[d-0xA0];
-       case 5:         // 8859-5 -> unicode mapping
-               return c88595[d-0xA0];
-       case 6:         // 8859-6 -> unicode mapping
-               return c88596[d-0xA0];
-       case 7:         // 8859-7 -> unicode mapping
-               return c88597[d-0xA0];
-       case 8:         // 8859-8 -> unicode mapping
-               return c88598[d-0xA0];
-       case 9:         // 8859-9 -> unicode mapping
-               return c88599[d-0xA0];
-       case 10:// 8859-10 -> unicode mapping
-               return c885910[d-0xA0];
-       case 11:// 8859-11 -> unicode mapping
-               return c885911[d-0xA0];
-/*     case 12:// 8859-12 -> unicode mapping  // reserved for indian use..
-               return c885912[d-0xA0];*/
-       case 13:// 8859-13 -> unicode mapping
-               return c885913[d-0xA0];
-       case 14:// 8859-14 -> unicode mapping
-               return c885914[d-0xA0];
-       case 15:// 8859-15 -> unicode mapping
-               return c885915[d-0xA0];
-       case 16:// 8859-16 -> unicode mapping
-               return c885916[d-0xA0];
-       default:
-               return d;
+       case 0:  return iso6937[d-0xA0]; // ISO6937
+       case 1:  return d;               // 8859-1 -> unicode mapping
+       case 2:  return c88592[d-0xA0];  // 8859-2 -> unicode mapping
+       case 3:  return c88593[d-0xA0];  // 8859-3 -> unicode mapping
+       case 4:  return c88594[d-0xA0];  // 8859-2 -> unicode mapping
+       case 5:  return c88595[d-0xA0];  // 8859-5 -> unicode mapping
+       case 6:  return c88596[d-0xA0];  // 8859-6 -> unicode mapping
+       case 7:  return c88597[d-0xA0];  // 8859-7 -> unicode mapping
+       case 8:  return c88598[d-0xA0];  // 8859-8 -> unicode mapping
+       case 9:  return c88599[d-0xA0];  // 8859-9 -> unicode mapping
+       case 10: return c885910[d-0xA0]; // 8859-10 -> unicode mapping
+       case 11: return c885911[d-0xA0]; // 8859-11 -> unicode mapping
+//     case 12: return c885912[d-0xA0]; // 8859-12 -> unicode mapping  // reserved for indian use..
+       case 13: return c885913[d-0xA0]; // 8859-13 -> unicode mapping
+       case 14: return c885914[d-0xA0]; // 8859-14 -> unicode mapping
+       case 15: return c885915[d-0xA0]; // 8859-15 -> unicode mapping
+       case 16: return c885916[d-0xA0]; // 8859-16 -> unicode mapping
+       default: return d;
+       }
+}
+
+std::string UnicodeToUTF8(long c)
+{
+       if ( c < 0x80 ) {
+               char utf[2] = {static_cast<char>(c), 0};
+               return std::string(utf, 1);
+       }
+       else if ( c < 0x800) {
+               char utf[3] = { static_cast<char>(0xc0 | (c >> 6)), static_cast<char>(0x80 | (c & 0x3f)), 0};
+               return std::string(utf, 2);
+       }
+       else if ( c < 0x10000) {
+               char utf[4] = { static_cast<char>(0xe0 | (c >> 12)), static_cast<char>(0x80 | ((c >> 6) & 0x3f)),
+                               static_cast<char>(0x80 | (c & 0x3f)), 0};
+               return std::string(utf, 3);
+       }
+       else if ( c < 0x200000) {
+               char utf[5] = { static_cast<char>(0xf0 | (c >> 18)), static_cast<char>(0x80 | ((c >> 12) & 0x3f)),
+                               static_cast<char>(0x80 | ((c >> 6) & 0x3f)), static_cast<char>(0x80 | (c & 0x3f)), 0};
+               return std::string(utf, 4);
        }
        }
+       eDebug("[UnicodeToUTF8] invalid unicode character: code=0x%08lx", c); // not a valid unicode
+       return "";
 }
 
 std::string convertDVBUTF8(const unsigned char *data, int len, int table, int tsidonid)
 }
 
 std::string convertDVBUTF8(const unsigned char *data, int len, int table, int tsidonid)
@@ -369,57 +378,82 @@ std::string convertDVBUTF8(const unsigned char *data, int len, int table, int ts
        if (!len)
                return "";
 
        if (!len)
                return "";
 
-       int i=0, t=0;
+       int i = 0;
+       std::string output = "";
 
 
-       if ( tsidonid )
+       if (tsidonid)
                encodingHandler.getTransponderDefaultMapping(tsidonid, table);
 
                encodingHandler.getTransponderDefaultMapping(tsidonid, table);
 
+       // first byte in strings may override general encoding table.
        switch(data[0])
        {
        switch(data[0])
        {
-               case 1 ... 11:
-                       table=data[i++]+4;
-//                     eDebug("(1..11)text encoded in ISO-8859-%d",table);
+               case ISO8859_5 ... ISO8859_15:
+                       // For Thai providers, encoding char is present but faulty.
+                       if (table != 11)
+                               table = data[i] + 4;
+                       ++i;
+//                     eDebug("[convertDVBUTF8] (1..11)text encoded in ISO-8859-%d", table);
                        break;
                        break;
-               case 0x10:
+               case ISO8859_xx:
                {
                {
-                       int n=(data[++i]<<8);
+                       int n = data[++i] << 8;
                        n |= (data[++i]);
                        n |= (data[++i]);
-//                     eDebug("(0x10)text encoded in ISO-8859-%d",n);
+//                     eDebug("[convertDVBUTF8] (0x10)text encoded in ISO-8859-%d",n);
                        ++i;
                        switch(n)
                        {
                        ++i;
                        switch(n)
                        {
-                               case 12:
-                                       eDebug("unsup. ISO8859-12 enc.");
+                               case 0x0C: // ETSI EN 300 468 Table A.4: Reserved for future use
+                                       eDebug("[convertDVBUTF8] ISO 8859-12 encoding unsupported");
                                        break;
                                default:
                                        break;
                                default:
-                                       table=n;
+                                       table = n;
                                        break;
                        }
                        break;
                }
                                        break;
                        }
                        break;
                }
-               case 0x11: //  Basic Multilingual Plane of ISO/IEC 10646-1 enc  (UTF-16... Unicode)
-                       table = 65;
+               case UNICODE_ENCODING: //  Basic Multilingual Plane of ISO/IEC 10646-1 enc  (UTF-16... Unicode)
+                       table = UNICODE_ENCODING;
                        tsidonid = 0;
                        ++i;
                        break;
                        tsidonid = 0;
                        ++i;
                        break;
-               case 0x12:
+               case KSX1001_ENCODING:
+                       ++i;
+                       eDebug("[convertDVBUTF8] KSC 5601 encoding unsupported.");
+                       break;
+               case GB18030_ENCODING:
                        ++i;
                        ++i;
-                       eDebug("unsup. KSC 5601 enc.");
+                       eDebug("[convertDVBUTF8] GB-2312-1980 encoding unsupported.");
                        break;
                        break;
-               case 0x13:
+               case BIG5_ENCODING:
                        ++i;
                        ++i;
-                       eDebug("unsup. GB-2312-1980 enc.");
+                       eDebug("[convertDVBUTF8] Big5 subset of ISO/IEC 10646-1 encoding unsupported.");
                        break;
                        break;
-               case 0x14:
+               case UTF8_ENCODING: // UTF-8 encoding of ISO/IEC 10646-1
+                       ++i;
+                       table = UTF8_ENCODING;
+                       break;
+               case UTF16BE_ENCODING:
+                       ++i;
+                       table = UTF16BE_ENCODING;
+                       break;
+               case UTF16LE_ENCODING:
+                       ++i;
+                       table = UTF16LE_ENCODING;
+                       break;
+               case 0x1F:
+                       {
+                               // Attempt to decode Freesat Huffman encoded string
+                               std::string decoded_string = huffmanDecoder.decode(data, len);
+                               if (!decoded_string.empty())
+                                       return decoded_string;
+                       }
                        ++i;
                        ++i;
-                       eDebug("unsup. Big5 subset of ISO/IEC 10646-1 enc.");
+                       eDebug("[convertDVBUTF8] failed to decode bbc freesat huffman");
                        break;
                        break;
-               case 0x15: // UTF-8 encoding of ISO/IEC 10646-1
-                       return std::string((char*)data+1, len-1);
                case 0x0:
                case 0xC ... 0xF:
                case 0x0:
                case 0xC ... 0xF:
-               case 0x16 ... 0x1F:
-                       eDebug("reserved %d", data[0]);
+               case 0x18 ... 0x1E:
+                       eDebug("[convertDVBUTF8] reserved %d", data[0]);
                        ++i;
                        break;
        }
                        ++i;
                        break;
        }
@@ -427,54 +461,75 @@ std::string convertDVBUTF8(const unsigned char *data, int len, int table, int ts
        bool useTwoCharMapping = !table || (tsidonid && encodingHandler.getTransponderUseTwoCharMapping(tsidonid));
 
        if (useTwoCharMapping && table == 5) { // i hope this dont break other transponders which realy use ISO8859-5 and two char byte mapping...
        bool useTwoCharMapping = !table || (tsidonid && encodingHandler.getTransponderUseTwoCharMapping(tsidonid));
 
        if (useTwoCharMapping && table == 5) { // i hope this dont break other transponders which realy use ISO8859-5 and two char byte mapping...
-//             eDebug("Cyfra / Cyfrowy Polsat HACK... override given ISO8859-5 with ISO6397");
+//             eDebug("[convertDVBUTF8] Cyfra / Cyfrowy Polsat HACK... override given ISO8859-5 with ISO6937");
                table = 0;
        }
                table = 0;
        }
+       else if ( table == -1 )
+               table = defaultEncodingTable;
 
 
-       unsigned char res[2048];
-       while (i < len)
+       switch(table)
        {
        {
-               unsigned long code=0;
-               if ( useTwoCharMapping && i+1 < len && (code=doVideoTexSuppl(data[i], data[i+1])) )
-                       i+=2;
-               if (!code) {
-                       if (table == 65) { // unicode
-                               if (i+1 < len) {
-                                       code=(data[i] << 8) | data[i+1];
+               case UTF8_ENCODING:
+                       output = std::string((char*)data + i, len - i);
+                       break;
+               default:
+                       std::string res = "";
+                       while (i < len)
+                       {
+                               unsigned long code = 0;
+                               if (useTwoCharMapping && i+1 < len && (code = doVideoTexSuppl(data[i], data[i+1])))
                                        i += 2;
                                        i += 2;
+                               else if (table == UTF16BE_ENCODING || table == UNICODE_ENCODING) {
+                                       if (i+2 > len)
+                                               break;
+                                       unsigned long w1 = ((unsigned long)(data[i])<<8) | ((unsigned long)(data[i+1]));
+                                       if (w1 < 0xD800UL || w1 > 0xDFFFUL) {
+                                               code = w1;
+                                               i += 2;
+                                       }
+                                       else if (w1 > 0xDBFFUL)
+                                               break;
+                                       else if (i+4 < len) {
+                                               unsigned long w2 = ((unsigned long)(data[i+2]) << 8) | ((unsigned long)(data[i+3]));
+                                               if (w2 < 0xDC00UL || w2 > 0xDFFFUL)
+                                                       return std::string("");
+                                               code = 0x10000UL + (((w1 & 0x03FFUL) << 10 ) | (w2 & 0x03FFUL));
+                                               i += 4;
+                                       }
+                                       else
+                                               break;
                                }
                                }
+                               else if (table == UTF16LE_ENCODING) {
+                                       if ((i+2) > len)
+                                               break;
+                                       unsigned long w1 = ((unsigned long)(data[i+1]) << 8) | ((unsigned long)(data[i]));
+                                       if (w1 < 0xD800UL || w1 > 0xDFFFUL) {
+                                               code = w1;
+                                               i += 2;
+                                       }
+                                       else if (w1 > 0xDBFFUL)
+                                               break;
+                                       else if (i+4 < len) {
+                                               unsigned long w2 = ((unsigned long)(data[i+3]) << 8) | ((unsigned long)(data[i+2]));
+                                               if (w2 < 0xDC00UL || w2 > 0xDFFFUL)
+                                                       break;
+                                               code = 0x10000UL + (((w2 & 0x03FFUL) << 10 ) | (w1 & 0x03FFUL));
+                                               i += 4;
+                                       }
+                                       else
+                                               break;
+                               }
+                               if (!code)
+                                       code = recode(data[i++], table);
+
+                               if (!code)
+                                       continue;
+                               res += UnicodeToUTF8(code);
                        }
                        }
-                       else
-                               code=recode(data[i++], table);
-               }
-               if (!code)
-                       continue;
-                               // Unicode->UTF8 encoding
-               if (code < 0x80) // identity ascii <-> utf8 mapping
-                       res[t++]=char(code);
-               else if (code < 0x800) // two byte mapping
-               {
-                       res[t++]=(code>>6)|0xC0;
-                       res[t++]=(code&0x3F)|0x80;
-               } else if (code < 0x10000) // three bytes mapping
-               {
-                       res[t++]=(code>>12)|0xE0;
-                       res[t++]=((code>>6)&0x3F)|0x80;
-                       res[t++]=(code&0x3F)|0x80;
-               } else
-               {
-                       res[t++]=(code>>18)|0xF0;
-                       res[t++]=((code>>12)&0x3F)|0x80;
-                       res[t++]=((code>>6)&0x3F)|0x80;
-                       res[t++]=(code&0x3F)|0x80;
-               }
-               if (t+4 > 2047)
-               {
-                       eDebug("convertDVBUTF8 buffer to small.. break now");
+                       output = res;
                        break;
                        break;
-               }
        }
        }
-       return std::string((char*)res, t);
+       return output;
 }
 
 std::string convertUTF8DVB(const std::string &string, int table)
 }
 
 std::string convertUTF8DVB(const std::string &string, int table)
@@ -485,171 +540,141 @@ std::string convertUTF8DVB(const std::string &string, int table)
 
        unsigned char buf[len];
 
 
        unsigned char buf[len];
 
-       for(int i=0;i<len;i++)
+       for (int i = 0; i < len; i++)
        {
        {
-               unsigned char c1=string[i];
+               unsigned char c1 = string[i];
                unsigned int c;
                unsigned int c;
-               if(c1<0x80)
-                       c=c1;
+               if (c1 < 0x80)
+                       c = c1;
                else
                {
                else
                {
-                       i++;
-                       unsigned char c2=string[i];
-                       c=((c1&0x3F)<<6) + (c2&0x3F);
-                       if (table==0||table==1||c1<0xA0)
+                       ++i;
+                       unsigned char c2 = string[i];
+                       c = ((c1&0x3F)<<6) + (c2&0x3F);
+                       if (table == 0 || table == 1 || c1 < 0xA0)
                                ;
                        else
                        {
                                if (!coding_table)
                                {
                                ;
                        else
                        {
                                if (!coding_table)
                                {
-                                       switch(table)
+                                       switch (table)
                                        {
                                        {
-                                               case 2:
-                                                       coding_table = c88592;
-                                                       break;
-                                               case 3:
-                                                       coding_table = c88593;
-                                                       break;
-                                               case 4:
-                                                       coding_table = c88594;
-                                                       break;
-                                               case 5:
-                                                       coding_table = c88595;
-                                                       break;
-                                               case 6:
-                                                       coding_table = c88596;
-                                                       break;
-                                               case 7:
-                                                       coding_table = c88597;
-                                                       break;
-                                               case 8:
-                                                       coding_table = c88598;
-                                                       break;
-                                               case 9:
-                                                       coding_table = c88599;
-                                                       break;
-                                               case 10:
-                                                       coding_table = c885910;
-                                                       break;
-                                               case 11:
-                                                       coding_table = c885911;
-                                                       break;
-/*                                             case 12:   // reserved.. for indian use
-                                                       coding_table = c885912;
-                                               break;*/
-                                               case 13:
-                                                       coding_table = c885913;
-                                                       break;
-                                               case 14:
-                                                       coding_table = c885914;
-                                                       break;
-                                               case 15:
-                                                       coding_table = c885915;
-                                                       break;
-                                               case 16:
-                                                       coding_table = c885916;
-                                                       break;
+                                               case 2: coding_table = c88592; break;
+                                               case 3: coding_table = c88593; break;
+                                               case 4: coding_table = c88594; break;
+                                               case 5: coding_table = c88595; break;
+                                               case 6: coding_table = c88596; break;
+                                               case 7: coding_table = c88597; break;
+                                               case 8: coding_table = c88598; break;
+                                               case 9: coding_table = c88599; break;
+                                               case 10: coding_table = c885910; break;
+                                               case 11: coding_table = c885911; break;
+//                                             case 12: coding_table = c885912; break; // reserved.. for indian use
+                                               case 13: coding_table = c885913; break;
+                                               case 14: coding_table = c885914; break;
+                                               case 15: coding_table = c885915; break;
+                                               case 16: coding_table = c885916; break;
                                                default:
                                                default:
-                                                       eFatal("unknown coding table %d", table);
+                                                       eFatal("[convertUTF8DVB] unknown coding table %d", table);
                                                        break;
                                        }
                                }
                                                        break;
                                        }
                                }
-                               for(unsigned int j=0;j<96;j++)
+                               for (unsigned int j = 0; j < 96; j++)
                                {
                                {
-                                       if(coding_table[j]==c)
+                                       if (coding_table[j] == c)
                                        {
                                        {
-                                               c=0xA0+j;
+                                               c = 0xA0 + j;
                                                break;
                                        }
                                }
                        }
                }
                                                break;
                                        }
                                }
                        }
                }
-               buf[t++]=(unsigned char)c;
+               buf[t++] = (unsigned char)c;
        }
        }
-       return std::string((char*)buf,t);
+       return std::string((char*)buf, t);
 }
 
 std::string convertLatin1UTF8(const std::string &string)
 {
 }
 
 std::string convertLatin1UTF8(const std::string &string)
 {
-       unsigned int t=0, i=0, len=string.size();
+       unsigned int i = 0, len = string.size();
 
 
-       unsigned char res[2048];
+       std::string res = "";
 
        while (i < len)
        {
 
        while (i < len)
        {
-               unsigned long code=(unsigned char)string[i++];
-                               // Unicode->UTF8 encoding
-               if (code < 0x80) // identity latin <-> utf8 mapping
-                       res[t++]=char(code);
-               else if (code < 0x800) // two byte mapping
-               {
-                       res[t++]=(code>>6)|0xC0;
-                       res[t++]=(code&0x3F)|0x80;
-               } else if (code < 0x10000) // three bytes mapping
-               {
-                       res[t++]=(code>>12)|0xE0;
-                       res[t++]=((code>>6)&0x3F)|0x80;
-                       res[t++]=(code&0x3F)|0x80;
-               } else
-               {
-                       res[t++]=(code>>18)|0xF0;
-                       res[t++]=((code>>12)&0x3F)|0x80;
-                       res[t++]=((code>>6)&0x3F)|0x80;
-                       res[t++]=(code&0x3F)|0x80;
-               }
-               if (t+4 > 2047)
-               {
-                       eDebug("convertLatin1UTF8 buffer to small.. break now");
-                       break;
-               }
+               unsigned long code = (unsigned char)string[i++];
+               res += UnicodeToUTF8(code);
        }
        }
-       return std::string((char*)res, t);
+       return res;
 }
 
 int isUTF8(const std::string &string)
 {
 }
 
 int isUTF8(const std::string &string)
 {
-       unsigned int len=string.size();
-
-       for (unsigned int i=0; i < len; ++i)
+       unsigned int len = string.size();
+
+       // Unicode chars: #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
+       // (i.e. any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
+       // Avoid "compatibility characters", as defined in section 2.3 of The Unicode Standard, Version 5.0.0.
+       // Following characters are also discouraged. They are either control characters or permanently
+       // undefined Unicode characters:
+       //[#x7F-#x84], [#x86-#x9F], [#xFDD0-#xFDEF],
+       //[#x1FFFE-#x1FFFF], [#x2FFFE-#x2FFFF], [#x3FFFE-#x3FFFF],
+       //[#x4FFFE-#x4FFFF], [#x5FFFE-#x5FFFF], [#x6FFFE-#x6FFFF],
+       //[#x7FFFE-#x7FFFF], [#x8FFFE-#x8FFFF], [#x9FFFE-#x9FFFF],
+       //[#xAFFFE-#xAFFFF], [#xBFFFE-#xBFFFF], [#xCFFFE-#xCFFFF],
+       //[#xDFFFE-#xDFFFF], [#xEFFFE-#xEFFFF], [#xFFFFE-#xFFFFF],
+       //[#x10FFFE-#x10FFFF].
+
+       for (unsigned int i = 0; i < len; ++i)
        {
        {
-               if (!(string[i]&0x80)) // normal ASCII
+               if (!(string[i] & 0x80)) // normal ASCII
                        continue;
                        continue;
-               if ((string[i] & 0xE0) == 0xC0) // one char following.
-               {
-                               // first, length check:
-                       if (i+1 >= len)
-                               return 0; // certainly NOT utf-8
-                       i++;
-                       if ((string[i]&0xC0) != 0x80)
-                               return 0; // no, not UTF-8.
-               } else if ((string[i] & 0xF0) == 0xE0)
-               {
-                       if ((i+1) >= len)
-                               return 0;
-                       i++;
-                       if ((string[i]&0xC0) != 0x80)
-                               return 0;
-                       i++;
-                       if ((string[i]&0xC0) != 0x80)
+               int l = 0;
+               if ((string[i] & 0xE0) == 0xC0) // 2-byte
+                       l = 1;
+               else if ((string[i] & 0xF0) == 0xE0)  // 3-byte
+                       l = 2;
+               else if ((string[i] & 0xF8) == 0xF0) // 4-byte
+                       l = 3;
+               if (l == 0 || i + l >= len) // no UTF leader or not enough bytes
+                       return 0;
+
+               while (l-- > 0) {
+                       if ((string[++i] & 0xC0) != 0x80)
                                return 0;
                }
        }
        return 1; // can be UTF8 (or pure ASCII, at least no non-UTF-8 8bit characters)
 }
 
                                return 0;
                }
        }
        return 1; // can be UTF8 (or pure ASCII, at least no non-UTF-8 8bit characters)
 }
 
+unsigned int truncateUTF8(std::string &s, unsigned int newsize)
+{
+        unsigned int len = s.size();
+
+        // Assume s is a real UTF8 string!!!
+        while (len > newsize) {
+                while (len-- > 0  && (s[len] & 0xC0) == 0x80)
+                        ; // remove UTF data bytes,  e.g. range 0x80 - 0xBF
+                if (len > 0)   // remove the UTF startbyte, or normal ascii character
+                         --len;
+        }
+        s.resize(len);
+        return len;
+}
+
 std::string removeDVBChars(const std::string &s)
 {
        std::string res;
 
        int len = s.length();
 
 std::string removeDVBChars(const std::string &s)
 {
        std::string res;
 
        int len = s.length();
 
-       for(int i = 0; i < len; i++)
+       for (int i = 0; i < len; i++)
        {
                unsigned char c1 = s[i];
                unsigned int c;
 
                        /* UTF8? decode (but only simple) */
        {
                unsigned char c1 = s[i];
                unsigned int c;
 
                        /* UTF8? decode (but only simple) */
-               if((c1 > 0x80) && (i < len-1))
+               if ((c1 > 0x80) && (i < len-1))
                {
                        unsigned char c2 = s[i + 1];
                        c = ((c1&0x3F)<<6) + (c2&0x3F);
                {
                        unsigned char c2 = s[i + 1];
                        c = ((c1&0x3F)<<6) + (c2&0x3F);
@@ -659,10 +684,9 @@ std::string removeDVBChars(const std::string &s)
                                continue;
                        }
                }
                                continue;
                        }
                }
-               
                res += s[i];
        }
                res += s[i];
        }
-       
+
        return res;
 }
 
        return res;
 }
 
@@ -671,11 +695,50 @@ void makeUpper(std::string &s)
        std::transform(s.begin(), s.end(), s.begin(), (int(*)(int)) toupper);
 }
 
        std::transform(s.begin(), s.end(), s.begin(), (int(*)(int)) toupper);
 }
 
-std::string replace_all(const std::string &in, const std::string &entity, const std::string &symbol)
+std::string replace_all(const std::string &in, const std::string &entity, const std::string &symbol, int table)
 {
        std::string out = in;
        std::string::size_type loc = 0;
 {
        std::string out = in;
        std::string::size_type loc = 0;
-       while (( loc = out.find(entity, loc)) != std::string::npos )
-       out.replace(loc, entity.length(), symbol);
+       if( table == -1 )
+               table = defaultEncodingTable;
+       switch(table){
+       case UTF8_ENCODING:
+               while (loc < out.length()) {
+                       if ( (entity.length() + loc) <= out.length() && !out.compare(loc, entity.length(), entity)) {
+                               out.replace(loc, entity.length(), symbol);
+                               loc += symbol.length();
+                               continue;
+                       }
+                       if (out.at(loc) < 0x80)
+                               ++loc;
+                       else if ((out.at(loc) & 0xE0) == 0xC0)
+                               loc += 2;
+                       else if ((out.at(loc) & 0xF0) == 0xE0)
+                               loc += 3;
+                       else if ((out.at(loc) & 0xF8) == 0xF0)
+                               loc += 4;
+               }
+               break;
+
+       case UTF16BE_ENCODING:
+       case UTF16LE_ENCODING:
+               while (loc<out.length()) {
+                       if ((entity.length() + loc) <= out.length() && !out.compare(loc, entity.length(), entity)) {
+                               out.replace(loc, entity.length(), symbol);
+                               loc += symbol.length();
+                               continue;
+                       }
+                       loc += 2;
+               }
+               break;
+
+       default:
+               while ((loc = out.find(entity, loc)) != std::string::npos)
+               {
+                       out.replace(loc, entity.length(), symbol);
+                       loc += symbol.length();
+               }
+               break;
+       }
        return out;
 }
        return out;
 }
index 727d591..589e0a5 100644 (file)
@@ -12,15 +12,16 @@ int strnicmp(const char*, const char*, int);
 
 std::string getNum(int num, int base=10);
 
 
 std::string getNum(int num, int base=10);
 
-std::string convertDVBUTF8(const unsigned char *data, int len, int table=1, int tsidonid=1); // with default ISO8859-1 / Latin1
+std::string convertDVBUTF8(const unsigned char *data, int len, int table=1, int tsidonid=1);
 std::string convertLatin1UTF8(const std::string &string);
 int isUTF8(const std::string &string);
 std::string convertLatin1UTF8(const std::string &string);
 int isUTF8(const std::string &string);
+unsigned int truncateUTF8(std::string &s, unsigned int newsize);
 
 std::string removeDVBChars(const std::string &s);
 void makeUpper(std::string &s);
 
 std::string removeDVBChars(const std::string &s);
 void makeUpper(std::string &s);
-std::string replace_all(const std::string &in, const std::string &entity, const std::string &symbol);
+std::string replace_all(const std::string &in, const std::string &entity, const std::string &symbol, int table=-1);
 
 
-inline std::string convertDVBUTF8(const std::string &string, int table=1, int tsidonid=1) // with default ISO8859-1 / Latin1
+inline std::string convertDVBUTF8(const std::string &string, int table=1, int tsidonid=1)
 {
        return convertDVBUTF8((const unsigned char*)string.c_str(), string.length(), table, tsidonid);
 }
 {
        return convertDVBUTF8((const unsigned char*)string.c_str(), string.length(), table, tsidonid);
 }
diff --git a/lib/base/freesatv2.cpp b/lib/base/freesatv2.cpp
new file mode 100644 (file)
index 0000000..2e54138
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+FreeSat Huffman decoder for VDR
+Copyright (C) 2008  DOM http://www.rst38.org.uk/vdr/
+Port to C++ / Enigma 2
+Copyright (C) 2008  Martin Croome
+
+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 "freesatv2.h"
+#ifdef FREESATV2_DEBUG
+#      include "eerror.h"
+#endif
+#include <asm/types.h>
+
+#define START   '\0'
+#define STOP    '\0'
+#define ESCAPE  '\1'
+
+#ifndef DATADIR
+#      define DATADIR "/usr/share"
+#endif
+
+#ifndef FREESAT_DATA_DIRECTORY
+#define FREESAT_DATA_DIRECTORY       DATADIR
+#endif
+#define TABLE1_FILENAME FREESAT_DATA_DIRECTORY "/enigma2/freesat.t1"
+#define TABLE2_FILENAME FREESAT_DATA_DIRECTORY "/enigma2/freesat.t2"
+
+static void loadFile(huffTableEntry **table, const char *filename);
+
+
+struct huffTableEntry
+{
+       uint32_t value;
+       uint16_t bits;
+       char next;
+       huffTableEntry * nextEntry;
+
+       huffTableEntry(unsigned int value, short bits, char next) : value(value), bits(bits), next(next), nextEntry(NULL)
+       { }
+};
+
+freesatHuffmanDecoder::freesatHuffmanDecoder()
+{
+       memset(m_tables, 0, sizeof(m_tables));
+       loadFile(&m_tables[0][0], TABLE1_FILENAME);
+       loadFile(&m_tables[1][0], TABLE2_FILENAME);
+}
+
+freesatHuffmanDecoder::~freesatHuffmanDecoder()
+{
+       int     i, j;
+       huffTableEntry *currentEntry, *nextEntry;
+       for ( j = 0 ; j < 2; j++ )
+       {
+               for ( i = 0 ; i < 256; i++ )
+               {
+                       currentEntry = m_tables[j][i];
+                       while ( currentEntry != NULL )
+                       {
+                               nextEntry = currentEntry->nextEntry;
+                               delete currentEntry;
+                               currentEntry = nextEntry;
+                       }
+                       m_tables[j][i] = NULL;
+               }
+       }
+}
+
+
+/** \brief Convert a textual character description into a value
+*
+*  \param str - Encoded (in someway) string
+*
+*  \return Raw character
+*/
+static unsigned char resolveChar(const char *str)
+{
+       const char *p = str;
+       unsigned c0 = *p++, c1 = *p++;
+       if (c1)
+               switch(c0|c1<<8)
+               {
+                       case '0'|'x'<<8:
+                               if ( sscanf(p,"%02x", &c1) == 1 )
+                                       c0 = c1;
+                               break;
+                       case 'E'|'S'<<8:
+                               if ( !strcmp(p,"CAPE") )
+                                       c0 = ESCAPE;
+                               break;
+                       case 'S'|'T'<<8:
+                               if ( !strcmp(p,"OP") )
+                                       c0 = STOP;
+                               else if ( !strcmp(p,"ART") )
+                                       c0 = START;
+                               break;
+               }
+       return c0;
+}
+
+
+/** \brief Decode a binary string into a value
+*
+*  \param binary - Binary string to decode
+*
+*  \return Decoded value
+*/
+static unsigned long decodeBinary(const char *binary)
+{
+       unsigned long mask = 0x80000000;
+       unsigned long val = 0;
+
+       while (*binary)
+       {
+               if ( *binary == '1' )
+               {
+                       val |= mask;
+               }
+               mask >>= 1;
+               ++binary;
+       }
+       return val;
+}
+
+static void loadFile(huffTableEntry **table, const char *filename)
+{
+       char buf[1024];
+       char *from;
+       char *to;
+       char *binary;
+       char *colon;
+
+       FILE *fp = fopen(filename, "r");
+       if ( fp )
+       {
+               while ( fgets(buf,sizeof(buf),fp) != NULL )
+               {
+                       // Tokenize string "in place"
+                       from = buf;
+                       colon = strchr(buf, ':');
+                       if (colon == NULL)
+                               continue;
+                       binary = colon + 1;
+                       *colon = 0;
+                       colon = strchr(binary, ':');
+                       if (colon == NULL)
+                               continue;
+                       *colon = 0;
+                       to = colon + 1;
+                       colon = strchr(to, ':');
+                       if (colon != NULL)
+                               *colon = 0;
+                       {
+                               int bin_len = strlen(binary);
+                               int from_char = resolveChar(from);
+                               char to_char = resolveChar(to);
+                               unsigned long bin = decodeBinary(binary);
+
+                               // Add entry to end of bucket
+                               huffTableEntry **pCurrent = &table[from_char];
+                               while ( *pCurrent != NULL )
+                               {
+                                       pCurrent = &((*pCurrent)->nextEntry);
+                               }
+                               *pCurrent = new huffTableEntry(bin, bin_len, to_char);
+                       }
+               }
+               fclose(fp);
+       }
+#ifdef FREESATV2_DEBUG
+       else
+       {
+               eDebug("[FREESAT] Cannot load '%s'",filename);
+       }
+#endif
+}
+
+
+/** \brief Decode an EPG string as necessary
+*
+*  \param src - Possibly encoded string
+*  \param size - Size of the buffer
+*
+*  \retval NULL - Can't decode
+*  \return A decoded string
+*/
+std::string freesatHuffmanDecoder::decode(const unsigned char *src, size_t size)
+{
+       std::string uncompressed;
+
+       if (src[0] != 0x1f)
+               return uncompressed;
+
+       const unsigned int table_index = src[1] - 1;
+
+       if (table_index <= 1)
+       {
+               huffTableEntry **table = &m_tables[table_index][0];
+               unsigned int value = 0;
+               unsigned int byte = 2;
+               unsigned int bit = 0;
+               int lastch = START;
+
+               while (byte < 6 && byte < size)
+               {
+                       value |= src[byte] << ((5-byte) * 8);
+                       byte++;
+               }
+
+               do
+               {
+                       int found = 0;
+                       unsigned bitShift = 0;
+                       if (lastch == ESCAPE)
+                       {
+                               char nextCh = (value >> 24) & 0xff;
+                               found = 1;
+                               // Encoded in the next 8 bits.
+                               // Terminated by the first ASCII character.
+                               bitShift = 8;
+                               if ((nextCh & 0x80) == 0)
+                                       lastch = nextCh;
+                               uncompressed.append(&nextCh, 1);
+                       }
+                       else
+                       {
+                               huffTableEntry * currentEntry = table[lastch];
+                               while ( currentEntry != NULL )
+                               {
+                                       unsigned mask = 0, maskbit = 0x80000000;
+                                       short kk;
+                                       for ( kk = 0; kk < currentEntry->bits; kk++)
+                                       {
+                                               mask |= maskbit;
+                                               maskbit >>= 1;
+                                       }
+                                       if ((value & mask) == currentEntry->value)
+                                       {
+                                               char nextCh = currentEntry->next;
+                                               bitShift = currentEntry->bits;
+                                               if (nextCh != STOP && nextCh != ESCAPE)
+                                               {
+                                                       uncompressed.append(&nextCh, 1);
+                                               }
+                                               found = 1;
+                                               lastch = nextCh;
+                                               break;
+                                       }
+                                       currentEntry = currentEntry->nextEntry;
+                               }
+                       }
+                       if (found)
+                       {
+                               // Shift up by the number of bits.
+                               unsigned b;
+                               for ( b = 0; b < bitShift; b++)
+                               {
+                                       value = (value << 1) & 0xfffffffe;
+                                       if (byte < size)
+                                               value |= (src[byte] >> (7-bit)) & 1;
+                                       if (bit == 7)
+                                       {
+                                               bit = 0;
+                                               byte++;
+                                       }
+                                       else bit++;
+                               }
+                       }
+                       else
+                       {
+#ifdef FREESATV2_DEBUG
+                               eDebug("[FREESAT] Missing table %d entry: <%s>", table_index + 1, uncompressed.c_str());
+#endif
+                               return uncompressed;
+                       }
+               } while (lastch != STOP && value != 0);
+       }
+       return uncompressed;
+}
diff --git a/lib/base/freesatv2.h b/lib/base/freesatv2.h
new file mode 100644 (file)
index 0000000..6c17a12
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef FREESAT_H
+#define FREESAT_H
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string>
+
+struct huffTableEntry;
+
+class freesatHuffmanDecoder
+{
+private:
+       huffTableEntry *m_tables[2][256];
+public:
+       freesatHuffmanDecoder();
+       ~freesatHuffmanDecoder();
+       std::string decode(const unsigned char *src, size_t size);
+};
+#endif
+
old mode 100755 (executable)
new mode 100644 (file)
index b2d21f4..dadca4d
@@ -1526,6 +1526,21 @@ eServiceReference eDVBDB::searchReference(int tsid, int onid, int sid)
        return eServiceReference();
 }
 
        return eServiceReference();
 }
 
+void eDVBDB::searchAllReferences(std::vector<eServiceReference> &result, int tsid, int onid, int sid)
+{
+       eServiceID Sid(sid);
+       eTransportStreamID Tsid(tsid);
+       eOriginalNetworkID Onid(onid);
+       for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator sit(m_services.begin());
+               sit != m_services.end(); ++sit)
+       {
+               if (sit->first.getTransportStreamID() == Tsid &&
+                       sit->first.getOriginalNetworkID() == Onid &&
+                       sit->first.getServiceID() == Sid)
+                       result.push_back(sit->first);
+       }
+}
+
 DEFINE_REF(eDVBDBQueryBase);
 
 eDVBDBQueryBase::eDVBDBQueryBase(eDVBDB *db, const eServiceReference &source, eDVBChannelQuery *query)
 DEFINE_REF(eDVBDBQueryBase);
 
 eDVBDBQueryBase::eDVBDBQueryBase(eDVBDB *db, const eServiceReference &source, eDVBChannelQuery *query)
index 098ee03..dd1585f 100644 (file)
@@ -61,6 +61,7 @@ public:
 //////
        void loadBouquet(const char *path);
        eServiceReference searchReference(int tsid, int onid, int sid);
 //////
        void loadBouquet(const char *path);
        eServiceReference searchReference(int tsid, int onid, int sid);
+       void searchAllReferences(std::vector<eServiceReference> &result, int tsid, int onid, int sid);
        eDVBDB();
        virtual ~eDVBDB();
 #endif
        eDVBDB();
        virtual ~eDVBDB();
 #endif
index 26b6767..2db7c8e 100644 (file)
@@ -67,13 +67,8 @@ time_t getRTC()
        return rtc_time != prev_time ? rtc_time : 0;
 }
 
        return rtc_time != prev_time ? rtc_time : 0;
 }
 
-time_t parseDVBtime(__u8 t1, __u8 t2, __u8 t3, __u8 t4, __u8 t5, __u16 *hash)
+static void parseDVBdate(tm& t, int mjd)
 {
 {
-       tm t;
-       t.tm_sec=fromBCD(t5);
-       t.tm_min=fromBCD(t4);
-       t.tm_hour=fromBCD(t3);
-       int mjd=(t1<<8)|t2;
        int k;
 
        t.tm_year = (int) ((mjd - 15078.2) / 365.25);
        int k;
 
        t.tm_year = (int) ((mjd - 15078.2) / 365.25);
@@ -86,12 +81,39 @@ time_t parseDVBtime(__u8 t1, __u8 t2, __u8 t3, __u8 t4, __u8 t5, __u16 *hash)
 
        t.tm_isdst =  0;
        t.tm_gmtoff = 0;
 
        t.tm_isdst =  0;
        t.tm_gmtoff = 0;
+}
 
 
-       if (hash) {
-               *hash = t.tm_hour * 60 + t.tm_min;
-               *hash |= t.tm_mday << 11;
-       }
+static inline void parseDVBtime_impl(tm& t, const uint8_t *data)
+{
+       parseDVBdate(t, (data[0] << 8) | data[1]);
+       t.tm_hour = fromBCD(data[2]);
+       t.tm_min = fromBCD(data[3]);
+       t.tm_sec = fromBCD(data[4]);
+}
 
 
+time_t parseDVBtime(uint16_t mjd, uint32_t stime_bcd)
+{
+       tm t;
+       parseDVBdate(t, mjd);
+       t.tm_hour = fromBCD(stime_bcd >> 16);
+       t.tm_min = fromBCD((stime_bcd >> 8)&0xFF);
+       t.tm_sec = fromBCD(stime_bcd & 0xFF);
+       return timegm(&t);
+}
+
+time_t parseDVBtime(const uint8_t *data)
+{
+       tm t;
+       parseDVBtime_impl(t, data);
+       return timegm(&t);
+}
+
+time_t parseDVBtime(const uint8_t *data, uint16_t *hash)
+{
+       tm t;
+       parseDVBtime_impl(t, data);
+       *hash = t.tm_hour * 60 + t.tm_min;
+       *hash |= t.tm_mday << 11;
        return timegm(&t);
 }
 
        return timegm(&t);
 }
 
@@ -116,7 +138,7 @@ int TDT::createTable(unsigned int nr, const __u8 *data, unsigned int max)
                int length = ((data[1] & 0x0F) << 8) | data[2];
                if ( length >= 5 )
                {
                int length = ((data[1] & 0x0F) << 8) | data[2];
                if ( length >= 5 )
                {
-                       time_t tptime = parseDVBtime(data[3], data[4], data[5], data[6], data[7]);
+                       time_t tptime = parseDVBtime(&data[3]);
                        if (tptime && tptime != -1)
                                eDVBLocalTimeHandler::getInstance()->updateTime(tptime, chan, update_count);
                        error=0;
                        if (tptime && tptime != -1)
                                eDVBLocalTimeHandler::getInstance()->updateTime(tptime, chan, update_count);
                        error=0;
@@ -264,9 +286,6 @@ void eDVBLocalTimeHandler::updateTime( time_t tp_time, eDVBChannel *chan, int up
        else if (tp_time == -1)
        {
                restart_tdt = true;
        else if (tp_time == -1)
        {
                restart_tdt = true;
-               /*if ( eSystemInfo::getInstance()->getHwType() == eSystemInfo::DM7020 ||
-               ( eSystemInfo::getInstance()->getHwType() == eSystemInfo::DM7000
-                       && eSystemInfo::getInstance()->hasStandbyWakeupTimer() ) )     TODO !!!!!!! */
                {
                        eDebug("[eDVBLocalTimerHandler] no transponder tuned... or no TDT/TOT avail .. try to use RTC :)");
                        time_t rtc_time = getRTC();
                {
                        eDebug("[eDVBLocalTimerHandler] no transponder tuned... or no TDT/TOT avail .. try to use RTC :)");
                        time_t rtc_time = getRTC();
index c49e67e..e8f4ae3 100644 (file)
@@ -25,7 +25,9 @@ inline int toBCD(int dec)
        return int(dec/10)*0x10 + dec%10;
 }
 
        return int(dec/10)*0x10 + dec%10;
 }
 
-time_t parseDVBtime(__u8 t1, __u8 t2, __u8 t3, __u8 t4, __u8 t5, __u16 *hash=0);
+time_t parseDVBtime(uint16_t mjd, uint32_t stime_bcd);
+time_t parseDVBtime(const uint8_t* data);
+time_t parseDVBtime(const uint8_t* data, uint16_t *hash);
 
 class TDT: public eGTable
 {
 
 class TDT: public eGTable
 {
index 4d32474..0d2545f 100644 (file)
@@ -1,26 +1,78 @@
 #include <lib/dvb/epgcache.h>
 #include <lib/dvb/dvb.h>
 #include <lib/dvb/epgcache.h>
 #include <lib/dvb/dvb.h>
+#include <lib/dvb/lowlevel/eit.h>
 
 
-#undef EPG_DEBUG  
+#undef EPG_DEBUG
 
 #ifdef EPG_DEBUG
 #include <lib/service/event.h>
 #endif
 
 
 #ifdef EPG_DEBUG
 #include <lib/service/event.h>
 #endif
 
+#include <deque>
+#include <string>
 #include <time.h>
 #include <unistd.h>  // for usleep
 #include <sys/vfs.h> // for statfs
 #include <time.h>
 #include <unistd.h>  // for usleep
 #include <sys/vfs.h> // for statfs
-// #include <libmd5sum.h>
 #include <lib/base/eerror.h>
 #include <lib/base/eerror.h>
+#include <lib/base/encoding.h>
 #include <lib/base/estring.h>
 #include <lib/dvb/pmt.h>
 #include <lib/dvb/db.h>
 #include <lib/python/python.h>
 #include <dvbsi++/descriptor_tag.h>
 
 #include <lib/base/estring.h>
 #include <lib/dvb/pmt.h>
 #include <lib/dvb/db.h>
 #include <lib/python/python.h>
 #include <dvbsi++/descriptor_tag.h>
 
-int eventData::CacheSize=0;
-descriptorMap eventData::descriptors;
-__u8 eventData::data[4108];
+/* Interval between "garbage collect" cycles */
+#define CLEAN_INTERVAL 60000    //  1 min
+/* Restart EPG data capture */
+#define UPDATE_INTERVAL 3600000  // 60 min
+/* Time to wait after tuning in before EPG data capturing starts */
+#define ZAP_DELAY 2000          // 2 sec
+
+struct DescriptorPair
+{
+       int reference_count;
+       uint8_t* data;
+
+       DescriptorPair() {}
+       DescriptorPair(int c, uint8_t* d): reference_count(c), data(d) {}
+};
+
+typedef std::tr1::unordered_map<uint32_t, DescriptorPair> DescriptorMap;
+
+struct eventData
+{
+       uint8_t rawEITdata[10];
+       uint8_t n_crc;
+       uint8_t type;
+       uint32_t *crc_list;
+       static DescriptorMap descriptors;
+       static uint8_t data[];
+       static unsigned int CacheSize;
+       static bool isCacheCorrupt;
+       eventData(const eit_event_struct* e = NULL, int size = 0, int type = 0, int tsidonid = 0);
+       ~eventData();
+       static void load(FILE *);
+       static void save(FILE *);
+       static void cacheCorrupt(const char* context);
+       const eit_event_struct* get() const;
+       int getEventID() const
+       {
+               return (rawEITdata[0] << 8) | rawEITdata[1];
+       }
+       time_t getStartTime() const
+       {
+               return parseDVBtime(&rawEITdata[2]);
+       }
+       int getDuration() const
+       {
+               return fromBCD(rawEITdata[7])*3600+fromBCD(rawEITdata[8])*60+fromBCD(rawEITdata[9]);
+       }
+};
+
+unsigned int eventData::CacheSize = 0;
+bool eventData::isCacheCorrupt = 0;
+DescriptorMap eventData::descriptors;
+uint8_t eventData::data[2 * 4096 + 12];
 extern const uint32_t crc32_table[256];
 
 const eServiceReference &handleGroup(const eServiceReference &ref)
 extern const uint32_t crc32_table[256];
 
 const eServiceReference &handleGroup(const eServiceReference &ref)
@@ -33,7 +85,7 @@ const eServiceReference &handleGroup(const eServiceReference &ref)
                        ePtr<iDVBChannelList> db;
                        if (!res->getChannelList(db))
                        {
                        ePtr<iDVBChannelList> db;
                        if (!res->getChannelList(db))
                        {
-                               eBouquet *bouquet=0;
+                               eBouquet *bouquet = NULL;
                                if (!db->getBouquet(ref, bouquet))
                                {
                                        std::list<eServiceReference>::iterator it(bouquet->m_services.begin());
                                if (!db->getBouquet(ref, bouquet))
                                {
                                        std::list<eServiceReference>::iterator it(bouquet->m_services.begin());
@@ -46,22 +98,30 @@ const eServiceReference &handleGroup(const eServiceReference &ref)
        return ref;
 }
 
        return ref;
 }
 
-eventData::eventData(const eit_event_struct* e, int size, int type)
-       :ByteSize(size&0xFF), type(type&0xFF)
+static uint32_t calculate_crc_hash(const uint8_t *data, int size)
+{
+       uint32_t crc = 0;
+       for (int i = 0; i < size; ++i)
+               crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ data[i]) & 0xFF];
+       return crc;
+}
+
+eventData::eventData(const eit_event_struct* e, int size, int _type, int tsidonid)
+       :n_crc(0), type(_type & 0xFF), crc_list(NULL)
 {
        if (!e)
 {
        if (!e)
-               return;
+               return; /* Used when loading from file */
 
 
-       __u32 descr[65];
-       __u32 *pdescr=descr;
+       uint32_t descr[65];
+       uint32_t *pdescr=descr;
 
 
-       __u8 *data = (__u8*)e;
+       uint8_t *data = (uint8_t*)e;
        int ptr=12;
        size -= 12;
 
        while(size > 1)
        {
        int ptr=12;
        size -= 12;
 
        while(size > 1)
        {
-               __u8 *descr = data+ptr;
+               uint8_t *descr = data + ptr;
                int descr_len = descr[1];
                descr_len += 2;
                if (size >= descr_len)
                int descr_len = descr[1];
                descr_len += 2;
                if (size >= descr_len)
@@ -69,69 +129,158 @@ eventData::eventData(const eit_event_struct* e, int size, int type)
                        switch (descr[0])
                        {
                                case EXTENDED_EVENT_DESCRIPTOR:
                        switch (descr[0])
                        {
                                case EXTENDED_EVENT_DESCRIPTOR:
-                               case SHORT_EVENT_DESCRIPTOR:
                                case LINKAGE_DESCRIPTOR:
                                case COMPONENT_DESCRIPTOR:
                                case LINKAGE_DESCRIPTOR:
                                case COMPONENT_DESCRIPTOR:
+                               case CONTENT_DESCRIPTOR:
+                               case PARENTAL_RATING_DESCRIPTOR:
+                               case PDC_DESCRIPTOR:
                                {
                                {
-                                       __u32 crc = 0;
-                                       int cnt=0;
-                                       while(cnt++ < descr_len)
-                                               crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ data[ptr++]) & 0xFF];
-       
-                                       descriptorMap::iterator it =
-                                               descriptors.find(crc);
+                                       uint32_t crc = calculate_crc_hash(descr, descr_len);
+                                       DescriptorMap::iterator it = descriptors.find(crc);
                                        if ( it == descriptors.end() )
                                        {
                                                CacheSize+=descr_len;
                                        if ( it == descriptors.end() )
                                        {
                                                CacheSize+=descr_len;
-                                               __u8 *d = new __u8[descr_len];
+                                               uint8_t *d = new uint8_t[descr_len];
                                                memcpy(d, descr, descr_len);
                                                memcpy(d, descr, descr_len);
-                                               descriptors[crc] = descriptorPair(1, d);
+                                               descriptors[crc] = DescriptorPair(1, d);
                                        }
                                        else
                                        }
                                        else
-                                               ++it->second.first;
-                                       *pdescr++=crc;
+                                               ++it->second.reference_count;
+                                       *pdescr++ = crc;
+                                       break;
+                               }
+                               case SHORT_EVENT_DESCRIPTOR:
+                               {
+                                       //parse the data out from the short event descriptor
+                                       //get the country code, which will be used for converting to UTF8
+                                       std::string cc( (const char*)&descr[2], 3);
+                                       std::transform(cc.begin(), cc.end(), cc.begin(), tolower);
+                                       int table = encodingHandler.getCountryCodeDefaultMapping(cc);
+
+                                       int eventNameLen = descr[5];
+                                       int eventTextLen = descr[6 + eventNameLen];
+
+                                       //convert our strings to UTF8
+                                       std::string eventNameUTF8 = convertDVBUTF8((const unsigned char*)&descr[6], eventNameLen, table, tsidonid);
+                                       std::string textUTF8 = convertDVBUTF8((const unsigned char*)&descr[7 + eventNameLen], eventTextLen, table, tsidonid);
+                                       unsigned int eventNameUTF8len = eventNameUTF8.length();
+                                       unsigned int textUTF8len = textUTF8.length();
+
+                                       //Rebuild the short event descriptor with UTF-8 strings
+
+                                       //Save the title first
+                                       if( eventNameUTF8len > 0 ) //only store the data if there is something to store
+                                       {
+                                               /*this will actually cause us to save some memory
+                                                previously some descriptors didnt match because there text was different and titles the same.
+                                                Now that we store them seperatly we can save some space on title data some rough calculation show anywhere from 20 - 40% savings
+                                               */
+                                               eventNameUTF8len = truncateUTF8(eventNameUTF8, 255 - 6);
+                                               int title_len = 6 + eventNameUTF8len;
+                                               uint8_t *title_data = new uint8_t[title_len + 2];
+                                               title_data[0] = SHORT_EVENT_DESCRIPTOR;
+                                               title_data[1] = title_len;
+                                               title_data[2] = descr[2];
+                                               title_data[3] = descr[3];
+                                               title_data[4] = descr[4];
+                                               title_data[5] = eventNameUTF8len + 1;
+                                               title_data[6] = 0x15; //identify event name as UTF-8
+                                               memcpy(&title_data[7], eventNameUTF8.data(), eventNameUTF8len);
+                                               title_data[7 + eventNameUTF8len] = 0;
+
+                                               //Calculate the CRC, based on our new data
+                                               title_len += 2; //add 2 the length to include the 2 bytes in the header
+                                               uint32_t title_crc = calculate_crc_hash(title_data, title_len);
+
+                                               DescriptorMap::iterator it = descriptors.find(title_crc);
+                                               if ( it == descriptors.end() )
+                                               {
+                                                       CacheSize += title_len;
+                                                       descriptors[title_crc] = DescriptorPair(1, title_data);
+                                               }
+                                               else
+                                               {
+                                                       ++it->second.reference_count;
+                                                       delete [] title_data;
+                                               }
+                                               *pdescr++ = title_crc;
+                                       }
+
+                                       //save the text
+                                       if( textUTF8len > 0 ) //only store the data if there is something to store
+                                       {
+                                               textUTF8len = truncateUTF8(textUTF8, 255 - 6);
+                                               int text_len = 6 + textUTF8len;
+                                               uint8_t *text_data = new uint8_t[text_len + 2];
+                                               text_data[0] = SHORT_EVENT_DESCRIPTOR;
+                                               text_data[1] = text_len;
+                                               text_data[2] = descr[2];
+                                               text_data[3] = descr[3];
+                                               text_data[4] = descr[4];
+                                               text_data[5] = 0;
+                                               text_data[6] = textUTF8len + 1; //identify text as UTF-8
+                                               text_data[7] = 0x15; //identify text as UTF-8
+                                               memcpy(&text_data[8], textUTF8.data(), textUTF8len);
+
+                                               text_len += 2; //add 2 the length to include the 2 bytes in the header
+                                               uint32_t text_crc = calculate_crc_hash(text_data, text_len);
+
+                                               DescriptorMap::iterator it = descriptors.find(text_crc);
+                                               if ( it == descriptors.end() )
+                                               {
+                                                       CacheSize += text_len;
+                                                       descriptors[text_crc] = DescriptorPair(1, text_data);
+                                               }
+                                               else
+                                               {
+                                                       ++it->second.reference_count;
+                                                       delete [] text_data;
+                                               }
+                                               *pdescr++ = text_crc;
+                                       }
                                        break;
                                }
                                default: // do not cache all other descriptors
                                        break;
                                }
                                default: // do not cache all other descriptors
-                                       ptr += descr_len;
                                        break;
                        }
                                        break;
                        }
+                       ptr += descr_len;
                        size -= descr_len;
                }
                else
                        break;
        }
                        size -= descr_len;
                }
                else
                        break;
        }
+       memcpy(rawEITdata, (uint8_t*)e, 10);
        ASSERT(pdescr <= &descr[65]);
        ASSERT(pdescr <= &descr[65]);
-       ByteSize = 10+((pdescr-descr)*4);
-       EITdata = new __u8[ByteSize];
-       CacheSize+=ByteSize;
-       memcpy(EITdata, (__u8*) e, 10);
-       memcpy(EITdata+10, descr, ByteSize-10);
+       n_crc = pdescr - descr;
+       if (n_crc)
+       {
+               crc_list = new uint32_t[n_crc];
+               memcpy(crc_list, descr, n_crc * sizeof(uint32_t));
+       }
+       CacheSize += sizeof(*this) + n_crc * sizeof(uint32_t);
 }
 
 const eit_event_struct* eventData::get() const
 {
 }
 
 const eit_event_struct* eventData::get() const
 {
-       int pos = 12;
-       int tmp = ByteSize-10;
-       memcpy(data, EITdata, 10);
-       int descriptors_length=0;
-       __u32 *p = (__u32*)(EITdata+10);
-       while(tmp>3)
+       unsigned int pos = 12;
+       memcpy(data, rawEITdata, 10);
+       unsigned int descriptors_length = 0;
+       for (uint8_t i = 0; i < n_crc; ++i)
        {
        {
-               descriptorMap::iterator it =
-                       descriptors.find(*p++);
-               if ( it != descriptors.end() )
+               DescriptorMap::iterator it = descriptors.find(crc_list[i]);
+               if (it != descriptors.end())
                {
                {
-                       int b = it->second.second[1]+2;
-                       memcpy(data+pos, it->second.second, b );
-                       pos += b;
-                       descriptors_length += b;
+                       unsigned int b = it->second.data[1] + 2;
+                       if (pos + b < sizeof(data))
+                       {
+                               memcpy(data + pos, it->second.data, b);
+                               pos += b;
+                               descriptors_length += b;
+                       }
                }
                else
                }
                else
-                       eFatal("LINE %d descriptor not found in descriptor cache %08x!!!!!!", __LINE__, *(p-1));
-               tmp-=4;
+                       cacheCorrupt("eventData::get");
        }
        }
-       ASSERT(pos <= 4108);
        data[10] = (descriptors_length >> 8) & 0x0F;
        data[11] = descriptors_length & 0xFF;
        return (eit_event_struct*)data;
        data[10] = (descriptors_length >> 8) & 0x0F;
        data[11] = descriptors_length & 0xFF;
        return (eit_event_struct*)data;
@@ -139,83 +288,95 @@ const eit_event_struct* eventData::get() const
 
 eventData::~eventData()
 {
 
 eventData::~eventData()
 {
-       if ( ByteSize )
+       for ( uint8_t i = 0; i < n_crc; ++i )
        {
        {
-               CacheSize -= ByteSize;
-               __u32 *d = (__u32*)(EITdata+10);
-               ByteSize -= 10;
-               while(ByteSize>3)
+               DescriptorMap::iterator it = descriptors.find(crc_list[i]);
+               if ( it != descriptors.end() )
                {
                {
-                       descriptorMap::iterator it =
-                               descriptors.find(*d++);
-                       if ( it != descriptors.end() )
+                       DescriptorPair &p = it->second;
+                       if (!--p.reference_count) // no more used descriptor
                        {
                        {
-                               descriptorPair &p = it->second;
-                               if (!--p.first) // no more used descriptor
-                               {
-                                       CacheSize -= it->second.second[1];
-                                       delete [] it->second.second;    // free descriptor memory
-                                       descriptors.erase(it);  // remove entry from descriptor map
-                               }
+                               CacheSize -= it->second.data[1];
+                               delete [] it->second.data;      // free descriptor memory
+                               descriptors.erase(it);  // remove entry from descriptor map
                        }
                        }
-                       else
-                               eFatal("LINE %d descriptor not found in descriptor cache %08x!!!!!!", __LINE__, *(d-1));
-                       ByteSize -= 4;
                }
                }
-               delete [] EITdata;
+               else
+               {
+                       cacheCorrupt("eventData::~eventData");
+               }
        }
        }
+       delete [] crc_list;
+       CacheSize -= sizeof(*this) + n_crc * sizeof(uint32_t);
 }
 
 void eventData::load(FILE *f)
 {
 }
 
 void eventData::load(FILE *f)
 {
-       int size=0;
+       int size = 0;
        int id=0;
        int id=0;
-       __u8 header[2];
-       descriptorPair p;
+       DescriptorPair p;
+       uint8_t header[2];
        fread(&size, sizeof(int), 1, f);
        fread(&size, sizeof(int), 1, f);
+       descriptors.rehash(size);
        while(size)
        {
        while(size)
        {
-               fread(&id, sizeof(__u32), 1, f);
-               fread(&p.first, sizeof(int), 1, f);
+               fread(&id, sizeof(uint32_t), 1, f);
+               fread(&p.reference_count, sizeof(int), 1, f);
                fread(header, 2, 1, f);
                int bytes = header[1]+2;
                fread(header, 2, 1, f);
                int bytes = header[1]+2;
-               p.second = new __u8[bytes];
-               p.second[0] = header[0];
-               p.second[1] = header[1];
-               fread(p.second+2, bytes-2, 1, f);
-               descriptors[id]=p;
+               p.data = new uint8_t[bytes];
+               p.data[0] = header[0];
+               p.data[1] = header[1];
+               fread(p.data+2, bytes-2, 1, f);
+               descriptors[id] = p;
                --size;
                --size;
-               CacheSize+=bytes;
        }
 }
 
 void eventData::save(FILE *f)
 {
        }
 }
 
 void eventData::save(FILE *f)
 {
+       if (isCacheCorrupt)
+               return;
        int size=descriptors.size();
        int size=descriptors.size();
-       descriptorMap::iterator it(descriptors.begin());
+       DescriptorMap::iterator it(descriptors.begin());
        fwrite(&size, sizeof(int), 1, f);
        while(size)
        {
        fwrite(&size, sizeof(int), 1, f);
        while(size)
        {
-               fwrite(&it->first, sizeof(__u32), 1, f);
-               fwrite(&it->second.first, sizeof(int), 1, f);
-               fwrite(it->second.second, it->second.second[1]+2, 1, f);
+               fwrite(&it->first, sizeof(uint32_t), 1, f);
+               fwrite(&it->second.reference_count, sizeof(int), 1, f);
+               fwrite(it->second.data, it->second.data[1]+2, 1, f);
                ++it;
                --size;
        }
 }
 
                ++it;
                --size;
        }
 }
 
+void eventData::cacheCorrupt(const char* context)
+{
+
+       eDebug("[eventData] EPG Cache is corrupt (%s), you should restart Enigma!", context);
+       if (!isCacheCorrupt)
+       {
+               isCacheCorrupt = true;
+               if (!eEPGCache::instance->m_filename.empty())
+                       unlink(eEPGCache::instance->m_filename.c_str()); // Remove corrupt EPG data
+       }
+}
+
 eEPGCache* eEPGCache::instance;
 eEPGCache* eEPGCache::instance;
-pthread_mutex_t eEPGCache::cache_lock=
+static pthread_mutex_t cache_lock =
        PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
        PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
-pthread_mutex_t eEPGCache::channel_map_lock=
+static pthread_mutex_t channel_map_lock =
        PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
 
 DEFINE_REF(eEPGCache)
 
 eEPGCache::eEPGCache()
        PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
 
 DEFINE_REF(eEPGCache)
 
 eEPGCache::eEPGCache()
-       :messages(this,1), cleanTimer(eTimer::create(this)), m_running(0)//, paused(0)
+       :messages(this,1), cleanTimer(eTimer::create(this)), m_running(false)
 {
 {
-       eDebug("[EPGC] Initialized EPGCache (wait for setCacheFile call now)");
+       eDebug("[eEPGCache] Initialized EPGCache (wait for setCacheFile call now)");
+
+       enabledSources = 0;
+       historySeconds = 0;
 
        CONNECT(messages.recv_msg, eEPGCache::gotMessage);
        CONNECT(eDVBLocalTimeHandler::getInstance()->m_timeUpdated, eEPGCache::timeUpdated);
 
        CONNECT(messages.recv_msg, eEPGCache::gotMessage);
        CONNECT(eDVBLocalTimeHandler::getInstance()->m_timeUpdated, eEPGCache::timeUpdated);
@@ -229,16 +390,15 @@ eEPGCache::eEPGCache()
                res_mgr->connectChannelAdded(slot(*this,&eEPGCache::DVBChannelAdded), m_chanAddedConn);
 
        instance=this;
                res_mgr->connectChannelAdded(slot(*this,&eEPGCache::DVBChannelAdded), m_chanAddedConn);
 
        instance=this;
-       memset(m_filename, 0, sizeof(m_filename));
 }
 
 void eEPGCache::setCacheFile(const char *path)
 {
 }
 
 void eEPGCache::setCacheFile(const char *path)
 {
-       bool inited = !!strlen(m_filename);
-       strncpy(m_filename, path, 1024);
+       bool inited = !m_filename.empty();
+       m_filename = path;
        if (!inited)
        {
        if (!inited)
        {
-               eDebug("[EPGC] setCacheFile read/write epg data from/to '%s'", m_filename);
+               eDebug("[eEPGCache] setCacheFile read/write epg data from/to '%s'", m_filename.c_str());
                if (eDVBLocalTimeHandler::getInstance()->ready())
                        timeUpdated();
        }
                if (eDVBLocalTimeHandler::getInstance()->ready())
                        timeUpdated();
        }
@@ -246,15 +406,15 @@ void eEPGCache::setCacheFile(const char *path)
 
 void eEPGCache::timeUpdated()
 {
 
 void eEPGCache::timeUpdated()
 {
-       if (strlen(m_filename))
+       if (!m_filename.empty())
        {
        {
-               if (!sync())
+               if (!m_running)
                {
                {
-                       eDebug("[EPGC] time updated.. start EPG Mainloop");
+                       eDebug("[eEPGCache] time updated.. start EPG Mainloop");
                        run();
                        run();
+                       m_running = true;
                        singleLock s(channel_map_lock);
                        singleLock s(channel_map_lock);
-                       channelMapIterator it = m_knownChannels.begin();
-                       for (; it != m_knownChannels.end(); ++it)
+                       for (ChannelMap::const_iterator it = m_knownChannels.begin(); it != m_knownChannels.end(); ++it)
                        {
                                if (it->second->state == -1) {
                                        it->second->state=0;
                        {
                                if (it->second->state == -1) {
                                        it->second->state=0;
@@ -265,7 +425,7 @@ void eEPGCache::timeUpdated()
                        messages.send(Message(Message::timeChanged));
        }
        else
                        messages.send(Message(Message::timeChanged));
        }
        else
-               eDebug("[EPGC] time updated.. but cache file not set yet.. dont start epg!!");
+               eDebug("[eEPGCache] time updated.. but cache file not set yet.. dont start epg!!");
 }
 
 void eEPGCache::DVBChannelAdded(eDVBChannel *chan)
 }
 
 void eEPGCache::DVBChannelAdded(eDVBChannel *chan)
@@ -292,8 +452,7 @@ void eEPGCache::DVBChannelAdded(eDVBChannel *chan)
 
 void eEPGCache::DVBChannelRunning(iDVBChannel *chan)
 {
 
 void eEPGCache::DVBChannelRunning(iDVBChannel *chan)
 {
-       channelMapIterator it =
-               m_knownChannels.find(chan);
+       ChannelMap::const_iterator it = m_knownChannels.find(chan);
        if ( it == m_knownChannels.end() )
                eDebug("[eEPGCache] will start non existing channel %p !!!", chan);
        else
        if ( it == m_knownChannels.end() )
                eDebug("[eEPGCache] will start non existing channel %p !!!", chan);
        else
@@ -333,6 +492,36 @@ void eEPGCache::DVBChannelRunning(iDVBChannel *chan)
                                        return;
                                }
 
                                        return;
                                }
 
+#ifdef ENABLE_VIRGIN
+                               res = demux->createSectionReader( this, data.m_VirginNowNextReader );
+                               if ( res )
+                               {
+                                       eDebug("[eEPGCache] couldnt initialize virgin nownext reader!!");
+                                       return;
+                               }
+
+                               res = demux->createSectionReader( this, data.m_VirginScheduleReader );
+                               if ( res )
+                               {
+                                       eDebug("[eEPGCache] couldnt initialize virgin schedule reader!!");
+                                       return;
+                               }
+#endif
+#ifdef ENABLE_NETMED
+                               res = demux->createSectionReader( this, data.m_NetmedScheduleReader );
+                               if ( res )
+                               {
+                                       eDebug("[eEPGCache] couldnt initialize netmed schedule reader!!");
+                                       return;
+                               }
+
+                               res = demux->createSectionReader( this, data.m_NetmedScheduleOtherReader );
+                               if ( res )
+                               {
+                                       eDebug("[eEPGCache] couldnt initialize netmed schedule other reader!!");
+                                       return;
+                               }
+#endif
                                res = demux->createSectionReader( this, data.m_ViasatReader );
                                if ( res )
                                {
                                res = demux->createSectionReader( this, data.m_ViasatReader );
                                if ( res )
                                {
@@ -361,8 +550,23 @@ void eEPGCache::DVBChannelRunning(iDVBChannel *chan)
                                        return;
                                }
 #endif
                                        return;
                                }
 #endif
-                               if (m_running) {
-                                       data.state=0;
+#if ENABLE_FREESAT
+                               res = demux->createSectionReader( this, data.m_FreeSatScheduleOtherReader );
+                               if ( res )
+                               {
+                                       eDebug("[eEPGCache] couldnt initialize FreeSat reader!!");
+                                       return;
+                               }
+                               res = demux->createSectionReader( this, data.m_FreeSatScheduleOtherReader2 );
+                               if ( res )
+                               {
+                                       eDebug("[eEPGCache] couldnt initialize FreeSat reader 2!!");
+                                       return;
+                               }
+#endif
+                               if (m_running)
+                               {
+                                       data.state = 0;
                                        messages.send(Message(Message::startChannel, chan));
                                        // -> gotMessage -> changedService
                                }
                                        messages.send(Message(Message::startChannel, chan));
                                        // -> gotMessage -> changedService
                                }
@@ -375,8 +579,7 @@ void eEPGCache::DVBChannelRunning(iDVBChannel *chan)
 
 void eEPGCache::DVBChannelStateChanged(iDVBChannel *chan)
 {
 
 void eEPGCache::DVBChannelStateChanged(iDVBChannel *chan)
 {
-       channelMapIterator it =
-               m_knownChannels.find(chan);
+       ChannelMap::iterator it = m_knownChannels.find(chan);
        if ( it != m_knownChannels.end() )
        {
                int state=0;
        if ( it != m_knownChannels.end() )
        {
                int state=0;
@@ -396,14 +599,16 @@ void eEPGCache::DVBChannelStateChanged(iDVBChannel *chan)
                                        eDebug("[eEPGCache] remove channel %p", chan);
                                        if (it->second->state >= 0)
                                                messages.send(Message(Message::leaveChannel, chan));
                                        eDebug("[eEPGCache] remove channel %p", chan);
                                        if (it->second->state >= 0)
                                                messages.send(Message(Message::leaveChannel, chan));
-                                       pthread_mutex_lock(&it->second->channel_active);
-                                       singleLock s(channel_map_lock);
-                                       m_knownChannels.erase(it);
-                                       pthread_mutex_unlock(&it->second->channel_active);
-                                       delete it->second;
-                                       it->second=0;
+                                       channel_data* cd = it->second;
+                                       pthread_mutex_lock(&cd->channel_active);
+                                       {
+                                               singleLock s(channel_map_lock);
+                                               m_knownChannels.erase(it);
+                                       }
+                                       pthread_mutex_unlock(&cd->channel_active);
+                                       delete cd;
                                        // -> gotMessage -> abortEPG
                                        // -> gotMessage -> abortEPG
-                                       break;
+                                       return;
                                }
                                default: // ignore all other events
                                        return;
                                }
                                default: // ignore all other events
                                        return;
@@ -414,46 +619,46 @@ void eEPGCache::DVBChannelStateChanged(iDVBChannel *chan)
        }
 }
 
        }
 }
 
-bool eEPGCache::FixOverlapping(std::pair<eventMap,timeMap> &servicemap, time_t TM, int duration, const timeMap::iterator &tm_it, const uniqueEPGKey &service)
+bool eEPGCache::FixOverlapping(EventCacheItem &servicemap, time_t TM, int duration, const timeMap::iterator &tm_it, const uniqueEPGKey &service)
 {
        bool ret = false;
        timeMap::iterator tmp = tm_it;
 {
        bool ret = false;
        timeMap::iterator tmp = tm_it;
-       while ((tmp->first+tmp->second->getDuration()-300) > TM)
+       while ((tmp->first + tmp->second->getDuration() - 300) > TM)
        {
        {
-               if(tmp->first != TM 
+               if(tmp->first != TM
 #ifdef ENABLE_PRIVATE_EPG
 #ifdef ENABLE_PRIVATE_EPG
-                       && tmp->second->type != PRIVATE 
+                       && tmp->second->type != PRIVATE
 #endif
 #endif
-#ifdef ENABLE_MHW
+#ifdef ENABLE_MHW_EPG
                        && tmp->second->type != MHW
 #endif
                        )
                {
                        && tmp->second->type != MHW
 #endif
                        )
                {
-                       __u16 event_id = tmp->second->getEventID();
-                       servicemap.first.erase(event_id);
+                       uint16_t event_id = tmp->second->getEventID();
+                       servicemap.byEvent.erase(event_id);
 #ifdef EPG_DEBUG
                        Event evt((uint8_t*)tmp->second->get());
                        eServiceEvent event;
                        event.parseFrom(&evt, service.sid<<16|service.onid);
 #ifdef EPG_DEBUG
                        Event evt((uint8_t*)tmp->second->get());
                        eServiceEvent event;
                        event.parseFrom(&evt, service.sid<<16|service.onid);
-                       eDebug("(1)erase no more used event %04x %d\n%s %s\n%s",
+                       eDebug("[eEPGCache] (1)erase no more used event %04x %d\n%s %s\n%s",
                                service.sid, event_id,
                                event.getBeginTimeString().c_str(),
                                event.getEventName().c_str(),
                                event.getExtendedDescription().c_str());
 #endif
                        delete tmp->second;
                                service.sid, event_id,
                                event.getBeginTimeString().c_str(),
                                event.getEventName().c_str(),
                                event.getExtendedDescription().c_str());
 #endif
                        delete tmp->second;
-                       if (tmp == servicemap.second.begin())
+                       if (tmp == servicemap.byTime.begin())
                        {
                        {
-                               servicemap.second.erase(tmp);
+                               servicemap.byTime.erase(tmp);
                                break;
                        }
                        else
                                break;
                        }
                        else
-                               servicemap.second.erase(tmp--);
+                               servicemap.byTime.erase(tmp--);
                        ret = true;
                }
                else
                {
                        ret = true;
                }
                else
                {
-                       if (tmp == servicemap.second.begin())
+                       if (tmp == servicemap.byTime.begin())
                                break;
                        --tmp;
                }
                                break;
                        --tmp;
                }
@@ -464,97 +669,107 @@ bool eEPGCache::FixOverlapping(std::pair<eventMap,timeMap> &servicemap, time_t T
        {
                if (tmp->first != TM && tmp->second->type != PRIVATE)
                {
        {
                if (tmp->first != TM && tmp->second->type != PRIVATE)
                {
-                       __u16 event_id = tmp->second->getEventID();
-                       servicemap.first.erase(event_id);
-#ifdef EPG_DEBUG  
+                       uint16_t event_id = tmp->second->getEventID();
+                       servicemap.byEvent.erase(event_id);
+#ifdef EPG_DEBUG
                        Event evt((uint8_t*)tmp->second->get());
                        eServiceEvent event;
                        event.parseFrom(&evt, service.sid<<16|service.onid);
                        Event evt((uint8_t*)tmp->second->get());
                        eServiceEvent event;
                        event.parseFrom(&evt, service.sid<<16|service.onid);
-                       eDebug("(2)erase no more used event %04x %d\n%s %s\n%s",
+                       eDebug("[eEPGCache] (2)erase no more used event %04x %d\n%s %s\n%s",
                                service.sid, event_id,
                                event.getBeginTimeString().c_str(),
                                event.getEventName().c_str(),
                                event.getExtendedDescription().c_str());
 #endif
                        delete tmp->second;
                                service.sid, event_id,
                                event.getBeginTimeString().c_str(),
                                event.getEventName().c_str(),
                                event.getExtendedDescription().c_str());
 #endif
                        delete tmp->second;
-                       servicemap.second.erase(tmp++);
+                       servicemap.byTime.erase(tmp++);
                        ret = true;
                }
                else
                        ++tmp;
                        ret = true;
                }
                else
                        ++tmp;
-               if (tmp == servicemap.second.end())
+               if (tmp == servicemap.byTime.end())
                        break;
        }
        return ret;
 }
 
                        break;
        }
        return ret;
 }
 
-void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel)
+void eEPGCache::sectionRead(const uint8_t *data, int source, channel_data *channel)
 {
 {
-       eit_t *eit = (eit_t*) data;
+       const eit_t *eit = (const eit_t*) data;
 
 
-       int len=HILO(eit->section_length)-1;//+3-4;
-       int ptr=EIT_SIZE;
+       int len = eit->getSectionLength()-1;//+3-4;
+       int ptr = EIT_SIZE;
        if ( ptr >= len )
                return;
 
        if ( ptr >= len )
                return;
 
+#if 0
+               /*
+                * disable for now, as this hack breaks EIT parsing for
+                * services with a low segment_last_table_id
+                *
+                * Multichoice should be the exception, not the rule...
+                */
+
        // This fixed the EPG on the Multichoice irdeto systems
        // the EIT packet is non-compliant.. their EIT packet stinks
        if ( data[ptr-1] < 0x40 )
                --ptr;
        // This fixed the EPG on the Multichoice irdeto systems
        // the EIT packet is non-compliant.. their EIT packet stinks
        if ( data[ptr-1] < 0x40 )
                --ptr;
+#endif
+
+       int onid = eit->getOriginalNetworkId();
+       int tsid = eit->getTransportStreamId();
 
        // Cablecom HACK .. tsid / onid in eit data are incorrect.. so we use
        // it from running channel (just for current transport stream eit data)
 
        // Cablecom HACK .. tsid / onid in eit data are incorrect.. so we use
        // it from running channel (just for current transport stream eit data)
-       bool use_transponder_chid = source == SCHEDULE || (source == NOWNEXT && data[0] == 0x4E);
-       eDVBChannelID chid = channel->channel->getChannelID();
-       uniqueEPGKey service( HILO(eit->service_id),
-               use_transponder_chid ? chid.original_network_id.get() : HILO(eit->original_network_id),
-               use_transponder_chid ? chid.transport_stream_id.get() : HILO(eit->transport_stream_id));
+       /*
+        * Make an exception for BEV (onid 0x100, 0x101), which doesn't use
+        * SCHEDULE_OTHER. As a result SCHEDULE will contain data for different tsid's,
+        * so we should not replace it with the current tsid.
+        */
+       bool use_transponder_chid = onid != 0x101 && onid != 0x100 && (source == SCHEDULE || (source == NOWNEXT && data[0] == 0x4E));
+
+       if (use_transponder_chid && channel)
+       {
+               eDVBChannelID chid = channel->channel->getChannelID();
+
+               onid = chid.original_network_id.get();
+               tsid = chid.transport_stream_id.get();
+       }
+
+       uniqueEPGKey service( eit->getServiceID(), onid, tsid);
 
        eit_event_struct* eit_event = (eit_event_struct*) (data+ptr);
        int eit_event_size;
        int duration;
 
 
        eit_event_struct* eit_event = (eit_event_struct*) (data+ptr);
        int eit_event_size;
        int duration;
 
-       time_t TM = parseDVBtime(
-                       eit_event->start_time_1,
-                       eit_event->start_time_2,
-                       eit_event->start_time_3,
-                       eit_event->start_time_4,
-                       eit_event->start_time_5);
+       time_t TM = parseDVBtime((const uint8_t*)eit_event + 2);
        time_t now = ::time(0);
 
        time_t now = ::time(0);
 
-       if ( TM != 3599 && TM > -1)
+       if ( TM != 3599 && TM > -1 && channel)
                channel->haveData |= source;
 
        singleLock s(cache_lock);
                channel->haveData |= source;
 
        singleLock s(cache_lock);
-       // hier wird immer eine eventMap zurück gegeben.. entweder eine vorhandene..
+       // hier wird immer eine eventMap zurck gegeben.. entweder eine vorhandene..
        // oder eine durch [] erzeugte
        // oder eine durch [] erzeugte
-       std::pair<eventMap,timeMap> &servicemap = eventDB[service];
-       eventMap::iterator prevEventIt = servicemap.first.end();
-       timeMap::iterator prevTimeIt = servicemap.second.end();
+       EventCacheItem &servicemap = eventDB[service];
+       eventMap::iterator prevEventIt = servicemap.byEvent.end();
+       timeMap::iterator prevTimeIt = servicemap.byTime.end();
 
        while (ptr<len)
        {
 
        while (ptr<len)
        {
-               __u16 event_hash;
-               eit_event_size = HILO(eit_event->descriptors_loop_length)+EIT_LOOP_SIZE;
+               uint16_t event_hash;
+               eit_event_size = eit_event->getDescriptorsLoopLength()+EIT_LOOP_SIZE;
 
                duration = fromBCD(eit_event->duration_1)*3600+fromBCD(eit_event->duration_2)*60+fromBCD(eit_event->duration_3);
 
                duration = fromBCD(eit_event->duration_1)*3600+fromBCD(eit_event->duration_2)*60+fromBCD(eit_event->duration_3);
-               TM = parseDVBtime(
-                       eit_event->start_time_1,
-                       eit_event->start_time_2,
-                       eit_event->start_time_3,
-                       eit_event->start_time_4,
-                       eit_event->start_time_5,
-                       &event_hash);
-
-               if ( TM == 3599 )
-                       goto next;
+               TM = parseDVBtime((const uint8_t*)eit_event + 2, &event_hash);
 
 
-               if ( TM != 3599 && (TM+duration < now || TM > now+14*24*60*60) )
-                       goto next;
-
-               if ( now <= (TM+duration) || TM == 3599 /*NVOD Service*/ )  // old events should not be cached
+               if ( (TM != 3599) &&            // NVOD Service
+                    (now <= (TM+duration)) &&  // skip old events
+                    (TM < (now+28*24*60*60)) &&        // no more than 4 weeks in future
+                    ( (onid != 1714) || (duration != (24*3600-1)) )    // PlatformaHD invalid event
+                  )
                {
                {
-                       __u16 event_id = HILO(eit_event->event_id);
+                       uint16_t event_id = eit_event->getEventId();
                        eventData *evt = 0;
                        int ev_erase_count = 0;
                        int tm_erase_count = 0;
                        eventData *evt = 0;
                        int ev_erase_count = 0;
                        int tm_erase_count = 0;
@@ -569,32 +784,31 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel)
 
                        // search in eventmap
                        eventMap::iterator ev_it =
 
                        // search in eventmap
                        eventMap::iterator ev_it =
-                               servicemap.first.find(event_id);
+                               servicemap.byEvent.find(event_id);
 
 
-//                     eDebug("event_id is %d sid is %04x", event_id, service.sid);
+                       //eDebug("[eEPGCache] event_id : %d, sid : %04x", event_id, service.sid);
 
                        // entry with this event_id is already exist ?
 
                        // entry with this event_id is already exist ?
-                       if ( ev_it != servicemap.first.end() )
+                       if ( ev_it != servicemap.byEvent.end() )
                        {
                                if ( source > ev_it->second->type )  // update needed ?
                                        goto next; // when not.. then skip this entry
 
                                // search this event in timemap
                                timeMap::iterator tm_it_tmp =
                        {
                                if ( source > ev_it->second->type )  // update needed ?
                                        goto next; // when not.. then skip this entry
 
                                // search this event in timemap
                                timeMap::iterator tm_it_tmp =
-                                       servicemap.second.find(ev_it->second->getStartTime());
+                                       servicemap.byTime.find(ev_it->second->getStartTime());
 
 
-                               if ( tm_it_tmp != servicemap.second.end() )
+                               if ( tm_it_tmp != servicemap.byTime.end() )
                                {
                                        if ( tm_it_tmp->first == TM ) // just update eventdata
                                        {
                                                // exempt memory
                                                eventData *tmp = ev_it->second;
                                {
                                        if ( tm_it_tmp->first == TM ) // just update eventdata
                                        {
                                                // exempt memory
                                                eventData *tmp = ev_it->second;
-                                               ev_it->second = tm_it_tmp->second =
-                                                       new eventData(eit_event, eit_event_size, source);
+                                               ev_it->second = tm_it_tmp->second = new eventData(eit_event, eit_event_size, source, (tsid<<16)|onid);
                                                if (FixOverlapping(servicemap, TM, duration, tm_it_tmp, service))
                                                {
                                                if (FixOverlapping(servicemap, TM, duration, tm_it_tmp, service))
                                                {
-                                                       prevEventIt = servicemap.first.end();
-                                                       prevTimeIt = servicemap.second.end();
+                                                       prevEventIt = servicemap.byEvent.end();
+                                                       prevTimeIt = servicemap.byTime.end();
                                                }
                                                delete tmp;
                                                goto next;
                                                }
                                                delete tmp;
                                                goto next;
@@ -603,8 +817,8 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel)
                                        {
                                                tm_erase_count++;
                                                // delete the found record from timemap
                                        {
                                                tm_erase_count++;
                                                // delete the found record from timemap
-                                               servicemap.second.erase(tm_it_tmp);
-                                               prevTimeIt=servicemap.second.end();
+                                               servicemap.byTime.erase(tm_it_tmp);
+                                               prevTimeIt = servicemap.byTime.end();
                                        }
                                }
                        }
                                        }
                                }
                        }
@@ -612,28 +826,27 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel)
                        // search in timemap, for check of a case if new time has coincided with time of other event
                        // or event was is not found in eventmap
                        timeMap::iterator tm_it =
                        // search in timemap, for check of a case if new time has coincided with time of other event
                        // or event was is not found in eventmap
                        timeMap::iterator tm_it =
-                               servicemap.second.find(TM);
+                               servicemap.byTime.find(TM);
 
 
-                       if ( tm_it != servicemap.second.end() )
+                       if ( tm_it != servicemap.byTime.end() )
                        {
                                // event with same start time but another event_id...
                                if ( source > tm_it->second->type &&
                        {
                                // event with same start time but another event_id...
                                if ( source > tm_it->second->type &&
-                                       ev_it == servicemap.first.end() )
+                                       ev_it == servicemap.byEvent.end() )
                                        goto next; // when not.. then skip this entry
 
                                // search this time in eventmap
                                        goto next; // when not.. then skip this entry
 
                                // search this time in eventmap
-                               eventMap::iterator ev_it_tmp =
-                                       servicemap.first.find(tm_it->second->getEventID());
+                               eventMap::iterator ev_it_tmp = servicemap.byEvent.find(tm_it->second->getEventID());
 
 
-                               if ( ev_it_tmp != servicemap.first.end() )
+                               if ( ev_it_tmp != servicemap.byEvent.end() )
                                {
                                        ev_erase_count++;
                                        // delete the found record from eventmap
                                {
                                        ev_erase_count++;
                                        // delete the found record from eventmap
-                                       servicemap.first.erase(ev_it_tmp);
-                                       prevEventIt=servicemap.first.end();
+                                       servicemap.byEvent.erase(ev_it_tmp);
+                                       prevEventIt = servicemap.byEvent.end();
                                }
                        }
                                }
                        }
-                       evt = new eventData(eit_event, eit_event_size, source);
+                       evt = new eventData(eit_event, eit_event_size, source, (tsid<<16)|onid);
 #ifdef EPG_DEBUG
                        bool consistencyCheck=true;
 #endif
 #ifdef EPG_DEBUG
                        bool consistencyCheck=true;
 #endif
@@ -649,90 +862,90 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel)
                        {
                                // exempt memory
                                delete ev_it->second;
                        {
                                // exempt memory
                                delete ev_it->second;
-                               tm_it=prevTimeIt=servicemap.second.insert( prevTimeIt, std::pair<const time_t, eventData*>( TM, evt ) );
-                               ev_it->second=evt;
+                               tm_it = prevTimeIt = servicemap.byTime.insert( prevTimeIt, std::pair<const time_t, eventData*>( TM, evt ) );
+                               ev_it->second = evt;
                        }
                        else if (ev_erase_count > 0 && tm_erase_count == 0)
                        {
                                // exempt memory
                                delete tm_it->second;
                        }
                        else if (ev_erase_count > 0 && tm_erase_count == 0)
                        {
                                // exempt memory
                                delete tm_it->second;
-                               ev_it=prevEventIt=servicemap.first.insert( prevEventIt, std::pair<const __u16, eventData*>( event_id, evt) );
-                               tm_it->second=evt;
+                               ev_it = prevEventIt = servicemap.byEvent.insert( prevEventIt, std::pair<const uint16_t, eventData*>( event_id, evt) );
+                               tm_it->second = evt;
                        }
                        else // added new eventData
                        {
 #ifdef EPG_DEBUG
                                consistencyCheck=false;
 #endif
                        }
                        else // added new eventData
                        {
 #ifdef EPG_DEBUG
                                consistencyCheck=false;
 #endif
-                               ev_it=prevEventIt=servicemap.first.insert( prevEventIt, std::pair<const __u16, eventData*>( event_id, evt) );
-                               tm_it=prevTimeIt=servicemap.second.insert( prevTimeIt, std::pair<const time_t, eventData*>( TM, evt ) );
+                               ev_it = prevEventIt = servicemap.byEvent.insert( prevEventIt, std::pair<const uint16_t, eventData*>( event_id, evt) );
+                               tm_it = prevTimeIt = servicemap.byTime.insert( prevTimeIt, std::pair<const time_t, eventData*>( TM, evt ) );
                        }
 
 #ifdef EPG_DEBUG
                        if ( consistencyCheck )
                        {
                                if ( tm_it->second != evt || ev_it->second != evt )
                        }
 
 #ifdef EPG_DEBUG
                        if ( consistencyCheck )
                        {
                                if ( tm_it->second != evt || ev_it->second != evt )
-                                       eFatal("tm_it->second != ev_it->second");
+                                       eFatal("[eEPGCache] tm_it->second != ev_it->second");
                                else if ( tm_it->second->getStartTime() != tm_it->first )
                                else if ( tm_it->second->getStartTime() != tm_it->first )
-                                       eFatal("event start_time(%d) non equal timemap key(%d)",
-                                               tm_it->second->getStartTime(), tm_it->first );
+                                       eFatal("[eEPGCache] event start_time(%d) non equal timemap key(%d)",
+                                               (int)tm_it->second->getStartTime(), (int)tm_it->first );
                                else if ( tm_it->first != TM )
                                else if ( tm_it->first != TM )
-                                       eFatal("timemap key(%d) non equal TM(%d)",
-                                               tm_it->first, TM);
+                                       eFatal("[eEPGCache] timemap key(%d) non equal TM(%d)",
+                                               (int)tm_it->first, (int)TM);
                                else if ( ev_it->second->getEventID() != ev_it->first )
                                else if ( ev_it->second->getEventID() != ev_it->first )
-                                       eFatal("event_id (%d) non equal event_map key(%d)",
-                                               ev_it->second->getEventID(), ev_it->first);
+                                       eFatal("[eEPGCache] event_id (%d) non equal event_map key(%d)",
+                                               (int)ev_it->second->getEventID(), (int)ev_it->first);
                                else if ( ev_it->first != event_id )
                                else if ( ev_it->first != event_id )
-                                       eFatal("eventmap key(%d) non equal event_id(%d)",
-                                               ev_it->first, event_id );
+                                       eFatal("[eEPGCache] eventmap key(%d) non equal event_id(%d)",
+                                               (int)ev_it->first, (int)event_id );
                        }
 #endif
                        if (FixOverlapping(servicemap, TM, duration, tm_it, service))
                        {
                        }
 #endif
                        if (FixOverlapping(servicemap, TM, duration, tm_it, service))
                        {
-                               prevEventIt = servicemap.first.end();
-                               prevTimeIt = servicemap.second.end();
+                               prevEventIt = servicemap.byEvent.end();
+                               prevTimeIt = servicemap.byTime.end();
                        }
                }
 next:
 #ifdef EPG_DEBUG
                        }
                }
 next:
 #ifdef EPG_DEBUG
-               if ( servicemap.first.size() != servicemap.second.size() )
+               if ( servicemap.byEvent.size() != servicemap.byTime.size() )
                {
                        FILE *f = fopen("/hdd/event_map.txt", "w+");
                        int i=0;
                {
                        FILE *f = fopen("/hdd/event_map.txt", "w+");
                        int i=0;
-                       for (eventMap::iterator it(servicemap.first.begin())
-                               ; it != servicemap.first.end(); ++it )
+                       for (eventMap::iterator it(servicemap.byEvent.begin())
+                               ; it != servicemap.byEvent.end(); ++it )
                                fprintf(f, "%d(key %d) -> time %d, event_id %d, data %p\n", 
                                        i++, (int)it->first, (int)it->second->getStartTime(), (int)it->second->getEventID(), it->second );
                        fclose(f);
                        f = fopen("/hdd/time_map.txt", "w+");
                        i=0;
                                fprintf(f, "%d(key %d) -> time %d, event_id %d, data %p\n", 
                                        i++, (int)it->first, (int)it->second->getStartTime(), (int)it->second->getEventID(), it->second );
                        fclose(f);
                        f = fopen("/hdd/time_map.txt", "w+");
                        i=0;
-                       for (timeMap::iterator it(servicemap.second.begin())
-                               ; it != servicemap.second.end(); ++it )
+                       for (timeMap::iterator it(servicemap.byTime.begin())
+                               ; it != servicemap.byTime.end(); ++it )
                                        fprintf(f, "%d(key %d) -> time %d, event_id %d, data %p\n", 
                                                i++, (int)it->first, (int)it->second->getStartTime(), (int)it->second->getEventID(), it->second );
                        fclose(f);
 
                                        fprintf(f, "%d(key %d) -> time %d, event_id %d, data %p\n", 
                                                i++, (int)it->first, (int)it->second->getStartTime(), (int)it->second->getEventID(), it->second );
                        fclose(f);
 
-                       eFatal("(1)map sizes not equal :( sid %04x tsid %04x onid %04x size %d size2 %d", 
-                               service.sid, service.tsid, service.onid, 
-                               servicemap.first.size(), servicemap.second.size() );
+                       eFatal("[eEPGCache] (1)map sizes not equal :( sid %04x tsid %04x onid %04x size %d size2 %d",
+                               service.sid, service.tsid, service.onid,
+                               servicemap.byEvent.size(), servicemap.byTime.size() );
                }
 #endif
                ptr += eit_event_size;
                }
 #endif
                ptr += eit_event_size;
-               eit_event=(eit_event_struct*)(((__u8*)eit_event)+eit_event_size);
+               eit_event = (eit_event_struct*)(((uint8_t*)eit_event) + eit_event_size);
        }
 }
 
 void eEPGCache::flushEPG(const uniqueEPGKey & s)
 {
        }
 }
 
 void eEPGCache::flushEPG(const uniqueEPGKey & s)
 {
-       eDebug("[EPGC] flushEPG %d", (int)(bool)s);
+       eDebug("[eEPGCache] flushEPG %d", (int)(bool)s);
        singleLock l(cache_lock);
        if (s)  // clear only this service
        {
                eventCache::iterator it = eventDB.find(s);
                if ( it != eventDB.end() )
                {
        singleLock l(cache_lock);
        if (s)  // clear only this service
        {
                eventCache::iterator it = eventDB.find(s);
                if ( it != eventDB.end() )
                {
-                       eventMap &evMap = it->second.first;
-                       timeMap &tmMap = it->second.second;
+                       eventMap &evMap = it->second.byEvent;
+                       timeMap &tmMap = it->second.byTime;
                        tmMap.clear();
                        for (eventMap::iterator i = evMap.begin(); i != evMap.end(); ++i)
                                delete i->second;
                        tmMap.clear();
                        for (eventMap::iterator i = evMap.begin(); i != evMap.end(); ++i)
                                delete i->second;
@@ -756,8 +969,8 @@ void eEPGCache::flushEPG(const uniqueEPGKey & s)
                for (eventCache::iterator it(eventDB.begin());
                        it != eventDB.end(); ++it)
                {
                for (eventCache::iterator it(eventDB.begin());
                        it != eventDB.end(); ++it)
                {
-                       eventMap &evMap = it->second.first;
-                       timeMap &tmMap = it->second.second;
+                       eventMap &evMap = it->second.byEvent;
+                       timeMap &tmMap = it->second.byTime;
                        for (eventMap::iterator i = evMap.begin(); i != evMap.end(); ++i)
                                delete i->second;
                        evMap.clear();
                        for (eventMap::iterator i = evMap.begin(); i != evMap.end(); ++i)
                                delete i->second;
                        evMap.clear();
@@ -769,42 +982,38 @@ void eEPGCache::flushEPG(const uniqueEPGKey & s)
 #endif
                channelLastUpdated.clear();
                singleLock m(channel_map_lock);
 #endif
                channelLastUpdated.clear();
                singleLock m(channel_map_lock);
-               for (channelMapIterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it)
+               for (ChannelMap::const_iterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it)
                        it->second->startEPG();
        }
                        it->second->startEPG();
        }
-       eDebug("[EPGC] %i bytes for cache used", eventData::CacheSize);
 }
 
 void eEPGCache::cleanLoop()
 {
 }
 
 void eEPGCache::cleanLoop()
 {
-       singleLock s(cache_lock);
-       if (!eventDB.empty())
-       {
-               eDebug("[EPGC] start cleanloop");
-
-               time_t now = ::time(0);
+       { /* scope for cache lock */
+               time_t now = ::time(0) - historySeconds;
+               singleLock s(cache_lock);
 
                for (eventCache::iterator DBIt = eventDB.begin(); DBIt != eventDB.end(); DBIt++)
                {
                        bool updated = false;
 
                for (eventCache::iterator DBIt = eventDB.begin(); DBIt != eventDB.end(); DBIt++)
                {
                        bool updated = false;
-                       for (timeMap::iterator It = DBIt->second.second.begin(); It != DBIt->second.second.end() && It->first < now;)
+                       for (timeMap::iterator It = DBIt->second.byTime.begin(); It != DBIt->second.byTime.end() && It->first < now;)
                        {
                                if ( now > (It->first+It->second->getDuration()) )  // outdated normal entry (nvod references to)
                                {
                                        // remove entry from eventMap
                        {
                                if ( now > (It->first+It->second->getDuration()) )  // outdated normal entry (nvod references to)
                                {
                                        // remove entry from eventMap
-                                       eventMap::iterator b(DBIt->second.first.find(It->second->getEventID()));
-                                       if ( b != DBIt->second.first.end() )
+                                       eventMap::iterator b(DBIt->second.byEvent.find(It->second->getEventID()));
+                                       if ( b != DBIt->second.byEvent.end() )
                                        {
                                                // release Heap Memory for this entry   (new ....)
                                        {
                                                // release Heap Memory for this entry   (new ....)
-//                                             eDebug("[EPGC] delete old event (evmap)");
-                                               DBIt->second.first.erase(b);
+                                               //eDebug("[eEPGCache] delete old event (evmap)");
+                                               DBIt->second.byEvent.erase(b);
                                        }
 
                                        // remove entry from timeMap
                                        }
 
                                        // remove entry from timeMap
-//                                     eDebug("[EPGC] release heap mem");
+                                       //eDebug("[eEPGCache] release heap mem");
                                        delete It->second;
                                        delete It->second;
-                                       DBIt->second.second.erase(It++);
-//                                     eDebug("[EPGC] delete old event (timeMap)");
+                                       DBIt->second.byTime.erase(It++);
+                                       //eDebug("[eEPGCache] delete old event (timeMap)");
                                        updated = true;
                                }
                                else
                                        updated = true;
                                }
                                else
@@ -817,7 +1026,7 @@ void eEPGCache::cleanLoop()
                                        content_time_tables.find( DBIt->first );
                                if ( x != content_time_tables.end() )
                                {
                                        content_time_tables.find( DBIt->first );
                                if ( x != content_time_tables.end() )
                                {
-                                       timeMap &tmMap = DBIt->second.second;
+                                       timeMap &tmMap = DBIt->second.byTime;
                                        for ( contentMap::iterator i = x->second.begin(); i != x->second.end(); )
                                        {
                                                for ( contentTimeMap::iterator it(i->second.begin());
                                        for ( contentMap::iterator i = x->second.begin(); i != x->second.end(); )
                                        {
                                                for ( contentTimeMap::iterator it(i->second.begin());
@@ -837,19 +1046,18 @@ void eEPGCache::cleanLoop()
                        }
 #endif
                }
                        }
 #endif
                }
-               eDebug("[EPGC] stop cleanloop");
-               eDebug("[EPGC] %i bytes for cache used", eventData::CacheSize);
-       }
+       } /* release lock */
        cleanTimer->start(CLEAN_INTERVAL,true);
 }
 
 eEPGCache::~eEPGCache()
 {
        cleanTimer->start(CLEAN_INTERVAL,true);
 }
 
 eEPGCache::~eEPGCache()
 {
+       m_running = false;
        messages.send(Message::quit);
        kill(); // waiting for thread shutdown
        singleLock s(cache_lock);
        for (eventCache::iterator evIt = eventDB.begin(); evIt != eventDB.end(); evIt++)
        messages.send(Message::quit);
        kill(); // waiting for thread shutdown
        singleLock s(cache_lock);
        for (eventCache::iterator evIt = eventDB.begin(); evIt != eventDB.end(); evIt++)
-               for (eventMap::iterator It = evIt->second.first.begin(); It != evIt->second.first.end(); It++)
+               for (eventMap::iterator It = evIt->second.byEvent.begin(); It != evIt->second.byEvent.end(); It++)
                        delete It->second;
 }
 
                        delete It->second;
 }
 
@@ -863,8 +1071,7 @@ void eEPGCache::gotMessage( const Message &msg )
                case Message::startChannel:
                {
                        singleLock s(channel_map_lock);
                case Message::startChannel:
                {
                        singleLock s(channel_map_lock);
-                       channelMapIterator channel =
-                               m_knownChannels.find(msg.channel);
+                       ChannelMap::const_iterator channel = m_knownChannels.find(msg.channel);
                        if ( channel != m_knownChannels.end() )
                                channel->second->startChannel();
                        break;
                        if ( channel != m_knownChannels.end() )
                                channel->second->startChannel();
                        break;
@@ -872,8 +1079,7 @@ void eEPGCache::gotMessage( const Message &msg )
                case Message::leaveChannel:
                {
                        singleLock s(channel_map_lock);
                case Message::leaveChannel:
                {
                        singleLock s(channel_map_lock);
-                       channelMapIterator channel =
-                               m_knownChannels.find(msg.channel);
+                       ChannelMap::const_iterator channel = m_knownChannels.find(msg.channel);
                        if ( channel != m_knownChannels.end() )
                                channel->second->abortEPG();
                        break;
                        if ( channel != m_knownChannels.end() )
                                channel->second->abortEPG();
                        break;
@@ -885,7 +1091,7 @@ void eEPGCache::gotMessage( const Message &msg )
                case Message::got_private_pid:
                {
                        singleLock s(channel_map_lock);
                case Message::got_private_pid:
                {
                        singleLock s(channel_map_lock);
-                       for (channelMapIterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it)
+                       for (ChannelMap::const_iterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it)
                        {
                                eDVBChannel *channel = (eDVBChannel*) it->first;
                                channel_data *data = it->second;
                        {
                                eDVBChannel *channel = (eDVBChannel*) it->first;
                                channel_data *data = it->second;
@@ -906,9 +1112,9 @@ void eEPGCache::gotMessage( const Message &msg )
                                                update = ZAP_DELAY;
                                        data->startPrivateTimer->start(update, 1);
                                        if (update >= 60000)
                                                update = ZAP_DELAY;
                                        data->startPrivateTimer->start(update, 1);
                                        if (update >= 60000)
-                                               eDebug("[EPGC] next private update in %i min", update/60000);
+                                               eDebug("[eEPGCache] next private update in %i min", update/60000);
                                        else if (update >= 1000)
                                        else if (update >= 1000)
-                                               eDebug("[EPGC] next private update in %i sec", update/1000);
+                                               eDebug("[eEPGCache] next private update in %i sec", update/1000);
                                        break;
                                }
                        }
                                        break;
                                }
                        }
@@ -919,7 +1125,7 @@ void eEPGCache::gotMessage( const Message &msg )
                case Message::got_mhw2_channel_pid:
                {
                        singleLock s(channel_map_lock);
                case Message::got_mhw2_channel_pid:
                {
                        singleLock s(channel_map_lock);
-                       for (channelMapIterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it)
+                       for (ChannelMap::const_iterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it)
                        {
                                eDVBChannel *channel = (eDVBChannel*) it->first;
                                channel_data *data = it->second;
                        {
                                eDVBChannel *channel = (eDVBChannel*) it->first;
                                channel_data *data = it->second;
@@ -928,7 +1134,7 @@ void eEPGCache::gotMessage( const Message &msg )
                                        chid.original_network_id.get() == msg.service.onid )
                                {
                                        data->m_mhw2_channel_pid = msg.pid;
                                        chid.original_network_id.get() == msg.service.onid )
                                {
                                        data->m_mhw2_channel_pid = msg.pid;
-                                       eDebug("[EPGC] got mhw2 channel pid %04x", msg.pid);
+                                       eDebug("[eEPGCache] got mhw2 channel pid %04x", msg.pid);
                                        break;
                                }
                        }
                                        break;
                                }
                        }
@@ -937,7 +1143,7 @@ void eEPGCache::gotMessage( const Message &msg )
                case Message::got_mhw2_title_pid:
                {
                        singleLock s(channel_map_lock);
                case Message::got_mhw2_title_pid:
                {
                        singleLock s(channel_map_lock);
-                       for (channelMapIterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it)
+                       for (ChannelMap::const_iterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it)
                        {
                                eDVBChannel *channel = (eDVBChannel*) it->first;
                                channel_data *data = it->second;
                        {
                                eDVBChannel *channel = (eDVBChannel*) it->first;
                                channel_data *data = it->second;
@@ -946,7 +1152,7 @@ void eEPGCache::gotMessage( const Message &msg )
                                        chid.original_network_id.get() == msg.service.onid )
                                {
                                        data->m_mhw2_title_pid = msg.pid;
                                        chid.original_network_id.get() == msg.service.onid )
                                {
                                        data->m_mhw2_title_pid = msg.pid;
-                                       eDebug("[EPGC] got mhw2 title pid %04x", msg.pid);
+                                       eDebug("[eEPGCache] got mhw2 title pid %04x", msg.pid);
                                        break;
                                }
                        }
                                        break;
                                }
                        }
@@ -955,7 +1161,7 @@ void eEPGCache::gotMessage( const Message &msg )
                case Message::got_mhw2_summary_pid:
                {
                        singleLock s(channel_map_lock);
                case Message::got_mhw2_summary_pid:
                {
                        singleLock s(channel_map_lock);
-                       for (channelMapIterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it)
+                       for (ChannelMap::const_iterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it)
                        {
                                eDVBChannel *channel = (eDVBChannel*) it->first;
                                channel_data *data = it->second;
                        {
                                eDVBChannel *channel = (eDVBChannel*) it->first;
                                channel_data *data = it->second;
@@ -964,7 +1170,7 @@ void eEPGCache::gotMessage( const Message &msg )
                                        chid.original_network_id.get() == msg.service.onid )
                                {
                                        data->m_mhw2_summary_pid = msg.pid;
                                        chid.original_network_id.get() == msg.service.onid )
                                {
                                        data->m_mhw2_summary_pid = msg.pid;
-                                       eDebug("[EPGC] got mhw2 summary pid %04x", msg.pid);
+                                       eDebug("[eEPGCache] got mhw2 summary pid %04x", msg.pid);
                                        break;
                                }
                        }
                                        break;
                                }
                        }
@@ -975,7 +1181,7 @@ void eEPGCache::gotMessage( const Message &msg )
                        cleanLoop();
                        break;
                default:
                        cleanLoop();
                        break;
                default:
-                       eDebug("unhandled EPGCache Message!!");
+                       eDebug("[eEPGCache] unhandled EPGCache Message!!");
                        break;
        }
 }
                        break;
        }
 }
@@ -983,137 +1189,177 @@ void eEPGCache::gotMessage( const Message &msg )
 void eEPGCache::thread()
 {
        hasStarted();
 void eEPGCache::thread()
 {
        hasStarted();
-       m_running=1;
        nice(4);
        load();
        cleanLoop();
        runLoop();
        save();
        nice(4);
        load();
        cleanLoop();
        runLoop();
        save();
-       m_running=0;
 }
 
 }
 
+static const char* EPGDAT_IN_FLASH = "/epg.dat";
+
 void eEPGCache::load()
 {
 void eEPGCache::load()
 {
-       FILE *f = fopen(m_filename, "r");
-       if (f)
+       if (m_filename.empty())
+               m_filename = "/hdd/epg.dat";
+       const char* EPGDAT = m_filename.c_str();
+       std::string filenamex = m_filename + ".loading";
+       const char* EPGDATX = filenamex.c_str();
+       FILE *f = fopen(EPGDAT, "rb");
+       int renameResult;
+       if (f == NULL)
+       {
+               /* No EPG on harddisk, so try internal flash */
+               eDebug("[eEPGCache] %s not found, try %s", EPGDAT, EPGDAT_IN_FLASH);
+               EPGDAT = EPGDAT_IN_FLASH;
+               f = fopen(EPGDAT, "rb");
+               if (f == NULL)
+                       return;
+               renameResult = -1;
+       }
+       else
+       {
+               unlink(EPGDATX);
+               renameResult = rename(EPGDAT, EPGDATX);
+               if (renameResult) eDebug("[eEPGCache] failed to rename %s", EPGDAT);
+       }
        {
        {
-               unlink(m_filename);
                int size=0;
                int cnt=0;
                int size=0;
                int cnt=0;
-
+               unsigned int magic=0;
+               unlink(EPGDAT_IN_FLASH);/* Don't keep it around when in flash */
+               fread( &magic, sizeof(int), 1, f);
+               if (magic != 0x98765432)
                {
                {
-                       unsigned int magic=0;
-                       fread( &magic, sizeof(int), 1, f);
-                       if (magic != 0x98765432)
-                       {
-                               eDebug("[EPGC] epg file has incorrect byte order.. dont read it");
-                               fclose(f);
-                               return;
-                       }
-                       char text1[13];
-                       fread( text1, 13, 1, f);
-                       if ( !strncmp( text1, "ENIGMA_EPG_V7", 13) )
+                       eDebug("[eEPGCache] epg file has incorrect byte order.. dont read it");
+                       fclose(f);
+                       return;
+               }
+               char text1[13];
+               fread( text1, 13, 1, f);
+               if ( !memcmp( text1, "ENIGMA_EPG_V7", 13) )
+               {
+                       singleLock s(cache_lock);
+                       fread( &size, sizeof(int), 1, f);
+                       eventDB.rehash(size); /* Reserve buckets in advance */
+                       while(size--)
                        {
                        {
-                               singleLock s(cache_lock);
+                               uniqueEPGKey key;
+                               int size=0;
+                               fread( &key, sizeof(uniqueEPGKey), 1, f);
                                fread( &size, sizeof(int), 1, f);
                                fread( &size, sizeof(int), 1, f);
+                               EventCacheItem& item = eventDB[key]; /* Constructs new entry */
                                while(size--)
                                {
                                while(size--)
                                {
-                                       uniqueEPGKey key;
-                                       eventMap evMap;
-                                       timeMap tmMap;
-                                       int size=0;
-                                       fread( &key, sizeof(uniqueEPGKey), 1, f);
-                                       fread( &size, sizeof(int), 1, f);
-                                       while(size--)
+                                       uint8_t len=0;
+                                       uint8_t type=0;
+                                       eventData *event=0;
+                                       fread( &type, sizeof(uint8_t), 1, f);
+                                       fread( &len, sizeof(uint8_t), 1, f);
+                                       event = new eventData(0, len, type);
+                                       event->n_crc = (len-10) / sizeof(uint32_t);
+                                       fread( event->rawEITdata, 10, 1, f);
+                                       if (event->n_crc)
                                        {
                                        {
-                                               __u8 len=0;
-                                               __u8 type=0;
-                                               eventData *event=0;
-                                               fread( &type, sizeof(__u8), 1, f);
-                                               fread( &len, sizeof(__u8), 1, f);
-                                               event = new eventData(0, len, type);
-                                               event->EITdata = new __u8[len];
-                                               eventData::CacheSize+=len;
-                                               fread( event->EITdata, len, 1, f);
-                                               evMap[ event->getEventID() ]=event;
-                                               tmMap[ event->getStartTime() ]=event;
-                                               ++cnt;
+                                               event->crc_list = new uint32_t[event->n_crc];
+                                               fread( event->crc_list, sizeof(uint32_t), event->n_crc, f);
                                        }
                                        }
-                                       eventDB[key]=std::pair<eventMap,timeMap>(evMap,tmMap);
+                                       eventData::CacheSize += sizeof(eventData) + event->n_crc * sizeof(uint32_t);
+                                       item.byEvent[event->getEventID()] = event;
+                                       item.byTime[event->getStartTime()] = event;
+                                       ++cnt;
                                }
                                }
-                               eventData::load(f);
-                               eDebug("[EPGC] %d events read from %s", cnt, m_filename);
+                       }
+                       eventData::load(f);
+                       eDebug("[eEPGCache] %d events read from %s", cnt, EPGDAT);
 #ifdef ENABLE_PRIVATE_EPG
 #ifdef ENABLE_PRIVATE_EPG
-                               char text2[11];
-                               fread( text2, 11, 1, f);
-                               if ( !strncmp( text2, "PRIVATE_EPG", 11) )
+                       char text2[11];
+                       fread( text2, 11, 1, f);
+                       if ( !memcmp( text2, "PRIVATE_EPG", 11) )
+                       {
+                               size=0;
+                               fread( &size, sizeof(int), 1, f);
+                               eventDB.rehash(size); /* Reserve buckets in advance */
+                               while(size--)
                                {
                                {
-                                       size=0;
+                                       int size=0;
+                                       uniqueEPGKey key;
+                                       fread( &key, sizeof(uniqueEPGKey), 1, f);
+                                       eventMap &evMap = eventDB[key].byEvent;
                                        fread( &size, sizeof(int), 1, f);
                                        while(size--)
                                        {
                                        fread( &size, sizeof(int), 1, f);
                                        while(size--)
                                        {
-                                               int size=0;
-                                               uniqueEPGKey key;
-                                               fread( &key, sizeof(uniqueEPGKey), 1, f);
-                                               eventMap &evMap=eventDB[key].first;
+                                               int size;
+                                               int content_id;
+                                               fread( &content_id, sizeof(int), 1, f);
                                                fread( &size, sizeof(int), 1, f);
                                                while(size--)
                                                {
                                                fread( &size, sizeof(int), 1, f);
                                                while(size--)
                                                {
-                                                       int size;
-                                                       int content_id;
-                                                       fread( &content_id, sizeof(int), 1, f);
-                                                       fread( &size, sizeof(int), 1, f);
-                                                       while(size--)
-                                                       {
-                                                               time_t time1, time2;
-                                                               __u16 event_id;
-                                                               fread( &time1, sizeof(time_t), 1, f);
-                                                               fread( &time2, sizeof(time_t), 1, f);
-                                                               fread( &event_id, sizeof(__u16), 1, f);
-                                                               content_time_tables[key][content_id][time1]=std::pair<time_t, __u16>(time2, event_id);
-                                                               eventMap::iterator it =
-                                                                       evMap.find(event_id);
-                                                               if (it != evMap.end())
-                                                                       it->second->type = PRIVATE;
-                                                       }
+                                                       time_t time1, time2;
+                                                       uint16_t event_id;
+                                                       fread( &time1, sizeof(time_t), 1, f);
+                                                       fread( &time2, sizeof(time_t), 1, f);
+                                                       fread( &event_id, sizeof(uint16_t), 1, f);
+                                                       content_time_tables[key][content_id][time1]=std::pair<time_t, uint16_t>(time2, event_id);
+                                                       eventMap::iterator it =
+                                                               evMap.find(event_id);
+                                                       if (it != evMap.end())
+                                                               it->second->type = PRIVATE;
                                                }
                                        }
                                }
                                                }
                                        }
                                }
-#endif // ENABLE_PRIVATE_EPG
                        }
                        }
-                       else
-                               eDebug("[EPGC] don't read old epg database");
-                       fclose(f);
+#endif // ENABLE_PRIVATE_EPG
+               }
+               else
+                       eDebug("[eEPGCache] don't read old epg database");
+               posix_fadvise(fileno(f), 0, 0, POSIX_FADV_DONTNEED);
+               fclose(f);
+               // We got this far, so the EPG file is okay.
+               if (renameResult == 0)
+               {
+                       renameResult = rename(EPGDATX, EPGDAT);
+                       if (renameResult) eDebug("[eEPGCache] failed to rename epg.dat back");
                }
        }
 }
 
 void eEPGCache::save()
 {
                }
        }
 }
 
 void eEPGCache::save()
 {
-       /* create empty file */
-       FILE *f = fopen(m_filename, "w");
+       const char* EPGDAT = m_filename.c_str();
+       if (eventData::isCacheCorrupt)
+               return;
+       // only save epg.dat if it's worth the trouble...
+       if (eventData::CacheSize < 10240)
+               return;
 
 
+       /* create empty file */
+       FILE *f = fopen(EPGDAT, "wb");
        if (!f)
        {
        if (!f)
        {
-               eDebug("[EPGC] couldn't save epg data to '%s'(%m)", m_filename);
-               return;
+               eDebug("[eEPGCache] couldn't save epg data to '%s'(%m)", EPGDAT);
+               EPGDAT = EPGDAT_IN_FLASH;
+               f = fopen(EPGDAT, "wb");
+               if (!f)
+                       return;
        }
 
        }
 
-       char *buf = realpath(m_filename, NULL);
+       char *buf = realpath(EPGDAT, NULL);
        if (!buf)
        {
        if (!buf)
        {
-               eDebug("[EPGC] realpath to '%s' failed in save (%m)", m_filename);
+               eDebug("[eEPGCache] realpath to '%s' failed in save (%m)", EPGDAT);
                fclose(f);
                return;
        }
 
                fclose(f);
                return;
        }
 
-       eDebug("[EPGC] store epg to realpath '%s'", buf);
+       eDebug("[eEPGCache] store epg to realpath '%s'", buf);
 
        struct statfs s;
        off64_t tmp;
        if (statfs(buf, &s) < 0) {
 
        struct statfs s;
        off64_t tmp;
        if (statfs(buf, &s) < 0) {
-               eDebug("[EPGC] statfs '%s' failed in save (%m)", buf);
+               eDebug("[eEPGCache] statfs '%s' failed in save (%m)", buf);
                fclose(f);
                fclose(f);
+               free(buf);
                return;
        }
 
                return;
        }
 
@@ -1124,7 +1370,7 @@ void eEPGCache::save()
        tmp*=s.f_bsize;
        if ( tmp < (eventData::CacheSize*12)/10 ) // 20% overhead
        {
        tmp*=s.f_bsize;
        if ( tmp < (eventData::CacheSize*12)/10 ) // 20% overhead
        {
-               eDebug("[EPGC] not enough free space at path '%s' %lld bytes availd but %d needed", buf, tmp, (eventData::CacheSize*12)/10);
+               eDebug("[eEPGCache] not enough free space at '%s' %lld bytes available but %u needed", buf, tmp, (eventData::CacheSize*12)/10);
                fclose(f);
                return;
        }
                fclose(f);
                return;
        }
@@ -1138,20 +1384,21 @@ void eEPGCache::save()
        fwrite( &size, sizeof(int), 1, f );
        for (eventCache::iterator service_it(eventDB.begin()); service_it != eventDB.end(); ++service_it)
        {
        fwrite( &size, sizeof(int), 1, f );
        for (eventCache::iterator service_it(eventDB.begin()); service_it != eventDB.end(); ++service_it)
        {
-               timeMap &timemap = service_it->second.second;
+               timeMap &timemap = service_it->second.byTime;
                fwrite( &service_it->first, sizeof(uniqueEPGKey), 1, f);
                size = timemap.size();
                fwrite( &size, sizeof(int), 1, f);
                for (timeMap::iterator time_it(timemap.begin()); time_it != timemap.end(); ++time_it)
                {
                fwrite( &service_it->first, sizeof(uniqueEPGKey), 1, f);
                size = timemap.size();
                fwrite( &size, sizeof(int), 1, f);
                for (timeMap::iterator time_it(timemap.begin()); time_it != timemap.end(); ++time_it)
                {
-                       __u8 len = time_it->second->ByteSize;
-                       fwrite( &time_it->second->type, sizeof(__u8), 1, f );
-                       fwrite( &len, sizeof(__u8), 1, f);
-                       fwrite( time_it->second->EITdata, len, 1, f);
+                       uint8_t len = time_it->second->n_crc * sizeof(uint32_t) + 10;
+                       fwrite( &time_it->second->type, sizeof(uint8_t), 1, f );
+                       fwrite( &len, sizeof(uint8_t), 1, f);
+                       fwrite( time_it->second->rawEITdata, 10, 1, f);
+                       fwrite( time_it->second->crc_list, sizeof(uint32_t), time_it->second->n_crc, f);
                        ++cnt;
                }
        }
                        ++cnt;
                }
        }
-       eDebug("[EPGC] %d events written to %s", cnt, m_filename);
+       eDebug("[eEPGCache] %d events written to %s", cnt, EPGDAT);
        eventData::save(f);
 #ifdef ENABLE_PRIVATE_EPG
        const char* text3 = "PRIVATE_EPG";
        eventData::save(f);
 #ifdef ENABLE_PRIVATE_EPG
        const char* text3 = "PRIVATE_EPG";
@@ -1174,7 +1421,7 @@ void eEPGCache::save()
                        {
                                fwrite( &it->first, sizeof(time_t), 1, f);
                                fwrite( &it->second.first, sizeof(time_t), 1, f);
                        {
                                fwrite( &it->first, sizeof(time_t), 1, f);
                                fwrite( &it->second.first, sizeof(time_t), 1, f);
-                               fwrite( &it->second.second, sizeof(__u16), 1, f);
+                               fwrite( &it->second.second, sizeof(uint16_t), 1, f);
                        }
                }
        }
                        }
                }
        }
@@ -1209,31 +1456,32 @@ eEPGCache::channel_data::channel_data(eEPGCache *ml)
        pthread_mutex_init(&channel_active, 0);
 }
 
        pthread_mutex_init(&channel_active, 0);
 }
 
-bool eEPGCache::channel_data::finishEPG()
+void eEPGCache::channel_data::finishEPG()
 {
        if (!isRunning)  // epg ready
        {
 {
        if (!isRunning)  // epg ready
        {
-               eDebug("[EPGC] stop caching events(%ld)", ::time(0));
+               eDebug("[eEPGCache] stop caching events(%ld)", ::time(0));
                zapTimer->start(UPDATE_INTERVAL, 1);
                zapTimer->start(UPDATE_INTERVAL, 1);
-               eDebug("[EPGC] next update in %i min", UPDATE_INTERVAL / 60000);
+               eDebug("[eEPGCache] next update in %i min", UPDATE_INTERVAL / 60000);
                for (unsigned int i=0; i < sizeof(seenSections)/sizeof(tidMap); ++i)
                {
                        seenSections[i].clear();
                        calcedSections[i].clear();
                }
                for (unsigned int i=0; i < sizeof(seenSections)/sizeof(tidMap); ++i)
                {
                        seenSections[i].clear();
                        calcedSections[i].clear();
                }
-               singleLock l(cache->cache_lock);
-               cache->channelLastUpdated[channel->getChannelID()] = ::time(0);
 #ifdef ENABLE_MHW_EPG
 #ifdef ENABLE_MHW_EPG
-               cleanup();
+               cleanupMHW();
 #endif
 #endif
-               return true;
+#ifdef ENABLE_FREESAT
+               cleanupFreeSat();
+#endif
+               singleLock l(cache_lock);
+               cache->channelLastUpdated[channel->getChannelID()] = ::time(0);
        }
        }
-       return false;
 }
 
 void eEPGCache::channel_data::startEPG()
 {
 }
 
 void eEPGCache::channel_data::startEPG()
 {
-       eDebug("[EPGC] start caching events(%ld)", ::time(0));
+       eDebug("[eEPGCache] start caching events(%ld)", ::time(0));
        state=0;
        haveData=0;
        for (unsigned int i=0; i < sizeof(seenSections)/sizeof(tidMap); ++i)
        state=0;
        haveData=0;
        for (unsigned int i=0; i < sizeof(seenSections)/sizeof(tidMap); ++i)
@@ -1241,60 +1489,145 @@ void eEPGCache::channel_data::startEPG()
                seenSections[i].clear();
                calcedSections[i].clear();
        }
                seenSections[i].clear();
                calcedSections[i].clear();
        }
+#ifdef ENABLE_MHW_EPG
+               cleanupMHW();
+#endif
+#ifdef ENABLE_FREESAT
+               cleanupFreeSat();
+#endif
 
        eDVBSectionFilterMask mask;
        memset(&mask, 0, sizeof(mask));
 
 #ifdef ENABLE_MHW_EPG
 
        eDVBSectionFilterMask mask;
        memset(&mask, 0, sizeof(mask));
 
 #ifdef ENABLE_MHW_EPG
-       mask.pid = 0xD3;
-       mask.data[0] = 0x91;
-       mask.mask[0] = 0xFF;
-       m_MHWReader->connectRead(slot(*this, &eEPGCache::channel_data::readMHWData), m_MHWConn);
-       m_MHWReader->start(mask);
-       isRunning |= MHW;
-       memcpy(&m_MHWFilterMask, &mask, sizeof(eDVBSectionFilterMask));
-
-       mask.pid = m_mhw2_channel_pid;
-       mask.data[0] = 0xC8;
-       mask.mask[0] = 0xFF;
-       mask.data[1] = 0;
-       mask.mask[1] = 0xFF;
-       m_MHWReader2->connectRead(slot(*this, &eEPGCache::channel_data::readMHWData2), m_MHWConn2);
-       m_MHWReader2->start(mask);
-       isRunning |= MHW;
-       memcpy(&m_MHWFilterMask2, &mask, sizeof(eDVBSectionFilterMask));
-       mask.data[1] = 0;
-       mask.mask[1] = 0;
-       m_MHWTimeoutet=false;
+       if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::MHW)
+       {
+               mask.pid = 0xD3;
+               mask.data[0] = 0x91;
+               mask.mask[0] = 0xFF;
+               m_MHWReader->connectRead(slot(*this, &eEPGCache::channel_data::readMHWData), m_MHWConn);
+               m_MHWReader->start(mask);
+               isRunning |= MHW;
+               memcpy(&m_MHWFilterMask, &mask, sizeof(eDVBSectionFilterMask));
+
+               mask.pid = m_mhw2_channel_pid;
+               mask.data[0] = 0xC8;
+               mask.mask[0] = 0xFF;
+               mask.data[1] = 0;
+               mask.mask[1] = 0xFF;
+               m_MHWReader2->connectRead(slot(*this, &eEPGCache::channel_data::readMHWData2), m_MHWConn2);
+               m_MHWReader2->start(mask);
+               isRunning |= MHW;
+               memcpy(&m_MHWFilterMask2, &mask, sizeof(eDVBSectionFilterMask));
+               mask.data[1] = 0;
+               mask.mask[1] = 0;
+               m_MHWTimeoutet=false;
+       }
+#endif
+#ifdef ENABLE_FREESAT
+       if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::FREESAT_SCHEDULE_OTHER)
+       {
+               mask.pid = 3842;
+               mask.flags = eDVBSectionFilterMask::rfCRC;
+               mask.data[0] = 0x60;
+               mask.mask[0] = 0xFE;
+               m_FreeSatScheduleOtherReader->connectRead(slot(*this, &eEPGCache::channel_data::readFreeSatScheduleOtherData), m_FreeSatScheduleOtherConn);
+               m_FreeSatScheduleOtherReader->start(mask);
+
+               /*
+                * faster pid, available on ITV HD transponder.
+                * We rely on the fact that we have either of the two,
+                * never both. (both readers share the same data callback
+                * and status maps)
+                */
+               mask.pid = 3003;
+               m_FreeSatScheduleOtherReader2->connectRead(slot(*this, &eEPGCache::channel_data::readFreeSatScheduleOtherData), m_FreeSatScheduleOtherConn2);
+               m_FreeSatScheduleOtherReader2->start(mask);
+               isRunning |= FREESAT_SCHEDULE_OTHER;
+       }
 #endif
 #endif
-
        mask.pid = 0x12;
        mask.flags = eDVBSectionFilterMask::rfCRC;
 
        mask.pid = 0x12;
        mask.flags = eDVBSectionFilterMask::rfCRC;
 
-       mask.data[0] = 0x4E;
-       mask.mask[0] = 0xFE;
-       m_NowNextReader->connectRead(slot(*this, &eEPGCache::channel_data::readData), m_NowNextConn);
-       m_NowNextReader->start(mask);
-       isRunning |= NOWNEXT;
+       if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::NOWNEXT)
+       {
+               mask.data[0] = 0x4E;
+               mask.mask[0] = 0xFE;
+               m_NowNextReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::NOWNEXT), m_NowNextConn);
+               m_NowNextReader->start(mask);
+               isRunning |= NOWNEXT;
+       }
+
+       if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::SCHEDULE)
+       {
+               mask.data[0] = 0x50;
+               mask.mask[0] = 0xF0;
+               m_ScheduleReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::SCHEDULE), m_ScheduleConn);
+               m_ScheduleReader->start(mask);
+               isRunning |= SCHEDULE;
+       }
+
+       if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::SCHEDULE_OTHER)
+       {
+               mask.data[0] = 0x60;
+               mask.mask[0] = 0xF0;
+               m_ScheduleOtherReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::SCHEDULE_OTHER), m_ScheduleOtherConn);
+               m_ScheduleOtherReader->start(mask);
+               isRunning |= SCHEDULE_OTHER;
+       }
 
 
-       mask.data[0] = 0x50;
-       mask.mask[0] = 0xF0;
-       m_ScheduleReader->connectRead(slot(*this, &eEPGCache::channel_data::readData), m_ScheduleConn);
-       m_ScheduleReader->start(mask);
-       isRunning |= SCHEDULE;
+#ifdef ENABLE_VIRGIN
+       if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::VIRGIN_NOWNEXT)
+       {
+               mask.pid = 0x2bc;
+               mask.data[0] = 0x4E;
+               mask.mask[0] = 0xFE;
+               m_VirginNowNextReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::VIRGIN_NOWNEXT), m_VirginNowNextConn);
+               m_VirginNowNextReader->start(mask);
+               isRunning |= VIRGIN_NOWNEXT;
+       }
 
 
-       mask.data[0] = 0x60;
-       m_ScheduleOtherReader->connectRead(slot(*this, &eEPGCache::channel_data::readData), m_ScheduleOtherConn);
-       m_ScheduleOtherReader->start(mask);
-       isRunning |= SCHEDULE_OTHER;
+       if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::VIRGIN_SCHEDULE)
+       {
+               mask.pid = 0x2bc;
+               mask.data[0] = 0x50;
+               mask.mask[0] = 0xFE;
+               m_VirginScheduleReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::VIRGIN_SCHEDULE), m_VirginScheduleConn);
+               m_VirginScheduleReader->start(mask);
+               isRunning |= VIRGIN_SCHEDULE;
+       }
+#endif
+#ifdef ENABLE_NETMED
+       if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::NETMED_SCHEDULE)
+       {
+               mask.pid = 0x1388;
+               mask.data[0] = 0x50;
+               mask.mask[0] = 0xF0;
+               m_NetmedScheduleReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::NETMED_SCHEDULE), m_NetmedScheduleConn);
+               m_NetmedScheduleReader->start(mask);
+               isRunning |= NETMED_SCHEDULE;
+       }
 
 
-       mask.pid = 0x39;
+       if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::NETMED_SCHEDULE_OTHER)
+       {
+               mask.pid = 0x1388;
+               mask.data[0] = 0x60;
+               mask.mask[0] = 0xF0;
+               m_NetmedScheduleOtherReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::NETMED_SCHEDULE_OTHER), m_NetmedScheduleOtherConn);
+               m_NetmedScheduleOtherReader->start(mask);
+               isRunning |= NETMED_SCHEDULE_OTHER;
+       }
+#endif
+       if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::VIASAT)
+       {
+               mask.pid = 0x39;
 
 
-       mask.data[0] = 0x40;
-       mask.mask[0] = 0x40;
-       m_ViasatReader->connectRead(slot(*this, &eEPGCache::channel_data::readDataViasat), m_ViasatConn);
-       m_ViasatReader->start(mask);
-       isRunning |= VIASAT;
+               mask.data[0] = 0x40;
+               mask.mask[0] = 0x40;
+               m_ViasatReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::VIASAT), m_ViasatConn);
+               m_ViasatReader->start(mask);
+               isRunning |= VIASAT;
+       }
 
        abortTimer->start(7000,true);
 }
 
        abortTimer->start(7000,true);
 }
@@ -1305,28 +1638,72 @@ void eEPGCache::channel_data::abortNonAvail()
        {
                if ( !(haveData&NOWNEXT) && (isRunning&NOWNEXT) )
                {
        {
                if ( !(haveData&NOWNEXT) && (isRunning&NOWNEXT) )
                {
-                       eDebug("[EPGC] abort non avail nownext reading");
+                       eDebug("[eEPGCache] abort non avail nownext reading");
                        isRunning &= ~NOWNEXT;
                        m_NowNextReader->stop();
                        m_NowNextConn=0;
                }
                if ( !(haveData&SCHEDULE) && (isRunning&SCHEDULE) )
                {
                        isRunning &= ~NOWNEXT;
                        m_NowNextReader->stop();
                        m_NowNextConn=0;
                }
                if ( !(haveData&SCHEDULE) && (isRunning&SCHEDULE) )
                {
-                       eDebug("[EPGC] abort non avail schedule reading");
+                       eDebug("[eEPGCache] abort non avail schedule reading");
                        isRunning &= ~SCHEDULE;
                        m_ScheduleReader->stop();
                        m_ScheduleConn=0;
                }
                if ( !(haveData&SCHEDULE_OTHER) && (isRunning&SCHEDULE_OTHER) )
                {
                        isRunning &= ~SCHEDULE;
                        m_ScheduleReader->stop();
                        m_ScheduleConn=0;
                }
                if ( !(haveData&SCHEDULE_OTHER) && (isRunning&SCHEDULE_OTHER) )
                {
-                       eDebug("[EPGC] abort non avail schedule other reading");
+                       eDebug("[eEPGCache] abort non avail schedule other reading");
                        isRunning &= ~SCHEDULE_OTHER;
                        m_ScheduleOtherReader->stop();
                        m_ScheduleOtherConn=0;
                }
                        isRunning &= ~SCHEDULE_OTHER;
                        m_ScheduleOtherReader->stop();
                        m_ScheduleOtherConn=0;
                }
+#ifdef ENABLE_VIRGIN
+               if ( !(haveData&VIRGIN_NOWNEXT) && (isRunning&VIRGIN_NOWNEXT) )
+               {
+                       eDebug("[eEPGCache] abort non avail virgin nownext reading");
+                       isRunning &= ~VIRGIN_NOWNEXT;
+                       m_VirginNowNextReader->stop();
+                       m_VirginNowNextConn=0;
+               }
+               if ( !(haveData&VIRGIN_SCHEDULE) && (isRunning&VIRGIN_SCHEDULE) )
+               {
+                       eDebug("[eEPGCache] abort non avail virgin schedule reading");
+                       isRunning &= ~VIRGIN_SCHEDULE;
+                       m_VirginScheduleReader->stop();
+                       m_VirginScheduleConn=0;
+               }
+#endif
+#ifdef ENABLE_NETMED
+               if ( !(haveData&NETMED_SCHEDULE) && (isRunning&NETMED_SCHEDULE) )
+               {
+                       eDebug("[eEPGCache] abort non avail netmed schedule reading");
+                       isRunning &= ~NETMED_SCHEDULE;
+                       m_NetmedScheduleReader->stop();
+                       m_NetmedScheduleConn=0;
+               }
+               if ( !(haveData&NETMED_SCHEDULE_OTHER) && (isRunning&NETMED_SCHEDULE_OTHER) )
+               {
+                       eDebug("[eEPGCache] abort non avail netmed schedule other reading");
+                       isRunning &= ~NETMED_SCHEDULE_OTHER;
+                       m_NetmedScheduleOtherReader->stop();
+                       m_NetmedScheduleOtherConn=0;
+               }
+#endif
+#ifdef ENABLE_FREESAT
+               if ( !(haveData&FREESAT_SCHEDULE_OTHER) && (isRunning&FREESAT_SCHEDULE_OTHER) )
+               {
+                       eDebug("[eEPGCache] abort non avail FreeSat schedule_other reading");
+                       isRunning &= ~FREESAT_SCHEDULE_OTHER;
+                       m_FreeSatScheduleOtherReader->stop();
+                       m_FreeSatScheduleOtherReader2->stop();
+                       m_FreeSatScheduleOtherConn=0;
+                       m_FreeSatScheduleOtherConn2=0;
+                       cleanupFreeSat();
+               }
+#endif
                if ( !(haveData&VIASAT) && (isRunning&VIASAT) )
                {
                if ( !(haveData&VIASAT) && (isRunning&VIASAT) )
                {
-                       eDebug("[EPGC] abort non avail viasat reading");
+                       eDebug("[eEPGCache] abort non avail viasat reading");
                        isRunning &= ~VIASAT;
                        m_ViasatReader->stop();
                        m_ViasatConn=0;
                        isRunning &= ~VIASAT;
                        m_ViasatReader->stop();
                        m_ViasatConn=0;
@@ -1334,7 +1711,7 @@ void eEPGCache::channel_data::abortNonAvail()
 #ifdef ENABLE_MHW_EPG
                if ( !(haveData&MHW) && (isRunning&MHW) )
                {
 #ifdef ENABLE_MHW_EPG
                if ( !(haveData&MHW) && (isRunning&MHW) )
                {
-                       eDebug("[EPGC] abort non avail mhw reading");
+                       eDebug("[eEPGCache] abort non avail mhw reading");
                        isRunning &= ~MHW;
                        m_MHWReader->stop();
                        m_MHWConn=0;
                        isRunning &= ~MHW;
                        m_MHWReader->stop();
                        m_MHWConn=0;
@@ -1354,6 +1731,12 @@ void eEPGCache::channel_data::abortNonAvail()
                                seenSections[i].clear();
                                calcedSections[i].clear();
                        }
                                seenSections[i].clear();
                                calcedSections[i].clear();
                        }
+#ifdef ENABLE_MHW_EPG
+                       cleanupMHW();
+#endif
+#ifdef ENABLE_FREESAT
+                       cleanupFreeSat();
+#endif
                }
        }
        ++state;
                }
        }
        ++state;
@@ -1371,9 +1754,9 @@ void eEPGCache::channel_data::startChannel()
 
        zapTimer->start(update, 1);
        if (update >= 60000)
 
        zapTimer->start(update, 1);
        if (update >= 60000)
-               eDebug("[EPGC] next update in %i min", update/60000);
+               eDebug("[eEPGCache] next update in %i min", update/60000);
        else if (update >= 1000)
        else if (update >= 1000)
-               eDebug("[EPGC] next update in %i sec", update/1000);
+               eDebug("[eEPGCache] next update in %i sec", update/1000);
 }
 
 void eEPGCache::channel_data::abortEPG()
 }
 
 void eEPGCache::channel_data::abortEPG()
@@ -1383,11 +1766,17 @@ void eEPGCache::channel_data::abortEPG()
                seenSections[i].clear();
                calcedSections[i].clear();
        }
                seenSections[i].clear();
                calcedSections[i].clear();
        }
+#ifdef ENABLE_MHW_EPG
+       cleanupMHW();
+#endif
+#ifdef ENABLE_FREESAT
+       cleanupFreeSat();
+#endif
        abortTimer->stop();
        zapTimer->stop();
        if (isRunning)
        {
        abortTimer->stop();
        zapTimer->stop();
        if (isRunning)
        {
-               eDebug("[EPGC] abort caching events !!");
+               eDebug("[eEPGCache] abort caching events !!");
                if (isRunning & SCHEDULE)
                {
                        isRunning &= ~SCHEDULE;
                if (isRunning & SCHEDULE)
                {
                        isRunning &= ~SCHEDULE;
@@ -1406,6 +1795,44 @@ void eEPGCache::channel_data::abortEPG()
                        m_ScheduleOtherReader->stop();
                        m_ScheduleOtherConn=0;
                }
                        m_ScheduleOtherReader->stop();
                        m_ScheduleOtherConn=0;
                }
+#ifdef ENABLE_VIRGIN
+               if (isRunning & VIRGIN_NOWNEXT)
+               {
+                       isRunning &= ~VIRGIN_NOWNEXT;
+                       m_VirginNowNextReader->stop();
+                       m_VirginNowNextConn=0;
+               }
+               if (isRunning & VIRGIN_SCHEDULE)
+               {
+                       isRunning &= ~VIRGIN_SCHEDULE;
+                       m_VirginScheduleReader->stop();
+                       m_VirginScheduleConn=0;
+               }
+#endif
+#ifdef ENABLE_NETMED
+               if (isRunning & NETMED_SCHEDULE)
+               {
+                       isRunning &= ~NETMED_SCHEDULE;
+                       m_NetmedScheduleReader->stop();
+                       m_NetmedScheduleConn=0;
+               }
+               if (isRunning & NETMED_SCHEDULE_OTHER)
+               {
+                       isRunning &= ~NETMED_SCHEDULE_OTHER;
+                       m_NetmedScheduleOtherReader->stop();
+                       m_NetmedScheduleOtherConn=0;
+               }
+#endif
+#ifdef ENABLE_FREESAT
+               if (isRunning & FREESAT_SCHEDULE_OTHER)
+               {
+                       isRunning &= ~FREESAT_SCHEDULE_OTHER;
+                       m_FreeSatScheduleOtherReader->stop();
+                       m_FreeSatScheduleOtherReader2->stop();
+                       m_FreeSatScheduleOtherConn=0;
+                       m_FreeSatScheduleOtherConn2=0;
+               }
+#endif
                if (isRunning & VIASAT)
                {
                        isRunning &= ~VIASAT;
                if (isRunning & VIASAT)
                {
                        isRunning &= ~VIASAT;
@@ -1432,52 +1859,57 @@ void eEPGCache::channel_data::abortEPG()
        pthread_mutex_unlock(&channel_active);
 }
 
        pthread_mutex_unlock(&channel_active);
 }
 
-
-void eEPGCache::channel_data::readDataViasat( const __u8 *data)
-{
-       __u8 *d=0;
-       memcpy(&d, &data, sizeof(__u8*));
-       d[0] |= 0x80;
-       readData(data);
-}
-
-void eEPGCache::channel_data::readData( const __u8 *data)
+void eEPGCache::channel_data::readData( const uint8_t *data, int source)
 {
 {
-       int source;
        int map;
        int map;
-       iDVBSectionReader *reader=NULL;
-       switch(data[0])
+       iDVBSectionReader *reader = NULL;
+       switch (source)
        {
        {
-               case 0x4E ... 0x4F:
-                       reader=m_NowNextReader;
-                       source=NOWNEXT;
-                       map=0;
+               case NOWNEXT:
+                       reader = m_NowNextReader;
+                       map = 0;
+                       break;
+               case SCHEDULE:
+                       reader = m_ScheduleReader;
+                       map = 1;
+                       break;
+               case SCHEDULE_OTHER:
+                       reader = m_ScheduleOtherReader;
+                       map = 2;
+                       break;
+               case VIASAT:
+                       reader = m_ViasatReader;
+                       map = 3;
                        break;
                        break;
-               case 0x50 ... 0x5F:
-                       reader=m_ScheduleReader;
-                       source=SCHEDULE;
-                       map=1;
+#ifdef ENABLE_NETMED
+               case NETMED_SCHEDULE:
+                       reader = m_NetmedScheduleReader;
+                       map = 1;
                        break;
                        break;
-               case 0x60 ... 0x6F:
-                       reader=m_ScheduleOtherReader;
-                       source=SCHEDULE_OTHER;
-                       map=2;
+               case NETMED_SCHEDULE_OTHER:
+                       reader = m_NetmedScheduleOtherReader;
+                       map = 2;
                        break;
                        break;
-               case 0xD0 ... 0xDF:
-               case 0xE0 ... 0xEF:
-                       reader=m_ViasatReader;
-                       source=VIASAT;
-                       map=3;
+#endif
+#ifdef ENABLE_VIRGIN
+               case VIRGIN_NOWNEXT:
+                       reader = m_VirginNowNextReader;
+                       map = 0;
+                       break;
+               case VIRGIN_SCHEDULE:
+                       reader = m_VirginScheduleReader;
+                       map = 1;
                        break;
                        break;
+#endif
                default:
                default:
-                       eDebug("[EPGC] unknown table_id !!!");
+                       eDebug("[eEPGCache] unknown source");
                        return;
        }
        tidMap &seenSections = this->seenSections[map];
        tidMap &calcedSections = this->calcedSections[map];
        if ( (state == 1 && calcedSections == seenSections) || state > 1 )
        {
                        return;
        }
        tidMap &seenSections = this->seenSections[map];
        tidMap &calcedSections = this->calcedSections[map];
        if ( (state == 1 && calcedSections == seenSections) || state > 1 )
        {
-               eDebugNoNewLine("[EPGC] ");
+               eDebugNoNewLine("[eEPGCache] ");
                switch (source)
                {
                        case NOWNEXT:
                switch (source)
                {
                        case NOWNEXT:
@@ -1496,9 +1928,29 @@ void eEPGCache::channel_data::readData( const __u8 *data)
                                m_ViasatConn=0;
                                eDebugNoNewLine("viasat");
                                break;
                                m_ViasatConn=0;
                                eDebugNoNewLine("viasat");
                                break;
+#ifdef ENABLE_NETMED
+                       case NETMED_SCHEDULE:
+                               m_NetmedScheduleConn=0;
+                               eDebugNoNewLine("netmed schedule");
+                               break;
+                       case NETMED_SCHEDULE_OTHER:
+                               m_NetmedScheduleOtherConn=0;
+                               eDebugNoNewLine("netmed schedule other");
+                               break;
+#endif
+#ifdef ENABLE_VIRGIN
+                       case VIRGIN_NOWNEXT:
+                               m_VirginNowNextConn=0;
+                               eDebugNoNewLine("virgin nownext");
+                               break;
+                       case VIRGIN_SCHEDULE:
+                               m_VirginScheduleConn=0;
+                               eDebugNoNewLine("virgin schedule");
+                               break;
+#endif
                        default: eDebugNoNewLine("unknown");break;
                }
                        default: eDebugNoNewLine("unknown");break;
                }
-               eDebug(" finished(%ld)", ::time(0));
+               eDebugNoNewLine(" finished(%ld)\n", ::time(0));
                if ( reader )
                        reader->stop();
                isRunning &= ~source;
                if ( reader )
                        reader->stop();
                isRunning &= ~source;
@@ -1508,7 +1960,7 @@ void eEPGCache::channel_data::readData( const __u8 *data)
        else
        {
                eit_t *eit = (eit_t*) data;
        else
        {
                eit_t *eit = (eit_t*) data;
-               __u32 sectionNo = data[0] << 24;
+               uint32_t sectionNo = data[0] << 24;
                sectionNo |= data[3] << 16;
                sectionNo |= data[4] << 8;
                sectionNo |= eit->section_number;
                sectionNo |= data[3] << 16;
                sectionNo |= data[4] << 8;
                sectionNo |= eit->section_number;
@@ -1520,44 +1972,165 @@ void eEPGCache::channel_data::readData( const __u8 *data)
                {
                        seenSections.insert(sectionNo);
                        calcedSections.insert(sectionNo);
                {
                        seenSections.insert(sectionNo);
                        calcedSections.insert(sectionNo);
-                       __u32 tmpval = sectionNo & 0xFFFFFF00;
-                       __u8 incr = source == NOWNEXT ? 1 : 8;
+                       uint32_t tmpval = sectionNo & 0xFFFFFF00;
+                       uint8_t incr = source == NOWNEXT ? 1 : 8;
                        for ( int i = 0; i <= eit->last_section_number; i+=incr )
                        {
                                if ( i == eit->section_number )
                                {
                                        for (int x=i; x <= eit->segment_last_section_number; ++x)
                        for ( int i = 0; i <= eit->last_section_number; i+=incr )
                        {
                                if ( i == eit->section_number )
                                {
                                        for (int x=i; x <= eit->segment_last_section_number; ++x)
+                                       {
                                                calcedSections.insert(tmpval|(x&0xFF));
                                                calcedSections.insert(tmpval|(x&0xFF));
+                                       }
                                }
                                else
                                }
                                else
+                               {
                                        calcedSections.insert(tmpval|(i&0xFF));
                                        calcedSections.insert(tmpval|(i&0xFF));
+                               }
                        }
                        cache->sectionRead(data, source, this);
                }
        }
 }
 
                        }
                        cache->sectionRead(data, source, this);
                }
        }
 }
 
-RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, const eventData *&result, int direction)
-// if t == -1 we search the current event...
+#if ENABLE_FREESAT
+
+freesatEITSubtableStatus::freesatEITSubtableStatus(u_char version, uint8_t maxSection) : version(version)
 {
 {
-       singleLock s(cache_lock);
-       uniqueEPGKey key(handleGroup(service));
+       initMap(maxSection);
+}
 
 
-       // check if EPG for this service is ready...
+void freesatEITSubtableStatus::initMap(uint8_t maxSection)
+{
+       int i, maxSectionIdx = maxSection / 8;
+       for (i = 0; i < 32; i++)
+       {
+               sectionMap[i] = (i <= maxSectionIdx ? 0x0100 : 0x0000 );
+       }
+}
+
+bool freesatEITSubtableStatus::isSectionPresent(uint8_t sectionNo)
+{
+       uint8_t sectionIdx = sectionNo / 8;
+       uint8_t bitOffset = sectionNo % 8;
+
+       return ((sectionMap[sectionIdx] & (1 << bitOffset)) != 0);
+}
+
+bool freesatEITSubtableStatus::isCompleted()
+{
+       uint32_t i = 0;
+       uint8_t calc;
+
+       while ( i < 32 )
+       {
+               calc = sectionMap[i] >> 8;
+               if (! calc) return true; // Last segment passed
+               if (calc ^ ( sectionMap[i] & 0xFF ) ) // Segment not fully found
+                       return false;
+               i++;
+       }
+       return true; // All segments ok
+}
+
+void freesatEITSubtableStatus::seen(uint8_t sectionNo, uint8_t maxSegmentSection)
+{
+       uint8_t sectionIdx = sectionNo / 8;
+       uint8_t bitOffset = sectionNo % 8;
+       uint8_t maxBitOffset = maxSegmentSection % 8;
+
+       sectionMap[sectionIdx] &= 0x00FF; // Clear calc map
+       sectionMap[sectionIdx] |= ((0x01FF << maxBitOffset) & 0xFF00); // Set calc map
+       sectionMap[sectionIdx] |= (1 << bitOffset); // Set seen map
+}
+
+bool freesatEITSubtableStatus::isVersionChanged(u_char testVersion)
+{
+       return version != testVersion;
+}
+
+void freesatEITSubtableStatus::updateVersion(u_char newVersion, uint8_t maxSection)
+{
+       version = newVersion;
+       initMap(maxSection);
+}
+
+void eEPGCache::channel_data::cleanupFreeSat()
+{
+       m_FreeSatSubTableStatus.clear();
+       m_FreesatTablesToComplete = 0;
+}
+
+void eEPGCache::channel_data::readFreeSatScheduleOtherData( const uint8_t *data)
+{
+       eit_t *eit = (eit_t*) data;
+       uint32_t subtableNo = data[0] << 24; // Table ID
+       subtableNo |= data[3] << 16; // Service ID Hi
+       subtableNo |= data[4] << 8; // Service ID Lo
+
+       // Check for sub-table version in map
+       std::map<uint32_t, freesatEITSubtableStatus> &freeSatSubTableStatus = this->m_FreeSatSubTableStatus;
+       std::map<uint32_t, freesatEITSubtableStatus>::iterator itmap = freeSatSubTableStatus.find(subtableNo);
+
+       freesatEITSubtableStatus *fsstatus;
+       if ( itmap == freeSatSubTableStatus.end() )
+       {
+               // New sub table. Store version.
+               //eDebug("[eEPGCache] New subtable (%x) version (%d) now/next (%d) tsid (%x/%x) onid (%x/%x)", subtableNo, eit->version_number, eit->current_next_indicator, eit->transport_stream_id_hi, eit->transport_stream_id_lo, eit->original_network_id_hi, eit->original_network_id_lo);
+               fsstatus = new freesatEITSubtableStatus(eit->version_number, eit->last_section_number);
+               m_FreesatTablesToComplete++;
+               freeSatSubTableStatus.insert(std::pair<uint32_t,freesatEITSubtableStatus>(subtableNo, *fsstatus));
+       }
+       else
+       {
+               fsstatus = &itmap->second;
+               // Existing subtable. Check version. Should check current / next as well? Seems to always be current for Freesat
+               if ( fsstatus->isVersionChanged(eit->version_number) )
+               {
+                       eDebug("[eEPGCache] FS subtable (%x) version changed (%d) now/next (%d)", subtableNo, eit->version_number, eit->current_next_indicator);
+                       m_FreesatTablesToComplete++;
+                       fsstatus->updateVersion(eit->version_number, eit->last_section_number);
+               }
+               else
+               {
+                       if ( fsstatus->isSectionPresent(eit->section_number) )
+                       {
+//                             eDebug("[eEPGCache] DUP FS sub/sec/ver (%x/%d/%d)", subtableNo, eit->section_number, eit->version_number);
+                               return;
+                       }
+               }
+       }
+
+//     eDebug("[eEPGCache] New FS sub/sec/ls/lss/ver (%x/%d/%d/%d/%d)", subtableNo, eit->section_number, eit->last_section_number, eit->segment_last_section_number, eit->version_number);
+       fsstatus->seen(eit->section_number, eit->segment_last_section_number);
+       if (fsstatus->isCompleted())
+       {
+               m_FreesatTablesToComplete--;
+       }
+       cache->sectionRead(data, FREESAT_SCHEDULE_OTHER, this);
+}
+#endif
+
+RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, const eventData *&result, int direction)
+// if t == -1 we search the current event...
+{
+       uniqueEPGKey key(handleGroup(service));
+
+       // check if EPG for this service is ready...
        eventCache::iterator It = eventDB.find( key );
        eventCache::iterator It = eventDB.find( key );
-       if ( It != eventDB.end() && !It->second.first.empty() ) // entrys cached ?
+       if ( It != eventDB.end() && !It->second.byEvent.empty() ) // entrys cached ?
        {
                if (t==-1)
                        t = ::time(0);
        {
                if (t==-1)
                        t = ::time(0);
-               timeMap::iterator i = direction <= 0 ? It->second.second.lower_bound(t) :  // find > or equal
-                       It->second.second.upper_bound(t); // just >
-               if ( i != It->second.second.end() )
+               timeMap::iterator i = direction <= 0 ? It->second.byTime.lower_bound(t) :  // find > or equal
+                       It->second.byTime.upper_bound(t); // just >
+               if ( i != It->second.byTime.end() )
                {
                        if ( direction < 0 || (direction == 0 && i->first > t) )
                        {
                                timeMap::iterator x = i;
                                --x;
                {
                        if ( direction < 0 || (direction == 0 && i->first > t) )
                        {
                                timeMap::iterator x = i;
                                --x;
-                               if ( x != It->second.second.end() )
+                               if ( x != It->second.byTime.end() )
                                {
                                        time_t start_time = x->first;
                                        if (direction >= 0)
                                {
                                        time_t start_time = x->first;
                                        if (direction >= 0)
@@ -1579,16 +2152,6 @@ RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, co
        return -1;
 }
 
        return -1;
 }
 
-RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, const eit_event_struct *&result, int direction)
-{
-       singleLock s(cache_lock);
-       const eventData *data=0;
-       RESULT ret = lookupEventTime(service, t, data, direction);
-       if ( !ret && data )
-               result = data->get();
-       return ret;
-}
-
 RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, Event *& result, int direction)
 {
        singleLock s(cache_lock);
 RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, Event *& result, int direction)
 {
        singleLock s(cache_lock);
@@ -1604,6 +2167,7 @@ RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, eP
        singleLock s(cache_lock);
        const eventData *data=0;
        RESULT ret = lookupEventTime(service, t, data, direction);
        singleLock s(cache_lock);
        const eventData *data=0;
        RESULT ret = lookupEventTime(service, t, data, direction);
+       result = NULL;
        if ( !ret && data )
        {
                Event ev((uint8_t*)data->get());
        if ( !ret && data )
        {
                Event ev((uint8_t*)data->get());
@@ -1616,14 +2180,13 @@ RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, eP
 
 RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, const eventData *&result )
 {
 
 RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, const eventData *&result )
 {
-       singleLock s(cache_lock);
        uniqueEPGKey key(handleGroup(service));
 
        uniqueEPGKey key(handleGroup(service));
 
-       eventCache::iterator It = eventDB.find( key );
-       if ( It != eventDB.end() && !It->second.first.empty() ) // entrys cached?
+       eventCache::iterator It = eventDB.find(key);
+       if (It != eventDB.end())
        {
        {
-               eventMap::iterator i( It->second.first.find( event_id ));
-               if ( i != It->second.first.end() )
+               eventMap::iterator i = It->second.byEvent.find(event_id);
+               if ( i != It->second.byEvent.end() )
                {
                        result = i->second;
                        return 0;
                {
                        result = i->second;
                        return 0;
@@ -1631,19 +2194,48 @@ RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id,
                else
                {
                        result = 0;
                else
                {
                        result = 0;
-                       eDebug("[EPGC] event %04x not found in epgcache", event_id);
+                       eDebug("[eEPGCache] event %04x not found in epgcache", event_id);
                }
        }
        return -1;
 }
 
                }
        }
        return -1;
 }
 
-RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, const eit_event_struct *&result)
+RESULT eEPGCache::saveEventToFile(const char* filename, const eServiceReference &service, int eit_event_id, time_t begTime, time_t endTime)
 {
 {
+       RESULT ret = -1;
        singleLock s(cache_lock);
        singleLock s(cache_lock);
-       const eventData *data=0;
-       RESULT ret = lookupEventId(service, event_id, data);
-       if ( !ret && data )
-               result = data->get();
+       const eventData *data = NULL;
+       if ( eit_event_id != -1 )
+       {
+               eDebug("[eEPGCache] %s epg event id %x", __func__, eit_event_id);
+               ret = lookupEventId(service, eit_event_id, data);
+       }
+       if ( (ret != 0) && (begTime != -1) )
+       {
+               time_t queryTime = begTime;
+               if (endTime != -1)
+                       queryTime += (endTime - begTime) / 2;
+               ret = lookupEventTime(service, queryTime, data);
+       }
+       if (ret == 0)
+       {
+               int fd = open(filename, O_CREAT|O_WRONLY, 0666);
+               if (fd < 0)
+               {
+                       eDebug("[eEPGCache] Failed to create file: %s", filename);
+                       return fd;
+               }
+               const eit_event_struct *event = data->get();
+               int evLen = event->getDescriptorsLoopLength() + 12/*EIT_LOOP_SIZE*/;
+               int wr = ::write( fd, event, evLen );
+               ::close(fd);
+               if ( wr != evLen )
+               {
+                       ::unlink(filename); /* Remove faulty file */
+                       eDebug("[eEPGCache] eit write error on %s: %m", filename);
+                       ret = (wr < 0) ? wr : -1;
+               }
+       }
        return ret;
 }
 
        return ret;
 }
 
@@ -1662,6 +2254,7 @@ RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id,
        singleLock s(cache_lock);
        const eventData *data=0;
        RESULT ret = lookupEventId(service, event_id, data);
        singleLock s(cache_lock);
        const eventData *data=0;
        RESULT ret = lookupEventId(service, event_id, data);
+       result = NULL;
        if ( !ret && data )
        {
                Event ev((uint8_t*)data->get());
        if ( !ret && data )
        {
                Event ev((uint8_t*)data->get());
@@ -1679,16 +2272,16 @@ RESULT eEPGCache::startTimeQuery(const eServiceReference &service, time_t begin,
        if (begin == -1)
                begin = ::time(0);
        eventCache::iterator It = eventDB.find(ref);
        if (begin == -1)
                begin = ::time(0);
        eventCache::iterator It = eventDB.find(ref);
-       if ( It != eventDB.end() && It->second.second.size() )
+       if ( It != eventDB.end() && !It->second.byTime.empty() )
        {
        {
-               m_timemap_cursor = It->second.second.lower_bound(begin);
-               if ( m_timemap_cursor != It->second.second.end() )
+               m_timemap_cursor = It->second.byTime.lower_bound(begin);
+               if ( m_timemap_cursor != It->second.byTime.end() )
                {
                        if ( m_timemap_cursor->first != begin )
                        {
                                timeMap::iterator x = m_timemap_cursor;
                                --x;
                {
                        if ( m_timemap_cursor->first != begin )
                        {
                                timeMap::iterator x = m_timemap_cursor;
                                --x;
-                               if ( x != It->second.second.end() )
+                               if ( x != It->second.byTime.end() )
                                {
                                        time_t start_time = x->first;
                                        if ( begin > start_time && begin < (start_time+x->second->getDuration()))
                                {
                                        time_t start_time = x->first;
                                        if ( begin > start_time && begin < (start_time+x->second->getDuration()))
@@ -1698,9 +2291,9 @@ RESULT eEPGCache::startTimeQuery(const eServiceReference &service, time_t begin,
                }
 
                if (minutes != -1)
                }
 
                if (minutes != -1)
-                       m_timemap_end = It->second.second.lower_bound(begin+minutes*60);
+                       m_timemap_end = It->second.byTime.lower_bound(begin+minutes*60);
                else
                else
-                       m_timemap_end = It->second.second.end();
+                       m_timemap_end = It->second.byTime.end();
 
                currentQueryTsidOnid = (ref.getTransportStreamID().get()<<16) | ref.getOriginalNetworkID().get();
                return m_timemap_cursor == m_timemap_end ? -1 : 0;
 
                currentQueryTsidOnid = (ref.getTransportStreamID().get()<<16) | ref.getOriginalNetworkID().get();
                return m_timemap_cursor == m_timemap_end ? -1 : 0;
@@ -1708,26 +2301,6 @@ RESULT eEPGCache::startTimeQuery(const eServiceReference &service, time_t begin,
        return -1;
 }
 
        return -1;
 }
 
-RESULT eEPGCache::getNextTimeEntry(const eventData *& result)
-{
-       if ( m_timemap_cursor != m_timemap_end )
-       {
-               result = m_timemap_cursor++->second;
-               return 0;
-       }
-       return -1;
-}
-
-RESULT eEPGCache::getNextTimeEntry(const eit_event_struct *&result)
-{
-       if ( m_timemap_cursor != m_timemap_end )
-       {
-               result = m_timemap_cursor++->second->get();
-               return 0;
-       }
-       return -1;
-}
-
 RESULT eEPGCache::getNextTimeEntry(Event *&result)
 {
        if ( m_timemap_cursor != m_timemap_end )
 RESULT eEPGCache::getNextTimeEntry(Event *&result)
 {
        if ( m_timemap_cursor != m_timemap_end )
@@ -1749,8 +2322,9 @@ RESULT eEPGCache::getNextTimeEntry(ePtr<eServiceEvent> &result)
        return -1;
 }
 
        return -1;
 }
 
-void fillTuple(ePyObject tuple, const char *argstring, int argcount, ePyObject service, eServiceEvent *ptr, ePyObject nowTime, ePyObject service_name )
+void fillTuple(ePyObject tuple, const char *argstring, int argcount, ePyObject service_reference, eServiceEvent *ptr, ePyObject service_name, ePyObject nowTime, eventData *evData )
 {
 {
+       //eDebug("[eEPGCache] fillTuple arg=%s argcnt=%d, ptr=%d evData=%d", argstring, argcount, ptr ? 1 : 0, evData ? 1 : 0);
        ePyObject tmp;
        int spos=0, tpos=0;
        char c;
        ePyObject tmp;
        int spos=0, tpos=0;
        char c;
@@ -1763,13 +2337,13 @@ void fillTuple(ePyObject tuple, const char *argstring, int argcount, ePyObject s
                                tmp = PyLong_FromLong(0);
                                break;
                        case 'I': // Event Id
                                tmp = PyLong_FromLong(0);
                                break;
                        case 'I': // Event Id
-                               tmp = ptr ? PyLong_FromLong(ptr->getEventId()) : ePyObject();
+                               tmp = evData ? PyLong_FromLong(evData->getEventID()) : (ptr ? PyLong_FromLong(ptr->getEventId()) : ePyObject());
                                break;
                        case 'B': // Event Begin Time
                                break;
                        case 'B': // Event Begin Time
-                               tmp = ptr ? PyLong_FromLong(ptr->getBeginTime()) : ePyObject();
+                               tmp = ptr ? PyLong_FromLong(ptr->getBeginTime()) : (evData ? PyLong_FromLong(evData->getStartTime()) : ePyObject());
                                break;
                        case 'D': // Event Duration
                                break;
                        case 'D': // Event Duration
-                               tmp = ptr ? PyLong_FromLong(ptr->getDuration()) : ePyObject();
+                               tmp = ptr ? PyLong_FromLong(ptr->getDuration()) : (evData ? PyLong_FromLong(evData->getDuration()) : ePyObject());
                                break;
                        case 'T': // Event Title
                                tmp = ptr ? PyString_FromString(ptr->getEventName().c_str()) : ePyObject();
                                break;
                        case 'T': // Event Title
                                tmp = ptr ? PyString_FromString(ptr->getEventName().c_str()) : ePyObject();
@@ -1780,12 +2354,18 @@ void fillTuple(ePyObject tuple, const char *argstring, int argcount, ePyObject s
                        case 'E': // Event Extended Description
                                tmp = ptr ? PyString_FromString(ptr->getExtendedDescription().c_str()) : ePyObject();
                                break;
                        case 'E': // Event Extended Description
                                tmp = ptr ? PyString_FromString(ptr->getExtendedDescription().c_str()) : ePyObject();
                                break;
+                       case 'P': // Event Parental Rating
+                               tmp = ptr ? ePyObject(ptr->getParentalData()) : ePyObject();
+                               break;
+                       case 'W': // Event Content Description
+                               tmp = ptr ? ePyObject(ptr->getGenreData()) : ePyObject();
+                               break;
                        case 'C': // Current Time
                                tmp = nowTime;
                                inc_refcount = true;
                                break;
                        case 'R': // service reference string
                        case 'C': // Current Time
                                tmp = nowTime;
                                inc_refcount = true;
                                break;
                        case 'R': // service reference string
-                               tmp = service;
+                               tmp = service_reference;
                                inc_refcount = true;
                                break;
                        case 'n': // short service name
                                inc_refcount = true;
                                break;
                        case 'n': // short service name
@@ -1798,7 +2378,7 @@ void fillTuple(ePyObject tuple, const char *argstring, int argcount, ePyObject s
                                continue;
                        default:  // ignore unknown
                                tmp = ePyObject();
                                continue;
                        default:  // ignore unknown
                                tmp = ePyObject();
-                               eDebug("fillTuple unknown '%c'... insert 'None' in result", c);
+                               eDebug("[eEPGCache] fillTuple unknown '%c'... insert 'None' in result", c);
                }
                if (!tmp)
                {
                }
                if (!tmp)
                {
@@ -1815,7 +2395,7 @@ int handleEvent(eServiceEvent *ptr, ePyObject dest_list, const char* argstring,
 {
        if (convertFunc)
        {
 {
        if (convertFunc)
        {
-               fillTuple(convertFuncArgs, argstring, argcount, service, ptr, nowTime, service_name);
+               fillTuple(convertFuncArgs, argstring, argcount, service, ptr, service_name, nowTime, 0);
                ePyObject result = PyObject_CallObject(convertFunc, convertFuncArgs);
                if (!result)
                {
                ePyObject result = PyObject_CallObject(convertFunc, convertFuncArgs);
                if (!result)
                {
@@ -1827,7 +2407,7 @@ int handleEvent(eServiceEvent *ptr, ePyObject dest_list, const char* argstring,
                        Py_DECREF(dest_list);
                        PyErr_SetString(PyExc_StandardError,
                                "error in convertFunc execute");
                        Py_DECREF(dest_list);
                        PyErr_SetString(PyExc_StandardError,
                                "error in convertFunc execute");
-                       eDebug("error in convertFunc execute");
+                       eDebug("[eEPGCache] handleEvent: error in convertFunc execute");
                        return -1;
                }
                PyList_Append(dest_list, result);
                        return -1;
                }
                PyList_Append(dest_list, result);
@@ -1836,7 +2416,7 @@ int handleEvent(eServiceEvent *ptr, ePyObject dest_list, const char* argstring,
        else
        {
                ePyObject tuple = PyTuple_New(argcount);
        else
        {
                ePyObject tuple = PyTuple_New(argcount);
-               fillTuple(tuple, argstring, argcount, service, ptr, nowTime, service_name);
+               fillTuple(tuple, argstring, argcount, service, ptr, service_name, nowTime, 0);
                PyList_Append(dest_list, tuple);
                Py_DECREF(tuple);
        }
                PyList_Append(dest_list, tuple);
                Py_DECREF(tuple);
        }
@@ -1852,6 +2432,8 @@ int handleEvent(eServiceEvent *ptr, ePyObject dest_list, const char* argstring,
 //   T = Event Title
 //   S = Event Short Description
 //   E = Event Extended Description
 //   T = Event Title
 //   S = Event Short Description
 //   E = Event Extended Description
+//   P = Event Parental Rating
+//   W = Event Content Description ('W'hat)
 //   C = Current Time
 //   R = Service Reference
 //   N = Service Name
 //   C = Current Time
 //   R = Service Reference
 //   N = Service Name
@@ -1880,7 +2462,7 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc)
        {
                PyErr_SetString(PyExc_StandardError,
                        "type error");
        {
                PyErr_SetString(PyExc_StandardError,
                        "type error");
-               eDebug("no list");
+               eDebug("[eEPGCache] no list");
                return NULL;
        }
        int listIt=0;
                return NULL;
        }
        int listIt=0;
@@ -1888,11 +2470,11 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc)
        if (!listSize)
        {
                PyErr_SetString(PyExc_StandardError,
        if (!listSize)
        {
                PyErr_SetString(PyExc_StandardError,
-                       "not params given");
-               eDebug("not params given");
+                       "no params given");
+               eDebug("[eEPGCache] no params given");
                return NULL;
        }
                return NULL;
        }
-       else 
+       else
        {
                ePyObject argv=PyList_GET_ITEM(list, 0); // borrowed reference!
                if (PyString_Check(argv))
        {
                ePyObject argv=PyList_GET_ITEM(list, 0); // borrowed reference!
                if (PyString_Check(argv))
@@ -1903,7 +2485,7 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc)
                else
                        argstring = "I"; // just event id as default
                argcount = strlen(argstring);
                else
                        argstring = "I"; // just event id as default
                argcount = strlen(argstring);
-//             eDebug("have %d args('%s')", argcount, argstring);
+//             eDebug("[eEPGCache] have %d args('%s')", argcount, argstring);
        }
 
        bool forceReturnOne = strchr(argstring, 'X') ? true : false;
        }
 
        bool forceReturnOne = strchr(argstring, 'X') ? true : false;
@@ -1916,7 +2498,7 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc)
                {
                        PyErr_SetString(PyExc_StandardError,
                                "convertFunc must be callable");
                {
                        PyErr_SetString(PyExc_StandardError,
                                "convertFunc must be callable");
-                       eDebug("convertFunc is not callable");
+                       eDebug("[eEPGCache] convertFunc is not callable");
                        return NULL;
                }
                convertFuncArgs = PyTuple_New(argcount);
                        return NULL;
                }
                convertFuncArgs = PyTuple_New(argcount);
@@ -1952,7 +2534,7 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc)
                                        {
                                                if (!PyString_Check(entry))
                                                {
                                        {
                                                if (!PyString_Check(entry))
                                                {
-                                                       eDebug("tuple entry 0 is no a string");
+                                                       eDebug("[eEPGCache] tuple entry 0 is no a string");
                                                        goto skip_entry;
                                                }
                                                service = entry;
                                                        goto skip_entry;
                                                }
                                                service = entry;
@@ -1962,7 +2544,7 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc)
                                                type=PyInt_AsLong(entry);
                                                if (type < -1 || type > 2)
                                                {
                                                type=PyInt_AsLong(entry);
                                                if (type < -1 || type > 2)
                                                {
-                                                       eDebug("unknown type %d", type);
+                                                       eDebug("[eEPGCache] unknown type %d", type);
                                                        goto skip_entry;
                                                }
                                                break;
                                                        goto skip_entry;
                                                }
                                                break;
@@ -1973,7 +2555,7 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc)
                                                minutes=PyInt_AsLong(entry);
                                                break;
                                        default:
                                                minutes=PyInt_AsLong(entry);
                                                break;
                                        default:
-                                               eDebug("unneeded extra argument");
+                                               eDebug("[eEPGCache] unneeded extra argument");
                                                break;
                                }
                        }
                                                break;
                                }
                        }
@@ -1982,12 +2564,6 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc)
                                stime = ::time(0);
 
                        eServiceReference ref(handleGroup(eServiceReference(PyString_AS_STRING(service))));
                                stime = ::time(0);
 
                        eServiceReference ref(handleGroup(eServiceReference(PyString_AS_STRING(service))));
-                       if (ref.type != eServiceReference::idDVB)
-                       {
-                               eDebug("service reference for epg query is not valid");
-                               continue;
-                       }
-
                        // redirect subservice querys to parent service
                        eServiceReferenceDVB &dvb_ref = (eServiceReferenceDVB&)ref;
                        if (dvb_ref.getParentTransportStreamID().get()) // linkage subservice
                        // redirect subservice querys to parent service
                        eServiceReferenceDVB &dvb_ref = (eServiceReferenceDVB&)ref;
                        if (dvb_ref.getParentTransportStreamID().get()) // linkage subservice
@@ -2096,63 +2672,302 @@ skip_entry:
        return dest_list;
 }
 
        return dest_list;
 }
 
-void fillTuple2(ePyObject tuple, const char *argstring, int argcount, eventData *evData, eServiceEvent *ptr, ePyObject service_name, ePyObject service_reference)
+static void fill_eit_start(eit_event_struct *evt, time_t t)
 {
 {
-       ePyObject tmp;
-       int pos=0;
-       while(pos < argcount)
+    tm *time = gmtime(&t);
+
+    int l = 0;
+    int month = time->tm_mon + 1;
+    if (month == 1 || month == 2)
+        l = 1;
+    int mjd = 14956 + time->tm_mday + (int)((time->tm_year - l) * 365.25) + (int)((month + 1 + l*12) * 30.6001);
+    evt->start_time_1 = mjd >> 8;
+    evt->start_time_2 = mjd & 0xFF;
+
+    evt->start_time_3 = toBCD(time->tm_hour);
+    evt->start_time_4 = toBCD(time->tm_min);
+    evt->start_time_5 = toBCD(time->tm_sec);
+
+}
+
+static void fill_eit_duration(eit_event_struct *evt, int time)
+{
+    //time is given in second
+    //convert to hour, minutes, seconds
+    evt->duration_1 = toBCD(time / 3600);
+    evt->duration_2 = toBCD((time % 3600) / 60);
+    evt->duration_3 = toBCD((time % 3600) % 60);
+}
+
+// convert from set of strings to DVB format (EIT)
+void eEPGCache::submitEventData(const std::vector<eServiceReferenceDVB>& serviceRefs, long start,
+       long duration, const char* title, const char* short_summary,
+       const char* long_description, char event_type)
+{
+       std::vector<int> sids;
+       std::vector<eDVBChannelID> chids;
+       for (std::vector<eServiceReferenceDVB>::const_iterator serviceRef = serviceRefs.begin();
+               serviceRef != serviceRefs.end();
+               ++serviceRef)
        {
        {
-               bool inc_refcount=false;
-               switch(argstring[pos])
+               eDVBChannelID chid;
+               serviceRef->getChannelID(chid);
+               chids.push_back(chid);
+               sids.push_back(serviceRef->getServiceID().get());
+       }
+       submitEventData(sids, chids, start, duration, title, short_summary, long_description, event_type, EPG_IMPORT);
+}
+
+void eEPGCache::submitEventData(const std::vector<int>& sids, const std::vector<eDVBChannelID>& chids, long start,
+       long duration, const char* title, const char* short_summary,
+       const char* long_description, char event_type, int source)
+{
+       if (!title)
+               return;
+       if (sids.size() != chids.size())
+               return;
+       static const int EIT_LENGTH = 4108;
+       static const uint8_t codePage = 0x15; // UTF-8 encoding
+       uint8_t data[EIT_LENGTH];
+
+       eit_t *packet = (eit_t *) data;
+       packet->table_id = 0x50;
+       packet->section_syntax_indicator = 1;
+
+       packet->version_number = 0;     // eEPGCache::sectionRead() will dig this for the moment
+       packet->current_next_indicator = 0;
+       packet->section_number = 0;     // eEPGCache::sectionRead() will dig this for the moment
+       packet->last_section_number = 0;        // eEPGCache::sectionRead() will dig this for the moment
+
+       packet->segment_last_section_number = 0; // eEPGCache::sectionRead() will dig this for the moment
+       packet->segment_last_table_id = 0x50;
+
+       eit_event_t *evt_struct = (eit_event_t*) (data + EIT_SIZE);
+
+       uint16_t eventId = start & 0xFFFF;
+       evt_struct->setEventId(eventId);
+
+       //6 bytes start time, 3 bytes duration
+       fill_eit_start(evt_struct, start);
+       fill_eit_duration(evt_struct, duration);
+
+       evt_struct->running_status = 0;
+       evt_struct->free_CA_mode = 0;
+
+       //no support for different code pages, only DVB's latin1 character set
+       //TODO: convert text to correct character set (data is probably passed in as UTF-8)
+       uint8_t *x = (uint8_t *) evt_struct;
+       x += EIT_LOOP_SIZE;
+       int nameLength = strnlen(title, 246);
+       int descLength = short_summary ? strnlen(short_summary, 246 - nameLength) : 0;
+
+       eit_short_event_descriptor_struct *short_evt = (eit_short_event_descriptor_struct*) x;
+       short_evt->descriptor_tag = SHORT_EVENT_DESCRIPTOR;
+       short_evt->descriptor_length = EIT_SHORT_EVENT_DESCRIPTOR_SIZE + nameLength + descLength + 1 - 2; //+1 for length of short description, -2 for tag and length
+       if (nameLength) ++short_evt->descriptor_length; // +1 for codepage byte
+       if (descLength) ++short_evt->descriptor_length;
+       short_evt->language_code_1 = 'e';
+       short_evt->language_code_2 = 'n';
+       short_evt->language_code_3 = 'g';
+       short_evt->event_name_length = nameLength ? nameLength + 1 : 0;
+       x = (uint8_t *) short_evt;
+       x += EIT_SHORT_EVENT_DESCRIPTOR_SIZE;
+       *x = codePage;
+       ++x;
+       memcpy(x, title, nameLength);
+       x += nameLength;
+       if (descLength)
+       {
+               *x = descLength + 1;
+               ++x;
+               *x = codePage;
+               ++x;
+               memcpy(x, short_summary, descLength);
+               x += descLength;
+       }
+       else
+       {
+               *x = 0;
+               ++x;
+       }
+
+       //Content type
+       if (event_type != 0)
+       {
+               x[0] = 0x54;
+               x[1] = 2;
+               x[2] = event_type;
+               x[3] = 0;
+               x += 4;
+       }
+
+       //Long description
+       int currentLoopLength = x - (uint8_t*)short_evt;
+       static const int overheadPerDescriptor = 9; //increase if codepages are added!!!
+       static const int MAX_LEN = 256 - overheadPerDescriptor;
+
+       int textLength = long_description ? strnlen(long_description, EIT_LENGTH) : 0;//EIT_LENGTH is a bit too much, but it's only here as a reasonable end point
+       int lastDescriptorNumber = (textLength + MAX_LEN-1) / MAX_LEN - 1;
+       int remainingTextLength = textLength - lastDescriptorNumber * MAX_LEN;
+
+       //if long description is too long, just try to fill as many descriptors as possible
+       while ( (lastDescriptorNumber+1) * 256 + currentLoopLength > EIT_LENGTH - EIT_LOOP_SIZE)
+       {
+               lastDescriptorNumber--;
+               remainingTextLength = MAX_LEN;
+       }
+
+       for (int descrIndex = 0; descrIndex <= lastDescriptorNumber; ++descrIndex)
+       {
+               eit_extended_descriptor_struct *ext_evt = (eit_extended_descriptor_struct*) x;
+               ext_evt->descriptor_tag = EIT_EXTENDED_EVENT_DESCRIPOR;
+               //descriptor header length is 6, including the 2 tag and length bytes
+               //so the length field must be: stringlength + 1 (2 4-bits numbers) + 3 (lang code) + 2 bytes for item info length field and text length field
+               int currentTextLength = descrIndex < lastDescriptorNumber ? MAX_LEN : remainingTextLength;
+               ext_evt->descriptor_length = 6 + currentTextLength + 1;
+
+               ext_evt->descriptor_number = descrIndex;
+               ext_evt->last_descriptor_number = lastDescriptorNumber;
+               ext_evt->iso_639_2_language_code_1 = 'e';
+               ext_evt->iso_639_2_language_code_2 = 'n';
+               ext_evt->iso_639_2_language_code_3 = 'g';
+
+               x[6] = 0; //item information (car, year, director, etc. Unsupported for now)
+               x[7] = currentTextLength + 1; //length of description string (part in this message)
+               x[8] = codePage;
+               memcpy(x + 9, &long_description[descrIndex*MAX_LEN], currentTextLength);
+
+               x += 2 + ext_evt->descriptor_length;
+       }
+
+       //TODO: add age and more
+       int desc_loop_length = x - ((uint8_t*)evt_struct + EIT_LOOP_SIZE);
+       evt_struct->setDescriptorsLoopLength(desc_loop_length);
+
+       int packet_length = (x - data) - 3; //should add 1 for crc....
+       packet->setSectionLength(packet_length);
+       // Add channelrefs and submit data.
+       for (unsigned int i = 0; i < chids.size(); i++)
+       {
+               packet->setServiceId(sids[i]);
+               packet->setTransportStreamId(chids[i].transport_stream_id.get());
+               packet->setOriginalNetworkId(chids[i].original_network_id.get());
+               sectionRead(data, source, 0);
+       }
+}
+
+void eEPGCache::setEpgHistorySeconds(time_t seconds)
+{
+       historySeconds = seconds;
+}
+
+void eEPGCache::setEpgSources(unsigned int mask)
+{
+       enabledSources = mask;
+}
+
+unsigned int eEPGCache::getEpgSources()
+{
+       return enabledSources;
+}
+
+static const char* getStringFromPython(ePyObject obj)
+{
+       char *result = 0;
+       if (PyString_Check(obj))
+       {
+               result = PyString_AS_STRING(obj);
+       }
+       return result;
+}
+
+void eEPGCache::importEvent(ePyObject serviceReference, ePyObject list)
+{
+       importEvents(serviceReference, list);
+}
+
+//here we get a python tuple of tuples ;)
+// consider it an array of objects with the following data
+// 1. start time (long)
+// 2. duration (int)
+// 3. event title (string)
+// 4. short description (string)
+// 5. extended description (string)
+// 6. event type (byte)
+void eEPGCache::importEvents(ePyObject serviceReferences, ePyObject list)
+{
+       std::vector<eServiceReferenceDVB> refs;
+
+       if (PyString_Check(serviceReferences))
+       {
+               char *refstr;
+               refstr = PyString_AS_STRING(serviceReferences);
+               if (!refstr)
                {
                {
-                       case '0': // PyLong 0
-                               tmp = PyLong_FromLong(0);
-                               break;
-                       case 'I': // Event Id
-                               tmp = PyLong_FromLong(evData->getEventID());
-                               break;
-                       case 'B': // Event Begin Time
-                               if (ptr)
-                                       tmp = ptr ? PyLong_FromLong(ptr->getBeginTime()) : ePyObject();
-                               else
-                                       tmp = PyLong_FromLong(evData->getStartTime());
-                               break;
-                       case 'D': // Event Duration
-                               if (ptr)
-                                       tmp = ptr ? PyLong_FromLong(ptr->getDuration()) : ePyObject();
-                               else
-                                       tmp = PyLong_FromLong(evData->getDuration());
-                               break;
-                       case 'T': // Event Title
-                               tmp = ptr ? PyString_FromString(ptr->getEventName().c_str()) : ePyObject();
-                               break;
-                       case 'S': // Event Short Description
-                               tmp = ptr ? PyString_FromString(ptr->getShortDescription().c_str()) : ePyObject();
-                               break;
-                       case 'E': // Event Extended Description
-                               tmp = ptr ? PyString_FromString(ptr->getExtendedDescription().c_str()) : ePyObject();
-                               break;
-                       case 'R': // service reference string
-                               tmp = service_reference;
-                               inc_refcount = true;
-                               break;
-                       case 'n': // short service name
-                       case 'N': // service name
-                               tmp = service_name;
-                               inc_refcount = true;
-                               break;
-                       default:  // ignore unknown
-                               tmp = ePyObject();
-                               eDebug("fillTuple2 unknown '%c'... insert None in Result", argstring[pos]);
+                       eDebug("[eEPGCache:import] serviceReference string is 0, aborting");
+                       return;
                }
                }
-               if (!tmp)
+               refs.push_back(eServiceReferenceDVB(refstr));
+       }
+       else if (PyList_Check(serviceReferences))
+       {
+               int nRefs = PyList_Size(serviceReferences);
+               for (int i = 0; i < nRefs; ++i)
                {
                {
-                       tmp = Py_None;
-                       inc_refcount = true;
+                       PyObject* item = PyList_GET_ITEM(serviceReferences, i);
+                       char *refstr;
+                       refstr = PyString_AS_STRING(item);
+                       if (!refstr)
+                       {
+                               eDebug("[eEPGCache:import] a serviceref item is not a string");
+                       }
+                       else
+                       {
+                               refs.push_back(eServiceReferenceDVB(refstr));
+                       }
                }
                }
-               if (inc_refcount)
-                       Py_INCREF(tmp);
-               PyTuple_SET_ITEM(tuple, pos++, tmp);
+       }
+       else
+       {
+               eDebug("[eEPGCache:import] serviceReference string is neither string nor list, aborting");
+               return;
+       }
+
+       bool isTuple = PyTuple_Check(list);
+       if (!isTuple && !PyList_Check(list))
+       {
+
+               eDebug("[eEPGCache:import] argument 'list' is neither list nor tuple.");
+               return;
+       }
+
+       int numberOfEvents = isTuple ? PyTuple_Size(list) : PyList_Size(list);
+
+       for (int i = 0; i < numberOfEvents;  ++i)
+       {
+               ePyObject singleEvent = isTuple ? PyTuple_GET_ITEM(list, i) : PyList_GET_ITEM(list, i);
+               if (!PyTuple_Check(singleEvent))
+               {
+                       eDebug("[eEPGCache:import] eventdata tuple does not pass PyTuple_Check, aborting");
+                       return;
+               }
+               int tupleSize = PyTuple_Size(singleEvent);
+               if (tupleSize < 5)
+               {
+                       eDebug("[eEPGCache:import] eventdata tuple does not contain enough fields, aborting");
+                       return;
+               }
+
+               long start = PyLong_AsLong(PyTuple_GET_ITEM(singleEvent, 0));
+               long duration = PyInt_AsLong(PyTuple_GET_ITEM(singleEvent, 1));
+               const char *title = getStringFromPython(PyTuple_GET_ITEM(singleEvent, 2));
+               const char *short_summary = getStringFromPython(PyTuple_GET_ITEM(singleEvent, 3));
+               const char *long_description = getStringFromPython(PyTuple_GET_ITEM(singleEvent, 4));
+               char event_type = (char) PyInt_AsLong(PyTuple_GET_ITEM(singleEvent, 5));
+
+               Py_BEGIN_ALLOW_THREADS;
+               submitEventData(refs, start, duration, title, short_summary, long_description, event_type);
+               Py_END_ALLOW_THREADS;
        }
 }
 
        }
 }
 
@@ -2163,6 +2978,8 @@ void fillTuple2(ePyObject tuple, const char *argstring, int argcount, eventData
 //   D = Event Duration
 //   T = Event Title
 //   S = Event Short Description
 //   D = Event Duration
 //   T = Event Title
 //   S = Event Short Description
+//   P = Event Parental Rating
+//   W = Event Content Description
 //   E = Event Extended Description
 //   R = Service Reference
 //   N = Service Name
 //   E = Event Extended Description
 //   R = Service Reference
 //   N = Service Name
@@ -2170,12 +2987,13 @@ void fillTuple2(ePyObject tuple, const char *argstring, int argcount, eventData
 //  the second tuple entry is the MAX matches value
 //  the third tuple entry is the type of query
 //     0 = search for similar broadcastings (SIMILAR_BROADCASTINGS_SEARCH)
 //  the second tuple entry is the MAX matches value
 //  the third tuple entry is the type of query
 //     0 = search for similar broadcastings (SIMILAR_BROADCASTINGS_SEARCH)
-//     1 = search events with exactly title name (EXAKT_TITLE_SEARCH)
+//     1 = search events with exactly title name (EXACT_TITLE_SEARCH)
 //     2 = search events with text in title name (PARTIAL_TITLE_SEARCH)
 //     2 = search events with text in title name (PARTIAL_TITLE_SEARCH)
+//     3 = search events starting with title name (START_TITLE_SEARCH)
 //  when type is 0 (SIMILAR_BROADCASTINGS_SEARCH)
 //   the fourth is the servicereference string
 //   the fifth is the eventid
 //  when type is 0 (SIMILAR_BROADCASTINGS_SEARCH)
 //   the fourth is the servicereference string
 //   the fifth is the eventid
-//  when type is 1 or 2 (EXAKT_TITLE_SEARCH or PARTIAL_TITLE_SEARCH)
+//  when type > 0 (*_TITLE_SEARCH)
 //   the fourth is the search text
 //   the fifth is
 //     0 = case sensitive (CASE_CHECK)
 //   the fourth is the search text
 //   the fifth is
 //     0 = case sensitive (CASE_CHECK)
@@ -2184,8 +3002,7 @@ void fillTuple2(ePyObject tuple, const char *argstring, int argcount, eventData
 PyObject *eEPGCache::search(ePyObject arg)
 {
        ePyObject ret;
 PyObject *eEPGCache::search(ePyObject arg)
 {
        ePyObject ret;
-       int descridx = -1;
-       __u32 descr[512];
+       std::deque<uint32_t> descr;
        int eventid = -1;
        const char *argstring=0;
        char *refstr=0;
        int eventid = -1;
        const char *argstring=0;
        char *refstr=0;
@@ -2211,11 +3028,14 @@ PyObject *eEPGCache::search(ePyObject arg)
 #endif
                                argstring = PyString_AS_STRING(obj);
                                for (int i=0; i < argcount; ++i)
 #endif
                                argstring = PyString_AS_STRING(obj);
                                for (int i=0; i < argcount; ++i)
+                               {
                                        switch(argstring[i])
                                        {
                                        case 'S':
                                        case 'E':
                                        case 'T':
                                        switch(argstring[i])
                                        {
                                        case 'S':
                                        case 'E':
                                        case 'T':
+                                       case 'P':
+                                       case 'W':
                                                needServiceEvent=true;
                                                break;
                                        case 'N':
                                                needServiceEvent=true;
                                                break;
                                        case 'N':
@@ -2230,20 +3050,24 @@ PyObject *eEPGCache::search(ePyObject arg)
                                        default:
                                                break;
                                        }
                                        default:
                                                break;
                                        }
+                               }
                        }
                        else
                        {
                                PyErr_SetString(PyExc_StandardError,
                                        "type error");
                        }
                        else
                        {
                                PyErr_SetString(PyExc_StandardError,
                                        "type error");
-                               eDebug("tuple arg 0 is not a string");
+                               eDebug("[eEPGCache] tuple arg 0 is not a string");
                                return NULL;
                        }
                }
                if (tuplesize > 1)
                                return NULL;
                        }
                }
                if (tuplesize > 1)
+               {
                        maxmatches = PyLong_AsLong(PyTuple_GET_ITEM(arg, 1));
                        maxmatches = PyLong_AsLong(PyTuple_GET_ITEM(arg, 1));
+               }
                if (tuplesize > 2)
                {
                        querytype = PyLong_AsLong(PyTuple_GET_ITEM(arg, 2));
                if (tuplesize > 2)
                {
                        querytype = PyLong_AsLong(PyTuple_GET_ITEM(arg, 2));
+
                        if (tuplesize > 4 && querytype == 0)
                        {
                                ePyObject obj = PyTuple_GET_ITEM(arg, 3);
                        if (tuplesize > 4 && querytype == 0)
                        {
                                ePyObject obj = PyTuple_GET_ITEM(arg, 3);
@@ -2259,47 +3083,44 @@ PyObject *eEPGCache::search(ePyObject arg)
                                                lookupEventId(ref, eventid, evData);
                                                if (evData)
                                                {
                                                lookupEventId(ref, eventid, evData);
                                                if (evData)
                                                {
-                                                       __u8 *data = evData->EITdata;
-                                                       int tmp = evData->ByteSize-10;
-                                                       __u32 *p = (__u32*)(data+10);
-                                                               // search short and extended event descriptors
-                                                       while(tmp>3)
+                                                       // search short and extended event descriptors
+                                                       for (uint8_t i = 0; i < evData->n_crc; ++i)
                                                        {
                                                        {
-                                                               __u32 crc = *p++;
-                                                               descriptorMap::iterator it =
+                                                               uint32_t crc = evData->crc_list[i];
+                                                               DescriptorMap::iterator it =
                                                                        eventData::descriptors.find(crc);
                                                                if (it != eventData::descriptors.end())
                                                                {
                                                                        eventData::descriptors.find(crc);
                                                                if (it != eventData::descriptors.end())
                                                                {
-                                                                       __u8 *descr_data = it->second.second;
+                                                                       uint8_t *descr_data = it->second.data;
                                                                        switch(descr_data[0])
                                                                        {
                                                                        case 0x4D ... 0x4E:
                                                                        switch(descr_data[0])
                                                                        {
                                                                        case 0x4D ... 0x4E:
-                                                                               descr[++descridx]=crc;
+                                                                               descr.push_back(crc);
+                                                                               break;
                                                                        default:
                                                                                break;
                                                                        }
                                                                }
                                                                        default:
                                                                                break;
                                                                        }
                                                                }
-                                                               tmp-=4;
                                                        }
                                                }
                                                        }
                                                }
-                                               if (descridx<0)
-                                                       eDebug("event not found");
+                                               if (descr.empty())
+                                                       eDebug("[eEPGCache] event not found");
                                        }
                                        else
                                        {
                                                PyErr_SetString(PyExc_StandardError, "type error");
                                        }
                                        else
                                        {
                                                PyErr_SetString(PyExc_StandardError, "type error");
-                                               eDebug("tuple arg 4 is not a valid service reference string");
+                                               eDebug("[eEPGCache] tuple arg 4 is not a valid service reference string");
                                                return NULL;
                                        }
                                }
                                else
                                {
                                        PyErr_SetString(PyExc_StandardError, "type error");
                                                return NULL;
                                        }
                                }
                                else
                                {
                                        PyErr_SetString(PyExc_StandardError, "type error");
-                                       eDebug("tuple arg 4 is not a string");
+                                       eDebug("[eEPGCache] tuple arg 4 is not a string");
                                        return NULL;
                                }
                        }
                                        return NULL;
                                }
                        }
-                       else if (tuplesize > 4 && (querytype == 1 || querytype == 2) )
+                       else if (tuplesize > 4 && (querytype > 0) )
                        {
                                ePyObject obj = PyTuple_GET_ITEM(arg, 3);
                                if (PyString_Check(obj))
                        {
                                ePyObject obj = PyTuple_GET_ITEM(arg, 3);
                                if (PyString_Check(obj))
@@ -2311,83 +3132,85 @@ PyObject *eEPGCache::search(ePyObject arg)
 #else
                                        int textlen = PyString_Size(obj);
 #endif
 #else
                                        int textlen = PyString_Size(obj);
 #endif
-                                       if (querytype == 1)
-                                               eDebug("lookup for events with '%s' as title(%s)", str, casetype?"ignore case":"case sensitive");
-                                       else
-                                               eDebug("lookup for events with '%s' in title(%s)", str, casetype?"ignore case":"case sensitive");
+                                       switch (querytype)
+                                       {
+                                               case 1:
+                                                       eDebug("[eEPGCache] lookup events with '%s' as title (%s)", str, casetype?"ignore case":"case sensitive");
+                                                       break;
+                                               case 2:
+                                                       eDebug("[eEPGCache] lookup events with '%s' in title (%s)", str, casetype?"ignore case":"case sensitive");
+                                                       break;
+                                               case 3:
+                                                       eDebug("[eEPGCache] lookup events, title starting with '%s' (%s)", str, casetype?"ignore case":"case sensitive");
+                                                       break;
+                                       }
+                                       Py_BEGIN_ALLOW_THREADS; /* No Python code in this section, so other threads can run */
                                        singleLock s(cache_lock);
                                        singleLock s(cache_lock);
-                                       for (descriptorMap::iterator it(eventData::descriptors.begin());
-                                               it != eventData::descriptors.end() && descridx < 511; ++it)
+                                       std::string title;
+                                       for (DescriptorMap::iterator it(eventData::descriptors.begin());
+                                               it != eventData::descriptors.end(); ++it)
                                        {
                                        {
-                                               __u8 *data = it->second.second;
-                                               if ( data[0] == 0x4D ) // short event descriptor
+                                               uint8_t *data = it->second.data;
+                                               if ( data[0] == SHORT_EVENT_DESCRIPTOR )
                                                {
                                                {
+                                                       const char *titleptr = (const char*)&data[6];
                                                        int title_len = data[5];
                                                        int title_len = data[5];
-                                                       if ( querytype == 1 )
+                                                       if (data[6] < 0x20)
                                                        {
                                                        {
-                                                               int offs = 6;
-                                                               // skip DVB-Text Encoding!
-                                                               if (data[6] == 0x10)
-                                                               {
-                                                                       offs+=3;
-                                                                       title_len-=3;
-                                                               }
-                                                               else if(data[6] > 0 && data[6] < 0x20)
-                                                               {
-                                                                       offs+=1;
-                                                                       title_len-=1;
-                                                               }
+                                                               /* custom encoding */
+                                                               title = convertDVBUTF8((unsigned char*)titleptr, title_len, 0x40, 0);
+                                                               titleptr = title.data();
+                                                               title_len = title.length();
+                                                       }
+                                                       if (title_len < textlen)
+                                                               /*Doesn't fit, so cannot match anything */
+                                                               continue;
+                                                       if (querytype == 1)
+                                                       {
+                                                               /* require exact title match */
                                                                if (title_len != textlen)
                                                                        continue;
                                                                if (title_len != textlen)
                                                                        continue;
-                                                               if ( casetype )
+                                                       }
+                                                       else if (querytype == 3)
+                                                       {
+                                                               /* Do a "startswith" match by pretending the text isn't that long */
+                                                               title_len = textlen;
+                                                       }
+                                                       if (casetype)
+                                                       {
+                                                               while (title_len >= textlen)
                                                                {
                                                                {
-                                                                       if ( !strncasecmp((const char*)data+offs, str, title_len) )
+                                                                       if (!strncasecmp(titleptr, str, textlen))
                                                                        {
                                                                        {
-//                                                                             std::string s((const char*)data+offs, title_len);
-//                                                                             eDebug("match1 %s %s", str, s.c_str() );
-                                                                               descr[++descridx] = it->first;
+                                                                               descr.push_back(it->first);
+                                                                               break;
                                                                        }
                                                                        }
-                                                               }
-                                                               else if ( !strncmp((const char*)data+offs, str, title_len) )
-                                                               {
-//                                                                     std::string s((const char*)data+offs, title_len);
-//                                                                     eDebug("match2 %s %s", str, s.c_str() );
-                                                                       descr[++descridx] = it->first;
+                                                                       title_len--;
+                                                                       titleptr++;
                                                                }
                                                        }
                                                        else
                                                        {
                                                                }
                                                        }
                                                        else
                                                        {
-                                                               int idx=0;
-                                                               while((title_len-idx) >= textlen)
+                                                               while (title_len >= textlen)
                                                                {
                                                                {
-                                                                       if (casetype)
-                                                                       {
-                                                                               if (!strncasecmp((const char*)data+6+idx, str, textlen) )
-                                                                               {
-                                                                                       descr[++descridx] = it->first;
-//                                                                                     std::string s((const char*)data+6, title_len);
-//                                                                                     eDebug("match 3 %s %s", str, s.c_str() );
-                                                                                       break;
-                                                                               }
-                                                                       }
-                                                                       else if (!strncmp((const char*)data+6+idx, str, textlen) )
+                                                                       if (!memcmp(titleptr, str, textlen))
                                                                        {
                                                                        {
-                                                                               descr[++descridx] = it->first;
-//                                                                             std::string s((const char*)data+6, title_len);
-//                                                                             eDebug("match 4 %s %s", str, s.c_str() );
+                                                                               descr.push_back(it->first);
                                                                                break;
                                                                        }
                                                                                break;
                                                                        }
-                                                                       ++idx;
+                                                                       title_len--;
+                                                                       titleptr++;
                                                                }
                                                        }
                                                }
                                        }
                                                                }
                                                        }
                                                }
                                        }
+                                       Py_END_ALLOW_THREADS;
                                }
                                else
                                {
                                        PyErr_SetString(PyExc_StandardError,
                                                "type error");
                                }
                                else
                                {
                                        PyErr_SetString(PyExc_StandardError,
                                                "type error");
-                                       eDebug("tuple arg 4 is not a string");
+                                       eDebug("[eEPGCache] tuple arg 4 is not a string");
                                        return NULL;
                                }
                        }
                                        return NULL;
                                }
                        }
@@ -2395,7 +3218,7 @@ PyObject *eEPGCache::search(ePyObject arg)
                        {
                                PyErr_SetString(PyExc_StandardError,
                                        "type error");
                        {
                                PyErr_SetString(PyExc_StandardError,
                                        "type error");
-                               eDebug("tuple arg 3(%d) is not a known querytype(0, 1, 2)", querytype);
+                               eDebug("[eEPGCache] tuple arg 3(%d) is not a known querytype(0..3)", querytype);
                                return NULL;
                        }
                }
                                return NULL;
                        }
                }
@@ -2403,7 +3226,7 @@ PyObject *eEPGCache::search(ePyObject arg)
                {
                        PyErr_SetString(PyExc_StandardError,
                                "type error");
                {
                        PyErr_SetString(PyExc_StandardError,
                                "type error");
-                       eDebug("not enough args in tuple");
+                       eDebug("[eEPGCache] not enough args in tuple");
                        return NULL;
                }
        }
                        return NULL;
                }
        }
@@ -2411,11 +3234,11 @@ PyObject *eEPGCache::search(ePyObject arg)
        {
                PyErr_SetString(PyExc_StandardError,
                        "type error");
        {
                PyErr_SetString(PyExc_StandardError,
                        "type error");
-               eDebug("arg 0 is not a tuple");
+               eDebug("[eEPGCache] arg 0 is not a tuple");
                return NULL;
        }
 
                return NULL;
        }
 
-       if (descridx > -1)
+       if (!descr.empty())
        {
                int maxcount=maxmatches;
                eServiceReferenceDVB ref(refstr?(const eServiceReferenceDVB&)handleGroup(eServiceReference(refstr)):eServiceReferenceDVB(""));
        {
                int maxcount=maxmatches;
                eServiceReferenceDVB ref(refstr?(const eServiceReferenceDVB&)handleGroup(eServiceReference(refstr)):eServiceReferenceDVB(""));
@@ -2432,105 +3255,118 @@ PyObject *eEPGCache::search(ePyObject arg)
                                ++cit;
                                continue;
                        }
                                ++cit;
                                continue;
                        }
-                       ePyObject service_name;
-                       ePyObject service_reference;
-                       timeMap &evmap = cit->second.second;
+                       timeMap &evmap = cit->second.byTime;
                        // check all events
                        for (timeMap::iterator evit(evmap.begin()); evit != evmap.end() && maxcount; ++evit)
                        {
                        // check all events
                        for (timeMap::iterator evit(evmap.begin()); evit != evmap.end() && maxcount; ++evit)
                        {
-                               int evid = evit->second->getEventID();
-                               if ( evid == eventid)
-                                       continue;
-                               __u8 *data = evit->second->EITdata;
-                               int tmp = evit->second->ByteSize-10;
-                               __u32 *p = (__u32*)(data+10);
+                               if (querytype == 0)
+                               {
+                                       /* ignore the current event, when looking for similar events */
+                                       if (evit->second->getEventID() == eventid)
+                                               continue;
+                               }
                                // check if any of our descriptor used by this event
                                // check if any of our descriptor used by this event
-                               int cnt=-1;
-                               while(tmp>3)
+                               unsigned int cnt = 0;
+                               for (uint8_t i = 0; i < evit->second->n_crc; ++i)
                                {
                                {
-                                       __u32 crc32 = *p++;
-                                       for ( int i=0; i <= descridx; ++i)
+                                       uint32_t crc32 = evit->second->crc_list[i];
+                                       for (std::deque<uint32_t>::const_iterator it = descr.begin();
+                                               it != descr.end(); ++it)
                                        {
                                        {
-                                               if (descr[i] == crc32)  // found...
+                                               if (*it == crc32)  // found...
+                                               {
                                                        ++cnt;
                                                        ++cnt;
+                                                       if (querytype)
+                                                       {
+                                                               /* we need only one match, when we're not looking for similar broadcasting events */
+                                                               i = evit->second->n_crc;
+                                                               break;
+                                                       }
+                                               }
                                        }
                                        }
-                                       tmp-=4;
                                }
                                }
-                               if ( (querytype == 0 && cnt == descridx) ||
-                                        ((querytype == 1 || querytype == 2) && cnt != -1) )
+                               if ( (querytype == 0 && cnt == descr.size()) ||
+                                        ((querytype > 0) && cnt != 0) )
                                {
                                        const uniqueEPGKey &service = cit->first;
                                {
                                        const uniqueEPGKey &service = cit->first;
-                                       eServiceReference ref =
-                                               eDVBDB::getInstance()->searchReference(service.tsid, service.onid, service.sid);
-                                       if (ref.valid())
+                                       std::vector<eServiceReference> refs;
+                                       eDVBDB::getInstance()->searchAllReferences(refs, service.tsid, service.onid, service.sid);
+                                       for (unsigned int i = 0; i < refs.size(); i++)
                                        {
                                        {
-                                       // create servive event
-                                               eServiceEvent ptr;
-                                               const eventData *ev_data=0;
-                                               if (needServiceEvent)
+                                               eServiceReference ref = refs[i];
+                                               if (ref.valid())
                                                {
                                                {
-                                                       if (lookupEventId(ref, evid, ev_data))
-                                                               eDebug("event not found !!!!!!!!!!!");
-                                                       else
+                                                       ePyObject service_name;
+                                                       ePyObject service_reference;
+                                               // create servive event
+                                                       eServiceEvent ptr;
+                                                       const eventData *ev_data=0;
+                                                       if (needServiceEvent)
                                                        {
                                                        {
-                                                               const eServiceReferenceDVB &dref = (const eServiceReferenceDVB&)ref;
-                                                               Event ev((uint8_t*)ev_data->get());
-                                                               ptr.parseFrom(&ev, (dref.getTransportStreamID().get()<<16)|dref.getOriginalNetworkID().get());
+                                                               if (lookupEventId(ref, evit->second->getEventID(), ev_data))
+                                                                       eDebug("[eEPGCache] event not found !!!!!!!!!!!");
+                                                               else
+                                                               {
+                                                                       const eServiceReferenceDVB &dref = (const eServiceReferenceDVB&)ref;
+                                                                       Event ev((uint8_t*)ev_data->get());
+                                                                       ptr.parseFrom(&ev, (dref.getTransportStreamID().get()<<16)|dref.getOriginalNetworkID().get());
+                                                               }
                                                        }
                                                        }
-                                               }
-                                       // create service name
-                                               if (must_get_service_name && !service_name)
-                                               {
-                                                       ePtr<iStaticServiceInformation> sptr;
-                                                       eServiceCenterPtr service_center;
-                                                       eServiceCenter::getPrivInstance(service_center);
-                                                       if (service_center)
+                                               // create service name
+                                                       if (must_get_service_name && !service_name)
                                                        {
                                                        {
-                                                               service_center->info(ref, sptr);
-                                                               if (sptr)
+                                                               ePtr<iStaticServiceInformation> sptr;
+                                                               eServiceCenterPtr service_center;
+                                                               eServiceCenter::getPrivInstance(service_center);
+                                                               if (service_center)
                                                                {
                                                                {
-                                                                       std::string name;
-                                                                       sptr->getName(ref, name);
-
-                                                                       if (must_get_service_name == 1)
+                                                                       service_center->info(ref, sptr);
+                                                                       if (sptr)
                                                                        {
                                                                        {
-                                                                               size_t pos;
-                                                                               // filter short name brakets
-                                                                               while((pos = name.find("\xc2\x86")) != std::string::npos)
-                                                                                       name.erase(pos,2);
-                                                                               while((pos = name.find("\xc2\x87")) != std::string::npos)
-                                                                                       name.erase(pos,2);
-                                                                       }
-                                                                       else
-                                                                               name = buildShortName(name);
+                                                                               std::string name;
+                                                                               sptr->getName(ref, name);
 
 
-                                                                       if (name.length())
-                                                                               service_name = PyString_FromString(name.c_str());
+                                                                               if (must_get_service_name == 1)
+                                                                               {
+                                                                                       size_t pos;
+                                                                                       // filter short name brakets
+                                                                                       while((pos = name.find("\xc2\x86")) != std::string::npos)
+                                                                                               name.erase(pos,2);
+                                                                                       while((pos = name.find("\xc2\x87")) != std::string::npos)
+                                                                                               name.erase(pos,2);
+                                                                               }
+                                                                               else
+                                                                                       name = buildShortName(name);
+
+                                                                               if (name.length())
+                                                                                       service_name = PyString_FromString(name.c_str());
+                                                                       }
                                                                }
                                                                }
+                                                               if (!service_name)
+                                                                       service_name = PyString_FromString("<n/a>");
                                                        }
                                                        }
-                                                       if (!service_name)
-                                                               service_name = PyString_FromString("<n/a>");
+                                               // create servicereference string
+                                                       if (must_get_service_reference && !service_reference)
+                                                               service_reference = PyString_FromString(ref.toString().c_str());
+                                               // create list
+                                                       if (!ret)
+                                                               ret = PyList_New(0);
+                                               // create tuple
+                                                       ePyObject tuple = PyTuple_New(argcount);
+                                               // fill tuple
+                                                       ePyObject tmp = ePyObject();
+                                                       fillTuple(tuple, argstring, argcount, service_reference, ev_data ? &ptr : 0, service_name, tmp, evit->second);
+                                                       PyList_Append(ret, tuple);
+                                                       Py_DECREF(tuple);
+                                                       if (service_name)
+                                                               Py_DECREF(service_name);
+                                                       if (service_reference)
+                                                               Py_DECREF(service_reference);
+                                                       --maxcount;
                                                }
                                                }
-                                       // create servicereference string
-                                               if (must_get_service_reference && !service_reference)
-                                                       service_reference = PyString_FromString(ref.toString().c_str());
-                                       // create list
-                                               if (!ret)
-                                                       ret = PyList_New(0);
-                                       // create tuple
-                                               ePyObject tuple = PyTuple_New(argcount);
-                                       // fill tuple
-                                               fillTuple2(tuple, argstring, argcount, evit->second, ev_data ? &ptr : 0, service_name, service_reference);
-                                               PyList_Append(ret, tuple);
-                                               Py_DECREF(tuple);
-                                               --maxcount;
                                        }
                                }
                        }
                                        }
                                }
                        }
-                       if (service_name)
-                               Py_DECREF(service_name);
-                       if (service_reference)
-                               Py_DECREF(service_reference);
                        if (first)
                        {
                                // now start at first service in epgcache database ( only in SIMILAR BROADCASTING SEARCH )
                        if (first)
                        {
                                // now start at first service in epgcache database ( only in SIMILAR BROADCASTING SEARCH )
@@ -2576,11 +3412,11 @@ void eEPGCache::PMTready(eDVBServicePMTHandler *pmthandler)
                                                switch ((*desc)->getTag())
                                                {
                                                        case 0xC2: // user defined
                                                switch ((*desc)->getTag())
                                                {
                                                        case 0xC2: // user defined
-                                                               if ((*desc)->getLength() == 8) 
+                                                               if ((*desc)->getLength() == 8)
                                                                {
                                                                {
-                                                                       __u8 buffer[10];
+                                                                       uint8_t buffer[10];
                                                                        (*desc)->writeToBuffer(buffer);
                                                                        (*desc)->writeToBuffer(buffer);
-                                                                       if (!strncmp((const char *)buffer+2, "EPGDATA", 7))
+                                                                       if (!memcmp((const char *)buffer+2, "EPGDATA", 7))
                                                                        {
                                                                                eServiceReferenceDVB ref;
                                                                                if (!pmthandler->getServiceReference(ref))
                                                                        {
                                                                                eServiceReferenceDVB ref;
                                                                                if (!pmthandler->getServiceReference(ref))
@@ -2589,7 +3425,7 @@ void eEPGCache::PMTready(eDVBServicePMTHandler *pmthandler)
                                                                                        messages.send(Message(Message::got_mhw2_channel_pid, ref, pid));
                                                                                }
                                                                        }
                                                                                        messages.send(Message(Message::got_mhw2_channel_pid, ref, pid));
                                                                                }
                                                                        }
-                                                                       else if(!strncmp((const char *)buffer+2, "FICHAS", 6))
+                                                                       else if(!memcmp((const char *)buffer+2, "FICHAS", 6))
                                                                        {
                                                                                eServiceReferenceDVB ref;
                                                                                if (!pmthandler->getServiceReference(ref))
                                                                        {
                                                                                eServiceReferenceDVB ref;
                                                                                if (!pmthandler->getServiceReference(ref))
@@ -2598,7 +3434,7 @@ void eEPGCache::PMTready(eDVBServicePMTHandler *pmthandler)
                                                                                        messages.send(Message(Message::got_mhw2_summary_pid, ref, pid));
                                                                                }
                                                                        }
                                                                                        messages.send(Message(Message::got_mhw2_summary_pid, ref, pid));
                                                                                }
                                                                        }
-                                                                       else if(!strncmp((const char *)buffer+2, "GENEROS", 7))
+                                                                       else if(!memcmp((const char *)buffer+2, "GENEROS", 7))
                                                                        {
                                                                                eServiceReferenceDVB ref;
                                                                                if (!pmthandler->getServiceReference(ref))
                                                                        {
                                                                                eServiceReferenceDVB ref;
                                                                                if (!pmthandler->getServiceReference(ref))
@@ -2625,7 +3461,7 @@ void eEPGCache::PMTready(eDVBServicePMTHandler *pmthandler)
                                                                break;
                                                        case 0x90:
                                                        {
                                                                break;
                                                        case 0x90:
                                                        {
-                                                               UnknownDescriptor *descr = (UnknownDescriptor*)*desc;
+                                                               Descriptor *descr = (Descriptor*)*desc;
                                                                int descr_len = descr->getLength();
                                                                if (descr_len == 4)
                                                                {
                                                                int descr_len = descr->getLength();
                                                                if (descr_len == 4)
                                                                {
@@ -2657,27 +3493,27 @@ void eEPGCache::PMTready(eDVBServicePMTHandler *pmthandler)
                }
        }
        else
                }
        }
        else
-               eDebug("PMTready but no pmt!!");
+               eDebug("[eEPGCache] PMTready but no pmt!!");
 }
 
 struct date_time
 {
 }
 
 struct date_time
 {
-       __u8 data[5];
+       uint8_t data[5];
        time_t tm;
        date_time( const date_time &a )
        {
                memcpy(data, a.data, 5);
                tm = a.tm;
        }
        time_t tm;
        date_time( const date_time &a )
        {
                memcpy(data, a.data, 5);
                tm = a.tm;
        }
-       date_time( const __u8 data[5])
+       date_time( const uint8_t data[5])
        {
                memcpy(this->data, data, 5);
        {
                memcpy(this->data, data, 5);
-               tm = parseDVBtime(data[0], data[1], data[2], data[3], data[4]);
+               tm = parseDVBtime(data);
        }
        date_time()
        {
        }
        }
        date_time()
        {
        }
-       const __u8& operator[](int pos) const
+       const uint8_t& operator[](int pos) const
        {
                return data[pos];
        }
        {
                return data[pos];
        }
@@ -2691,42 +3527,44 @@ struct less_datetime
        }
 };
 
        }
 };
 
-void eEPGCache::privateSectionRead(const uniqueEPGKey &current_service, const __u8 *data)
+void eEPGCache::privateSectionRead(const uniqueEPGKey &current_service, const uint8_t *data)
 {
        contentMap &content_time_table = content_time_tables[current_service];
        singleLock s(cache_lock);
        std::map< date_time, std::list<uniqueEPGKey>, less_datetime > start_times;
 {
        contentMap &content_time_table = content_time_tables[current_service];
        singleLock s(cache_lock);
        std::map< date_time, std::list<uniqueEPGKey>, less_datetime > start_times;
-       eventMap &evMap = eventDB[current_service].first;
-       timeMap &tmMap = eventDB[current_service].second;
-       int ptr=8;
+       EventCacheItem &eventDBitem = eventDB[current_service];
+       eventMap &evMap = eventDBitem.byEvent;
+       timeMap &tmMap = eventDBitem.byTime;
+       int ptr = 8;
        int content_id = data[ptr++] << 24;
        content_id |= data[ptr++] << 16;
        content_id |= data[ptr++] << 8;
        content_id |= data[ptr++];
 
        int content_id = data[ptr++] << 24;
        content_id |= data[ptr++] << 16;
        content_id |= data[ptr++] << 8;
        content_id |= data[ptr++];
 
-       contentTimeMap &time_event_map =
-               content_time_table[content_id];
+       contentTimeMap &time_event_map = content_time_table[content_id];
        for ( contentTimeMap::iterator it( time_event_map.begin() );
                it != time_event_map.end(); ++it )
        {
                eventMap::iterator evIt( evMap.find(it->second.second) );
                if ( evIt != evMap.end() )
                {
        for ( contentTimeMap::iterator it( time_event_map.begin() );
                it != time_event_map.end(); ++it )
        {
                eventMap::iterator evIt( evMap.find(it->second.second) );
                if ( evIt != evMap.end() )
                {
+                       // time_event_map can have other timestamp -> get timestamp from eventData
+                       time_t ev_time = evIt->second->getStartTime();
                        delete evIt->second;
                        evMap.erase(evIt);
                        delete evIt->second;
                        evMap.erase(evIt);
+                       tmMap.erase(ev_time);
                }
                }
-               tmMap.erase(it->second.first);
        }
        time_event_map.clear();
 
        }
        time_event_map.clear();
 
-       __u8 duration[3];
+       uint8_t duration[3];
        memcpy(duration, data+ptr, 3);
        ptr+=3;
        int duration_sec =
                fromBCD(duration[0])*3600+fromBCD(duration[1])*60+fromBCD(duration[2]);
 
        memcpy(duration, data+ptr, 3);
        ptr+=3;
        int duration_sec =
                fromBCD(duration[0])*3600+fromBCD(duration[1])*60+fromBCD(duration[2]);
 
-       const __u8 *descriptors[65];
-       const __u8 **pdescr = descriptors;
+       const uint8_t *descriptors[65];
+       const uint8_t **pdescr = descriptors;
 
        int descriptors_length = (data[ptr++]&0x0F) << 8;
        descriptors_length |= data[ptr++];
 
        int descriptors_length = (data[ptr++]&0x0F) << 8;
        descriptors_length |= data[ptr++];
@@ -2768,7 +3606,7 @@ void eEPGCache::privateSectionRead(const uniqueEPGKey &current_service, const __
                                descr_len -= 6;
                                while( descr_len > 2 )
                                {
                                descr_len -= 6;
                                while( descr_len > 2 )
                                {
-                                       __u8 datetime[5];
+                                       uint8_t datetime[5];
                                        datetime[0] = data[ptr++];
                                        datetime[1] = data[ptr++];
                                        int tmp_len = data[ptr++];
                                        datetime[0] = data[ptr++];
                                        datetime[1] = data[ptr++];
                                        int tmp_len = data[ptr++];
@@ -2795,13 +3633,13 @@ void eEPGCache::privateSectionRead(const uniqueEPGKey &current_service, const __
                }
        }
        ASSERT(pdescr <= &descriptors[65]);
                }
        }
        ASSERT(pdescr <= &descriptors[65]);
-       __u8 event[4098];
+       uint8_t event[4098];
        eit_event_struct *ev_struct = (eit_event_struct*) event;
        ev_struct->running_status = 0;
        ev_struct->free_CA_mode = 1;
        memcpy(event+7, duration, 3);
        ptr = 12;
        eit_event_struct *ev_struct = (eit_event_struct*) event;
        ev_struct->running_status = 0;
        ev_struct->free_CA_mode = 1;
        memcpy(event+7, duration, 3);
        ptr = 12;
-       const __u8 **d=descriptors;
+       const uint8_t **d=descriptors;
        while ( d < pdescr )
        {
                memcpy(event+ptr, *d, ((*d)[1])+2);
        while ( d < pdescr )
        {
                memcpy(event+ptr, *d, ((*d)[1])+2);
@@ -2820,7 +3658,7 @@ void eEPGCache::privateSectionRead(const uniqueEPGKey &current_service, const __
                for (std::list<uniqueEPGKey>::iterator i(it->second.begin()); i != it->second.end(); ++i)
                {
                        event[bptr++] = 0x4A;
                for (std::list<uniqueEPGKey>::iterator i(it->second.begin()); i != it->second.end(); ++i)
                {
                        event[bptr++] = 0x4A;
-                       __u8 *len = event+(bptr++);
+                       uint8_t *len = event+(bptr++);
                        event[bptr++] = (i->tsid & 0xFF00) >> 8;
                        event[bptr++] = (i->tsid & 0xFF);
                        event[bptr++] = (i->onid & 0xFF00) >> 8;
                        event[bptr++] = (i->tsid & 0xFF00) >> 8;
                        event[bptr++] = (i->tsid & 0xFF);
                        event[bptr++] = (i->onid & 0xFF00) >> 8;
@@ -2839,12 +3677,12 @@ void eEPGCache::privateSectionRead(const uniqueEPGKey &current_service, const __
                while( tmMap.find(stime) != tmMap.end() )
                        ++stime;
                event[6] += (stime - it->first.tm);
                while( tmMap.find(stime) != tmMap.end() )
                        ++stime;
                event[6] += (stime - it->first.tm);
-               __u16 event_id = 0;
+               uint16_t event_id = 0;
                while( evMap.find(event_id) != evMap.end() )
                        ++event_id;
                event[0] = (event_id & 0xFF00) >> 8;
                event[1] = (event_id & 0xFF);
                while( evMap.find(event_id) != evMap.end() )
                        ++event_id;
                event[0] = (event_id & 0xFF00) >> 8;
                event[1] = (event_id & 0xFF);
-               time_event_map[it->first.tm]=std::pair<time_t, __u16>(stime, event_id);
+               time_event_map[it->first.tm]=std::pair<time_t, uint16_t>(stime, event_id);
                eventData *d = new eventData( ev_struct, bptr, PRIVATE );
                evMap[event_id] = d;
                tmMap[stime] = d;
                eventData *d = new eventData( ev_struct, bptr, PRIVATE );
                evMap[event_id] = d;
                tmMap[stime] = d;
@@ -2860,7 +3698,7 @@ void eEPGCache::channel_data::startPrivateReader()
        mask.flags = eDVBSectionFilterMask::rfCRC;
        mask.data[0] = 0xA0;
        mask.mask[0] = 0xFF;
        mask.flags = eDVBSectionFilterMask::rfCRC;
        mask.data[0] = 0xA0;
        mask.mask[0] = 0xFF;
-       eDebug("[EPGC] start privatefilter for pid %04x and version %d", m_PrivatePid, m_PrevVersion);
+       eDebug("[eEPGCache] start privatefilter for pid %04x and version %d", m_PrivatePid, m_PrevVersion);
        if (m_PrevVersion != -1)
        {
                mask.data[3] = m_PrevVersion << 1;
        if (m_PrevVersion != -1)
        {
                mask.data[3] = m_PrevVersion << 1;
@@ -2873,7 +3711,7 @@ void eEPGCache::channel_data::startPrivateReader()
        m_PrivateReader->start(mask);
 }
 
        m_PrivateReader->start(mask);
 }
 
-void eEPGCache::channel_data::readPrivateData( const __u8 *data)
+void eEPGCache::channel_data::readPrivateData( const uint8_t *data)
 {
        if ( seenPrivateSections.find(data[6]) == seenPrivateSections.end() )
        {
 {
        if ( seenPrivateSections.find(data[6]) == seenPrivateSections.end() )
        {
@@ -2882,7 +3720,7 @@ void eEPGCache::channel_data::readPrivateData( const __u8 *data)
        }
        if ( seenPrivateSections.size() == (unsigned int)(data[7] + 1) )
        {
        }
        if ( seenPrivateSections.size() == (unsigned int)(data[7] + 1) )
        {
-               eDebug("[EPGC] private finished");
+               eDebug("[eEPGCache] private finished");
                eDVBChannelID chid = channel->getChannelID();
                int tmp = chid.original_network_id.get();
                tmp |= 0x80000000; // we use highest bit as private epg indicator
                eDVBChannelID chid = channel->getChannelID();
                int tmp = chid.original_network_id.get();
                tmp |= 0x80000000; // we use highest bit as private epg indicator
@@ -2896,15 +3734,16 @@ void eEPGCache::channel_data::readPrivateData( const __u8 *data)
 #endif // ENABLE_PRIVATE_EPG
 
 #ifdef ENABLE_MHW_EPG
 #endif // ENABLE_PRIVATE_EPG
 
 #ifdef ENABLE_MHW_EPG
-void eEPGCache::channel_data::cleanup()
+void eEPGCache::channel_data::cleanupMHW()
 {
 {
+       m_MHWTimeoutTimer->stop();
        m_channels.clear();
        m_themes.clear();
        m_titles.clear();
        m_program_ids.clear();
 }
 
        m_channels.clear();
        m_themes.clear();
        m_titles.clear();
        m_program_ids.clear();
 }
 
-__u8 *eEPGCache::channel_data::delimitName( __u8 *in, __u8 *out, int len_in )
+uint8_t *eEPGCache::channel_data::delimitName( uint8_t *in, uint8_t *out, int len_in )
 {
        // Names in mhw structs are not strings as they are not '\0' terminated.
        // This function converts the mhw name into a string.
 {
        // Names in mhw structs are not strings as they are not '\0' terminated.
        // This function converts the mhw name into a string.
@@ -2939,7 +3778,7 @@ void eEPGCache::channel_data::timeMHW2DVB( u_char day, u_char hours, u_char minu
 {
        char tz_saved[1024];
        // Remove offset in mhw time.
 {
        char tz_saved[1024];
        // Remove offset in mhw time.
-       __u8 local_hours = hours;
+       uint8_t local_hours = hours;
        if ( hours >= 16 )
                local_hours -= 4;
        else if ( hours >= 8 )
        if ( hours >= 16 )
                local_hours -= 4;
        else if ( hours >= 8 )
@@ -2952,7 +3791,7 @@ void eEPGCache::channel_data::timeMHW2DVB( u_char day, u_char hours, u_char minu
        char *old_tz = getenv( "TZ" );
        if (old_tz)
                strcpy(tz_saved, old_tz);
        char *old_tz = getenv( "TZ" );
        if (old_tz)
                strcpy(tz_saved, old_tz);
-       putenv("TZ=CET-1CEST,M3.5.0/2,M10.5.0/3");
+       putenv((char*)"TZ=CET-1CEST,M3.5.0/2,M10.5.0/3");
        tzset();
 
        tm localnow;
        tzset();
 
        tm localnow;
@@ -2990,10 +3829,10 @@ void eEPGCache::channel_data::timeMHW2DVB( u_char day, u_char hours, u_char minu
        timeMHW2DVB( recdate.tm_hour, minutes, return_time+2 );
 }
 
        timeMHW2DVB( recdate.tm_hour, minutes, return_time+2 );
 }
 
-void eEPGCache::channel_data::storeTitle(std::map<__u32, mhw_title_t>::iterator itTitle, std::string sumText, const __u8 *data)
+void eEPGCache::channel_data::storeMHWTitle(std::map<uint32_t, mhw_title_t>::iterator itTitle, std::string sumText, const uint8_t *data)
 // data is borrowed from calling proc to save memory space.
 {
 // data is borrowed from calling proc to save memory space.
 {
-       __u8 name[34];
+       uint8_t name[34];
 
        // For each title a separate EIT packet will be sent to eEPGCache::sectionRead()
        bool isMHW2 = itTitle->second.mhw2_mjd_hi || itTitle->second.mhw2_mjd_lo ||
 
        // For each title a separate EIT packet will be sent to eEPGCache::sectionRead()
        bool isMHW2 = itTitle->second.mhw2_mjd_hi || itTitle->second.mhw2_mjd_lo ||
@@ -3016,7 +3855,7 @@ void eEPGCache::channel_data::storeTitle(std::map<__u32, mhw_title_t>::iterator
        packet->segment_last_section_number = 0; // eEPGCache::sectionRead() will dig this for the moment
        packet->segment_last_table_id = 0x50;
 
        packet->segment_last_section_number = 0; // eEPGCache::sectionRead() will dig this for the moment
        packet->segment_last_table_id = 0x50;
 
-       __u8 *title = isMHW2 ? ((__u8*)(itTitle->second.title))-4 : (__u8*)itTitle->second.title;
+       uint8_t *title = isMHW2 ? ((uint8_t*)(itTitle->second.title))-4 : (uint8_t*)itTitle->second.title;
        std::string prog_title = (char *) delimitName( title, name, isMHW2 ? 35 : 23 );
        int prog_title_length = prog_title.length();
 
        std::string prog_title = (char *) delimitName( title, name, isMHW2 ? 35 : 23 );
        int prog_title_length = prog_title.length();
 
@@ -3035,13 +3874,13 @@ void eEPGCache::channel_data::storeTitle(std::map<__u32, mhw_title_t>::iterator
                data[4] = itTitle->second.mhw2_hours;
                data[5] = itTitle->second.mhw2_minutes;
                data[6] = itTitle->second.mhw2_seconds;
                data[4] = itTitle->second.mhw2_hours;
                data[5] = itTitle->second.mhw2_minutes;
                data[6] = itTitle->second.mhw2_seconds;
-               timeMHW2DVB( HILO(itTitle->second.mhw2_duration), data+7 );
+               timeMHW2DVB( itTitle->second.getMhw2Duration(), data+7 );
        }
        else
        {
                timeMHW2DVB( itTitle->second.dh.day, itTitle->second.dh.hours, itTitle->second.ms.minutes,
                (u_char *) event_data + 2 );
        }
        else
        {
                timeMHW2DVB( itTitle->second.dh.day, itTitle->second.dh.hours, itTitle->second.ms.minutes,
                (u_char *) event_data + 2 );
-               timeMHW2DVB( HILO(itTitle->second.duration), (u_char *) event_data+7 );
+               timeMHW2DVB( itTitle->second.getDuration(), (u_char *) event_data+7 );
        }
 
        event_data->running_status = 0;
        }
 
        event_data->running_status = 0;
@@ -3136,21 +3975,21 @@ void eEPGCache::channel_data::storeTitle(std::map<__u32, mhw_title_t>::iterator
        cache->sectionRead( data, MHW, this );
 }
 
        cache->sectionRead( data, MHW, this );
 }
 
-void eEPGCache::channel_data::startTimeout(int msec)
+void eEPGCache::channel_data::startMHWTimeout(int msec)
 {
        m_MHWTimeoutTimer->start(msec,true);
        m_MHWTimeoutet=false;
 }
 
 {
        m_MHWTimeoutTimer->start(msec,true);
        m_MHWTimeoutet=false;
 }
 
-void eEPGCache::channel_data::startMHWReader(__u16 pid, __u8 tid)
+void eEPGCache::channel_data::startMHWReader(uint16_t pid, uint8_t tid)
 {
        m_MHWFilterMask.pid = pid;
        m_MHWFilterMask.data[0] = tid;
        m_MHWReader->start(m_MHWFilterMask);
 {
        m_MHWFilterMask.pid = pid;
        m_MHWFilterMask.data[0] = tid;
        m_MHWReader->start(m_MHWFilterMask);
-//     eDebug("start 0x%02x 0x%02x", pid, tid);
+//     eDebug("[eEPGCache] start 0x%02x 0x%02x", pid, tid);
 }
 
 }
 
-void eEPGCache::channel_data::startMHWReader2(__u16 pid, __u8 tid, int ext)
+void eEPGCache::channel_data::startMHWReader2(uint16_t pid, uint8_t tid, int ext)
 {
        m_MHWFilterMask2.pid = pid;
        m_MHWFilterMask2.data[0] = tid;
 {
        m_MHWFilterMask2.pid = pid;
        m_MHWFilterMask2.data[0] = tid;
@@ -3158,18 +3997,18 @@ void eEPGCache::channel_data::startMHWReader2(__u16 pid, __u8 tid, int ext)
        {
                m_MHWFilterMask2.data[1] = ext;
                m_MHWFilterMask2.mask[1] = 0xFF;
        {
                m_MHWFilterMask2.data[1] = ext;
                m_MHWFilterMask2.mask[1] = 0xFF;
-//             eDebug("start 0x%03x 0x%02x 0x%02x", pid, tid, ext);
+//             eDebug("[eEPGCache] start 0x%03x 0x%02x 0x%02x", pid, tid, ext);
        }
        else
        {
                m_MHWFilterMask2.data[1] = 0;
                m_MHWFilterMask2.mask[1] = 0;
        }
        else
        {
                m_MHWFilterMask2.data[1] = 0;
                m_MHWFilterMask2.mask[1] = 0;
-//             eDebug("start 0x%02x 0x%02x", pid, tid);
+//             eDebug("[eEPGCache] start 0x%02x 0x%02x", pid, tid);
        }
        m_MHWReader2->start(m_MHWFilterMask2);
 }
 
        }
        m_MHWReader2->start(m_MHWFilterMask2);
 }
 
-void eEPGCache::channel_data::readMHWData(const __u8 *data)
+void eEPGCache::channel_data::readMHWData(const uint8_t *data)
 {
        if ( m_MHWReader2 )
                m_MHWReader2->stop();
 {
        if ( m_MHWReader2 )
                m_MHWReader2->stop();
@@ -3178,7 +4017,7 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data)
                // have si data.. so we dont read mhw data
                (haveData & (SCHEDULE|SCHEDULE_OTHER|VIASAT)) )
        {
                // have si data.. so we dont read mhw data
                (haveData & (SCHEDULE|SCHEDULE_OTHER|VIASAT)) )
        {
-               eDebug("[EPGC] mhw aborted %d", state);
+               eDebug("[eEPGCache] mhw aborted %d", state);
        }
        else if (m_MHWFilterMask.pid == 0xD3 && m_MHWFilterMask.data[0] == 0x91)
        // Channels table
        }
        else if (m_MHWFilterMask.pid == 0xD3 && m_MHWFilterMask.data[0] == 0x91)
        // Channels table
@@ -3195,7 +4034,7 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data)
                }
                haveData |= MHW;
 
                }
                haveData |= MHW;
 
-               eDebug("[EPGC] mhw %d channels found", m_channels.size());
+               eDebug("[eEPGCache] mhw %d channels found", m_channels.size());
 
                // Channels table has been read, start reading the themes table.
                startMHWReader(0xD3, 0x92);
 
                // Channels table has been read, start reading the themes table.
                startMHWReader(0xD3, 0x92);
@@ -3208,9 +4047,9 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data)
                int record_size = sizeof( mhw_theme_name_t );
                int nbr_records = int (len/record_size);
                int idx_ptr = 0;
                int record_size = sizeof( mhw_theme_name_t );
                int nbr_records = int (len/record_size);
                int idx_ptr = 0;
-               __u8 next_idx = (__u8) *(data + 3 + idx_ptr);
-               __u8 idx = 0;
-               __u8 sub_idx = 0;
+               uint8_t next_idx = (uint8_t) *(data + 3 + idx_ptr);
+               uint8_t idx = 0;
+               uint8_t sub_idx = 0;
                for ( int i = 0; i < nbr_records; i++ )
                {
                        mhw_theme_name_t *theme = (mhw_theme_name_t*) &data[19 + i*record_size];
                for ( int i = 0; i < nbr_records; i++ )
                {
                        mhw_theme_name_t *theme = (mhw_theme_name_t*) &data[19 + i*record_size];
@@ -3218,7 +4057,7 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data)
                        {
                                idx = (idx_ptr<<4);
                                idx_ptr++;
                        {
                                idx = (idx_ptr<<4);
                                idx_ptr++;
-                               next_idx = (__u8) *(data + 3 + idx_ptr);
+                               next_idx = (uint8_t) *(data + 3 + idx_ptr);
                                sub_idx = 0;
                        }
                        else
                                sub_idx = 0;
                        }
                        else
@@ -3226,30 +4065,32 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data)
 
                        m_themes[idx+sub_idx] = *theme;
                }
 
                        m_themes[idx+sub_idx] = *theme;
                }
-               eDebug("[EPGC] mhw %d themes found", m_themes.size());
+               eDebug("[eEPGCache] mhw %d themes found", m_themes.size());
                // Themes table has been read, start reading the titles table.
                startMHWReader(0xD2, 0x90);
                // Themes table has been read, start reading the titles table.
                startMHWReader(0xD2, 0x90);
-               startTimeout(4000);
+               startMHWTimeout(4000);
                return;
        }
        else if (m_MHWFilterMask.pid == 0xD2 && m_MHWFilterMask.data[0] == 0x90)
        // Titles table
        {
                mhw_title_t *title = (mhw_title_t*) data;
                return;
        }
        else if (m_MHWFilterMask.pid == 0xD2 && m_MHWFilterMask.data[0] == 0x90)
        // Titles table
        {
                mhw_title_t *title = (mhw_title_t*) data;
+               uint8_t name[24];
+               std::string prog_title = (char *) delimitName( title->title, name, 23 );
 
 
-               if ( title->channel_id == 0xFF )        // Separator
+               if ( title->channel_id == 0xFF || prog_title.substr(0,7) == "BIENTOT" ) // Separator or BIENTOT record
                        return; // Continue reading of the current table.
                else
                {
                        // Create unique key per title
                        return; // Continue reading of the current table.
                else
                {
                        // Create unique key per title
-                       __u32 title_id = ((title->channel_id)<<16)|((title->dh.day)<<13)|((title->dh.hours)<<8)|
+                       uint32_t title_id = ((title->channel_id)<<16)|((title->dh.day)<<13)|((title->dh.hours)<<8)|
                                (title->ms.minutes);
                                (title->ms.minutes);
-                       __u32 program_id = ((title->program_id_hi)<<24)|((title->program_id_mh)<<16)|
+                       uint32_t program_id = ((title->program_id_hi)<<24)|((title->program_id_mh)<<16)|
                                ((title->program_id_ml)<<8)|(title->program_id_lo);
 
                        if ( m_titles.find( title_id ) == m_titles.end() )
                        {
                                ((title->program_id_ml)<<8)|(title->program_id_lo);
 
                        if ( m_titles.find( title_id ) == m_titles.end() )
                        {
-                               startTimeout(4000);
+                               startMHWTimeout(4000);
                                title->mhw2_mjd_hi = 0;
                                title->mhw2_mjd_lo = 0;
                                title->mhw2_duration_hi = 0;
                                title->mhw2_mjd_hi = 0;
                                title->mhw2_mjd_lo = 0;
                                title->mhw2_duration_hi = 0;
@@ -3257,10 +4098,10 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data)
                                m_titles[ title_id ] = *title;
                                if ( (title->ms.summary_available) && (m_program_ids.find(program_id) == m_program_ids.end()) )
                                        // program_ids will be used to gather summaries.
                                m_titles[ title_id ] = *title;
                                if ( (title->ms.summary_available) && (m_program_ids.find(program_id) == m_program_ids.end()) )
                                        // program_ids will be used to gather summaries.
-                                       m_program_ids.insert(std::pair<__u32,__u32>(program_id,title_id));
+                                       m_program_ids.insert(std::pair<uint32_t,uint32_t>(program_id,title_id));
                                return; // Continue reading of the current table.
                        }
                                return; // Continue reading of the current table.
                        }
-                       else if (!checkTimeout())
+                       else if (!checkMHWTimeout())
                                return;
                }
                if ( !m_program_ids.empty())
                                return;
                }
                if ( !m_program_ids.empty())
@@ -3268,10 +4109,10 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data)
                        // Titles table has been read, there are summaries to read.
                        // Start reading summaries, store corresponding titles on the fly.
                        startMHWReader(0xD3, 0x90);
                        // Titles table has been read, there are summaries to read.
                        // Start reading summaries, store corresponding titles on the fly.
                        startMHWReader(0xD3, 0x90);
-                       eDebug("[EPGC] mhw %d titles(%d with summary) found",
+                       eDebug("[eEPGCache] mhw %d titles(%d with summary) found",
                                m_titles.size(),
                                m_program_ids.size());
                                m_titles.size(),
                                m_program_ids.size());
-                       startTimeout(4000);
+                       startMHWTimeout(4000);
                        return;
                }
        }
                        return;
                }
        }
@@ -3281,20 +4122,20 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data)
                mhw_summary_t *summary = (mhw_summary_t*) data;
 
                // Create unique key per record
                mhw_summary_t *summary = (mhw_summary_t*) data;
 
                // Create unique key per record
-               __u32 program_id = ((summary->program_id_hi)<<24)|((summary->program_id_mh)<<16)|
+               uint32_t program_id = ((summary->program_id_hi)<<24)|((summary->program_id_mh)<<16)|
                        ((summary->program_id_ml)<<8)|(summary->program_id_lo);
                int len = ((data[1]&0xf)<<8) + data[2];
 
                        ((summary->program_id_ml)<<8)|(summary->program_id_lo);
                int len = ((data[1]&0xf)<<8) + data[2];
 
-               // ugly workaround to convert const __u8* to char*
+               // ugly workaround to convert const uint8_t* to char*
                char *tmp=0;
                memcpy(&tmp, &data, sizeof(void*));
                tmp[len+3] = 0; // Terminate as a string.
 
                char *tmp=0;
                memcpy(&tmp, &data, sizeof(void*));
                tmp[len+3] = 0; // Terminate as a string.
 
-               std::multimap<__u32, __u32>::iterator itProgid( m_program_ids.find( program_id ) );
+               std::multimap<uint32_t, uint32_t>::iterator itProgid( m_program_ids.find( program_id ) );
                if ( itProgid == m_program_ids.end() )
                { /*    This part is to prevent to looping forever if some summaries are not received yet.
                        There is a timeout of 4 sec. after the last successfully read summary. */
                if ( itProgid == m_program_ids.end() )
                { /*    This part is to prevent to looping forever if some summaries are not received yet.
                        There is a timeout of 4 sec. after the last successfully read summary. */
-                       if (!m_program_ids.empty() && !checkTimeout())
+                       if (!m_program_ids.empty() && !checkMHWTimeout())
                                return; // Continue reading of the current table.
                }
                else
                                return; // Continue reading of the current table.
                }
                else
@@ -3306,11 +4147,11 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data)
                                the_text.replace(pos, 2, " ");
 
                        // Find corresponding title, store title and summary in epgcache.
                                the_text.replace(pos, 2, " ");
 
                        // Find corresponding title, store title and summary in epgcache.
-                       std::map<__u32, mhw_title_t>::iterator itTitle( m_titles.find( itProgid->second ) );
+                       std::map<uint32_t, mhw_title_t>::iterator itTitle( m_titles.find( itProgid->second ) );
                        if ( itTitle != m_titles.end() )
                        {
                        if ( itTitle != m_titles.end() )
                        {
-                               startTimeout(4000);
-                               storeTitle( itTitle, the_text, data );
+                               startMHWTimeout(4000);
+                               storeMHWTitle( itTitle, the_text, data );
                                m_titles.erase( itTitle );
                        }
                        m_program_ids.erase( itProgid );
                                m_titles.erase( itTitle );
                        }
                        m_program_ids.erase( itProgid );
@@ -3318,13 +4159,13 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data)
                                return; // Continue reading of the current table.
                }
        }
                                return; // Continue reading of the current table.
                }
        }
-       eDebug("[EPGC] mhw finished(%ld) %d summaries not found",
+       eDebug("[eEPGCache] mhw finished(%ld) %d summaries not found",
                ::time(0),
                m_program_ids.size());
        // Summaries have been read, titles that have summaries have been stored.
        // Now store titles that do not have summaries.
                ::time(0),
                m_program_ids.size());
        // Summaries have been read, titles that have summaries have been stored.
        // Now store titles that do not have summaries.
-       for (std::map<__u32, mhw_title_t>::iterator itTitle(m_titles.begin()); itTitle != m_titles.end(); itTitle++)
-               storeTitle( itTitle, "", data );
+       for (std::map<uint32_t, mhw_title_t>::iterator itTitle(m_titles.begin()); itTitle != m_titles.end(); itTitle++)
+               storeMHWTitle( itTitle, "", data );
        isRunning &= ~MHW;
        m_MHWConn=0;
        if ( m_MHWReader )
        isRunning &= ~MHW;
        m_MHWConn=0;
        if ( m_MHWReader )
@@ -3333,7 +4174,7 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data)
                finishEPG();
 }
 
                finishEPG();
 }
 
-void eEPGCache::channel_data::readMHWData2(const __u8 *data)
+void eEPGCache::channel_data::readMHWData2(const uint8_t *data)
 {
        int dataLen = (((data[1]&0xf) << 8) | data[2]) + 3;
 
 {
        int dataLen = (((data[1]&0xf) << 8) | data[2]) + 3;
 
@@ -3344,7 +4185,7 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data)
                // have si data.. so we dont read mhw data
                (haveData & (SCHEDULE|SCHEDULE_OTHER|VIASAT)) )
        {
                // have si data.. so we dont read mhw data
                (haveData & (SCHEDULE|SCHEDULE_OTHER|VIASAT)) )
        {
-               eDebug("[EPGC] mhw2 aborted %d", state);
+               eDebug("[eEPGCache] mhw2 aborted %d", state);
        }
        else if (m_MHWFilterMask2.pid == m_mhw2_channel_pid && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 0)
        // Channels table
        }
        else if (m_MHWFilterMask2.pid == m_mhw2_channel_pid && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 0)
        // Channels table
@@ -3369,7 +4210,7 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data)
                else
                        goto abort;
                // data seems consistent...
                else
                        goto abort;
                // data seems consistent...
-               const __u8 *tmp = data+121;
+               const uint8_t *tmp = data+121;
                for (int i=0; i < num_channels; ++i)
                {
                        mhw_channel_name_t channel;
                for (int i=0; i < num_channels; ++i)
                {
                        mhw_channel_name_t channel;
@@ -3380,7 +4221,7 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data)
                        channel.channel_id_hi = *(tmp++);
                        channel.channel_id_lo = *(tmp++);
                        m_channels[i]=channel;
                        channel.channel_id_hi = *(tmp++);
                        channel.channel_id_lo = *(tmp++);
                        m_channels[i]=channel;
-//                     eDebug("%d(%02x) %04x: %02x %02x", i, i, (channel.channel_id_hi << 8) | channel.channel_id_lo, *tmp, *(tmp+1));
+//                     eDebug("[eEPGCache] %d(%02x) %04x: %02x %02x", i, i, (channel.channel_id_hi << 8) | channel.channel_id_lo, *tmp, *(tmp+1));
                        tmp+=2;
                }
                for (int i=0; i < num_channels; ++i)
                        tmp+=2;
                }
                for (int i=0; i < num_channels; ++i)
@@ -3391,15 +4232,15 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data)
                        for (; x < channel_name_len; ++x)
                                channel.name[x]=*(tmp++);
                        channel.name[x+1]=0;
                        for (; x < channel_name_len; ++x)
                                channel.name[x]=*(tmp++);
                        channel.name[x+1]=0;
-//                     eDebug("%d(%02x) %s", i, i, channel.name);
+//                     eDebug("[eEPGCache] %d(%02x) %s", i, i, channel.name);
                }
                haveData |= MHW;
                }
                haveData |= MHW;
-               eDebug("[EPGC] mhw2 %d channels found", m_channels.size());
+               eDebug("[eEPGCache] mhw2 %d channels found", m_channels.size());
        }
        else if (m_MHWFilterMask2.pid == m_mhw2_channel_pid && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 1)
        {
                // Themes table
        }
        else if (m_MHWFilterMask2.pid == m_mhw2_channel_pid && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 1)
        {
                // Themes table
-               eDebug("[EPGC] mhw2 themes nyi");
+               eDebug("[eEPGCache] mhw2 themes nyi");
        }
        else if (m_MHWFilterMask2.pid == m_mhw2_title_pid && m_MHWFilterMask2.data[0] == 0xe6)
        // Titles table
        }
        else if (m_MHWFilterMask2.pid == m_mhw2_title_pid && m_MHWFilterMask2.data[0] == 0xe6)
        // Titles table
@@ -3408,7 +4249,7 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data)
                bool valid=false;
                bool finish=false;
 
                bool valid=false;
                bool finish=false;
 
-//             eDebug("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
+//             eDebug("[eEPGCache] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
 //                     data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10],
 //                     data[11], data[12], data[13], data[14], data[15], data[16], data[17] );
 
 //                     data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10],
 //                     data[11], data[12], data[13], data[14], data[15], data[16], data[17] );
 
@@ -3423,11 +4264,11 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data)
                if (!valid)
                {
                        if (dataLen > 18)
                if (!valid)
                {
                        if (dataLen > 18)
-                               eDebug("mhw2 title table invalid!!");
-                       if (checkTimeout())
+                               eDebug("[eEPGCache] mhw2 title table invalid!!");
+                       if (checkMHWTimeout())
                                goto abort;
                        if (!m_MHWTimeoutTimer->isActive())
                                goto abort;
                        if (!m_MHWTimeoutTimer->isActive())
-                               startTimeout(5000);
+                               startMHWTimeout(5000);
                        return; // continue reading
                }
 
                        return; // continue reading
                }
 
@@ -3436,7 +4277,7 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data)
                pos = 18;
                while (pos < dataLen)
                {
                pos = 18;
                while (pos < dataLen)
                {
-//                     eDebugNoNewLine("    [%02x] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x [%02x %02x %02x %02x %02x %02x %02x] LL - DESCR - ",
+//                     eDebugNoNewLine("[eEPGCache]     [%02x] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x [%02x %02x %02x %02x %02x %02x %02x] LL - DESCR - ",
 //                             data[pos], data[pos+1], data[pos+2], data[pos+3], data[pos+4], data[pos+5], data[pos+6], data[pos+7], 
 //                             data[pos+8], data[pos+9], data[pos+10], data[pos+11], data[pos+12], data[pos+13], data[pos+14], data[pos+15], data[pos+16], data[pos+17]);
                        title.channel_id = data[pos]+1;
 //                             data[pos], data[pos+1], data[pos+2], data[pos+3], data[pos+4], data[pos+5], data[pos+6], data[pos+7], 
 //                             data[pos+8], data[pos+9], data[pos+10], data[pos+11], data[pos+12], data[pos+13], data[pos+14], data[pos+15], data[pos+16], data[pos+17]);
                        title.channel_id = data[pos]+1;
@@ -3450,37 +4291,37 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data)
                        title.mhw2_duration_lo = duration&0xFF;
 
                        // Create unique key per title
                        title.mhw2_duration_lo = duration&0xFF;
 
                        // Create unique key per title
-                       __u32 title_id = (data[pos+7] << 24) | (data[pos+8] << 16) | (data[pos+9] << 8) | data[pos+10];
+                       uint32_t title_id = (data[pos+7] << 24) | (data[pos+8] << 16) | (data[pos+9] << 8) | data[pos+10];
 
 
-                       __u8 slen = data[pos+18] & 0x3f;
-                       __u8 *dest = ((__u8*)title.title)-4;
+                       uint8_t slen = data[pos+18] & 0x3f;
+                       uint8_t *dest = ((uint8_t*)title.title)-4;
                        memcpy(dest, &data[pos+19], slen>35 ? 35 : slen);
                        memset(dest+slen, 0, 35-slen);
                        pos += 19 + slen;
 //                     eDebug("%02x [%02x %02x]: %s", data[pos], data[pos+1], data[pos+2], dest);
 
 //                     not used theme id (data[7] & 0x3f) + (data[pos] & 0x3f);
                        memcpy(dest, &data[pos+19], slen>35 ? 35 : slen);
                        memset(dest+slen, 0, 35-slen);
                        pos += 19 + slen;
 //                     eDebug("%02x [%02x %02x]: %s", data[pos], data[pos+1], data[pos+2], dest);
 
 //                     not used theme id (data[7] & 0x3f) + (data[pos] & 0x3f);
-                       __u32 summary_id = (data[pos+1] << 8) | data[pos+2];
+                       uint32_t summary_id = (data[pos+1] << 8) | data[pos+2];
 
 //                     if (title.channel_id > m_channels.size())
 
 //                     if (title.channel_id > m_channels.size())
-//                             eDebug("channel_id(%d %02x) to big!!", title.channel_id);
+//                             eDebug("[eEPGCache] channel_id(%d %02x) to big!!", title.channel_id);
 
 
-//                     eDebug("pos %d prog_id %02x %02x chid %02x summary_id %04x dest %p len %d\n",
+//                     eDebug("[eEPGCache] pos %d prog_id %02x %02x chid %02x summary_id %04x dest %p len %d\n",
 //                             pos, title.program_id_ml, title.program_id_lo, title.channel_id, summary_id, dest, slen);
 
 //                             pos, title.program_id_ml, title.program_id_lo, title.channel_id, summary_id, dest, slen);
 
-//                     eDebug("title_id %08x -> summary_id %04x\n", title_id, summary_id);
+//                     eDebug("[eEPGCache] title_id %08x -> summary_id %04x\n", title_id, summary_id);
 
                        pos += 3;
 
 
                        pos += 3;
 
-                       std::map<__u32, mhw_title_t>::iterator it = m_titles.find( title_id );
+                       std::map<uint32_t, mhw_title_t>::iterator it = m_titles.find( title_id );
                        if ( it == m_titles.end() )
                        {
                        if ( it == m_titles.end() )
                        {
-                               startTimeout(5000);
+                               startMHWTimeout(5000);
                                m_titles[ title_id ] = title;
                                if (summary_id != 0xFFFF)
                                {
                                        bool add=true;
                                m_titles[ title_id ] = title;
                                if (summary_id != 0xFFFF)
                                {
                                        bool add=true;
-                                       std::multimap<__u32, __u32>::iterator it(m_program_ids.lower_bound(summary_id));
+                                       std::multimap<uint32_t, uint32_t>::iterator it(m_program_ids.lower_bound(summary_id));
                                        while (it != m_program_ids.end() && it->first == summary_id)
                                        {
                                                if (it->second == title_id) {
                                        while (it != m_program_ids.end() && it->first == summary_id)
                                        {
                                                if (it->second == title_id) {
@@ -3490,27 +4331,26 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data)
                                                ++it;
                                        }
                                        if (add)
                                                ++it;
                                        }
                                        if (add)
-                                               m_program_ids.insert(std::pair<__u32,__u32>(summary_id,title_id));
+                                               m_program_ids.insert(std::pair<uint32_t,uint32_t>(summary_id,title_id));
                                }
                        }
                        else
                        {
                                }
                        }
                        else
                        {
-                               if ( !checkTimeout() )
+                               if ( !checkMHWTimeout() )
                                        continue;       // Continue reading of the current table.
                                finish=true;
                                break;
                        }
                }
                                        continue;       // Continue reading of the current table.
                                finish=true;
                                break;
                        }
                }
-start_summary:
                if (finish)
                {
                if (finish)
                {
-                       eDebug("[EPGC] mhw2 %d titles(%d with summary) found", m_titles.size(), m_program_ids.size());
+                       eDebug("[eEPGCache] mhw2 %d titles(%d with summary) found", m_titles.size(), m_program_ids.size());
                        if (!m_program_ids.empty())
                        {
                                // Titles table has been read, there are summaries to read.
                                // Start reading summaries, store corresponding titles on the fly.
                                startMHWReader2(m_mhw2_summary_pid, 0x96);
                        if (!m_program_ids.empty())
                        {
                                // Titles table has been read, there are summaries to read.
                                // Start reading summaries, store corresponding titles on the fly.
                                startMHWReader2(m_mhw2_summary_pid, 0x96);
-                               startTimeout(15000);
+                               startMHWTimeout(15000);
                                return;
                        }
                }
                                return;
                        }
                }
@@ -3520,7 +4360,7 @@ start_summary:
        else if (m_MHWFilterMask2.pid == m_mhw2_summary_pid && m_MHWFilterMask2.data[0] == 0x96)
        // Summaries table
        {
        else if (m_MHWFilterMask2.pid == m_mhw2_summary_pid && m_MHWFilterMask2.data[0] == 0x96)
        // Summaries table
        {
-               if (!checkTimeout())
+               if (!checkMHWTimeout())
                {
                        int len, loop, pos, lenline;
                        bool valid;
                {
                        int len, loop, pos, lenline;
                        bool valid;
@@ -3555,11 +4395,11 @@ start_summary:
                        if (valid)
                        {
                                // data seems consistent...
                        if (valid)
                        {
                                // data seems consistent...
-                               __u32 summary_id = (data[3]<<8)|data[4];
-//                             eDebug ("summary id %04x\n", summary_id);
-//                             eDebug("[%02x %02x] %02x %02x %02x %02x %02x %02x %02x %02x XX\n", data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12], data[13] );
+                               uint32_t summary_id = (data[3]<<8)|data[4];
+//                             eDebug ("[eEPGCache] summary id %04x\n", summary_id);
+//                             eDebug("[eEPGCache] [%02x %02x] %02x %02x %02x %02x %02x %02x %02x %02x XX\n", data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12], data[13] );
 
 
-                               // ugly workaround to convert const __u8* to char*
+                               // ugly workaround to convert const uint8_t* to char*
                                char *tmp=0;
                                memcpy(&tmp, &data, sizeof(void*));
 
                                char *tmp=0;
                                memcpy(&tmp, &data, sizeof(void*));
 
@@ -3579,7 +4419,7 @@ start_summary:
                                else
                                        tmp[pos+1] = 0;
 
                                else
                                        tmp[pos+1] = 0;
 
-                               std::multimap<__u32, __u32>::iterator itProgId( m_program_ids.lower_bound(summary_id) );
+                               std::multimap<uint32_t, uint32_t>::iterator itProgId( m_program_ids.lower_bound(summary_id) );
                                if ( itProgId == m_program_ids.end() || itProgId->first != summary_id)
                                { /*    This part is to prevent to looping forever if some summaries are not received yet.
                                        There is a timeout of 4 sec. after the last successfully read summary. */
                                if ( itProgId == m_program_ids.end() || itProgId->first != summary_id)
                                { /*    This part is to prevent to looping forever if some summaries are not received yet.
                                        There is a timeout of 4 sec. after the last successfully read summary. */
@@ -3588,19 +4428,19 @@ start_summary:
                                }
                                else
                                {
                                }
                                else
                                {
-                                       startTimeout(15000);
+                                       startMHWTimeout(15000);
                                        std::string the_text = (char *) (data + pos + 1);
 
                                        std::string the_text = (char *) (data + pos + 1);
 
-//                                     eDebug ("summary id %04x : %s\n", summary_id, data+pos+1);
+//                                     eDebug ("[eEPGCache] summary id %04x : %s\n", summary_id, data+pos+1);
 
                                        while( itProgId != m_program_ids.end() && itProgId->first == summary_id )
                                        {
 
                                        while( itProgId != m_program_ids.end() && itProgId->first == summary_id )
                                        {
-//                                             eDebug(".");
+//                                             eDebug("[eEPGCache] .");
                                                // Find corresponding title, store title and summary in epgcache.
                                                // Find corresponding title, store title and summary in epgcache.
-                                               std::map<__u32, mhw_title_t>::iterator itTitle( m_titles.find( itProgId->second ) );
+                                               std::map<uint32_t, mhw_title_t>::iterator itTitle( m_titles.find( itProgId->second ) );
                                                if ( itTitle != m_titles.end() )
                                                {
                                                if ( itTitle != m_titles.end() )
                                                {
-                                                       storeTitle( itTitle, the_text, data );
+                                                       storeMHWTitle( itTitle, the_text, data );
                                                        m_titles.erase( itTitle );
                                                }
                                                m_program_ids.erase( itProgId++ );
                                                        m_titles.erase( itTitle );
                                                }
                                                m_program_ids.erase( itProgId++ );
@@ -3631,9 +4471,9 @@ start_summary:
                {
                        // Summaries have been read, titles that have summaries have been stored.
                        // Now store titles that do not have summaries.
                {
                        // Summaries have been read, titles that have summaries have been stored.
                        // Now store titles that do not have summaries.
-                       for (std::map<__u32, mhw_title_t>::iterator itTitle(m_titles.begin()); itTitle != m_titles.end(); itTitle++)
-                               storeTitle( itTitle, "", data );
-                       eDebug("[EPGC] mhw2 finished(%ld) %d summaries not found",
+                       for (std::map<uint32_t, mhw_title_t>::iterator itTitle(m_titles.begin()); itTitle != m_titles.end(); itTitle++)
+                               storeMHWTitle( itTitle, "", data );
+                       eDebug("[eEPGCache] mhw2 finished(%ld) %d summaries not found",
                                ::time(0),
                                m_program_ids.size());
                }
                                ::time(0),
                                m_program_ids.size());
                }
index 90aff6c..2b47977 100644 (file)
@@ -2,32 +2,20 @@
 #define __epgcache_h_
 
 #define ENABLE_PRIVATE_EPG 1
 #define __epgcache_h_
 
 #define ENABLE_PRIVATE_EPG 1
-//#define ENABLE_MHW_EPG 1
+#define ENABLE_MHW_EPG 1
+#define ENABLE_FREESAT 1
+#define ENABLE_NETMED 1
+#define ENABLE_VIRGIN 1
 
 #ifndef SWIG
 
 
 #ifndef SWIG
 
-/* Test for gcc >= maj.min, as per __GNUC_PREREQ in glibc */
-#if defined (__GNUC__) && defined (__GNUC_MINOR__)
-#define __GNUC_PREREQ(maj, min) \
-         ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
-#else
-#define __GNUC_PREREQ(maj, min)  0
-#endif
-
 #include <vector>
 #include <list>
 #include <vector>
 #include <list>
-#if 0 && __GNUC_PREREQ(4,3)
-#include <unordered_map>
-#include <unordered_set>
-#else
-#include <ext/hash_map>
-#include <ext/hash_set>
-#endif
+#include <tr1/unordered_map>
 
 #include <errno.h>
 
 #include <lib/dvb/eit.h>
 
 #include <errno.h>
 
 #include <lib/dvb/eit.h>
-#include <lib/dvb/lowlevel/eit.h>
 #ifdef ENABLE_MHW_EPG
 #include <lib/dvb/lowlevel/mhw.h>
 #endif
 #ifdef ENABLE_MHW_EPG
 #include <lib/dvb/lowlevel/mhw.h>
 #endif
 #include <lib/service/event.h>
 #include <lib/python/python.h>
 
 #include <lib/service/event.h>
 #include <lib/python/python.h>
 
-#define CLEAN_INTERVAL 60000    //  1 min
-#define UPDATE_INTERVAL 3600000  // 60 min
-#define ZAP_DELAY 2000          // 2 sek
-
-#define HILO(x) (x##_hi << 8 | x##_lo)
-
 class eventData;
 class eServiceReferenceDVB;
 class eDVBServicePMTHandler;
 class eventData;
 class eServiceReferenceDVB;
 class eDVBServicePMTHandler;
@@ -69,32 +51,39 @@ struct uniqueEPGKey
        }
        bool operator <(const uniqueEPGKey &a) const
        {
        }
        bool operator <(const uniqueEPGKey &a) const
        {
-               return memcmp( &sid, &a.sid, sizeof(int)*3)<0;
+               if (sid < a.sid)
+                       return true;
+               if (sid != a.sid)
+                       return false;
+               if (onid < a.onid)
+                       return true;
+               if (onid != a.onid)
+                       return false;
+               return (tsid < a.tsid);
        }
        operator bool() const
        }
        operator bool() const
-       { 
-               return !(sid == -1 && onid == -1 && tsid == -1); 
+       {
+               return !(sid == -1 && onid == -1 && tsid == -1);
        }
        bool operator==(const uniqueEPGKey &a) const
        {
        }
        bool operator==(const uniqueEPGKey &a) const
        {
-               return !memcmp( &sid, &a.sid, sizeof(int)*3);
+               return (tsid == a.tsid) && (onid == a.onid) && (sid == a.sid);
        }
        struct equal
        {
                bool operator()(const uniqueEPGKey &a, const uniqueEPGKey &b) const
                {
        }
        struct equal
        {
                bool operator()(const uniqueEPGKey &a, const uniqueEPGKey &b) const
                {
-                       return !memcmp( &a.sid, &b.sid, sizeof(int)*3);
+                       return (a.tsid == b.tsid) && (a.onid == b.onid) && (a.sid == b.sid);
                }
        };
 };
 
 //eventMap is sorted by event_id
                }
        };
 };
 
 //eventMap is sorted by event_id
-#define eventMap std::map<__u16, eventData*>
+typedef std::map<uint16_t, eventData*> eventMap;
 //timeMap is sorted by beginTime
 //timeMap is sorted by beginTime
-#define timeMap std::map<time_t, eventData*>
+typedef std::map<time_t, eventData*> timeMap;
 
 
-#define channelMapIterator std::map<iDVBChannel*, channel_data*>::iterator
-#define updateMap std::map<eDVBChannelID, time_t>
+typedef std::map<eDVBChannelID, time_t> updateMap;
 
 struct hash_uniqueEPGKey
 {
 
 struct hash_uniqueEPGKey
 {
@@ -104,65 +93,38 @@ struct hash_uniqueEPGKey
        }
 };
 
        }
 };
 
-#define tidMap std::set<__u32>
-#if 0 && __GNUC_PREREQ(4,3)
-       #define eventCache std::unordered_map<uniqueEPGKey, std::pair<eventMap, timeMap>, hash_uniqueEPGKey, uniqueEPGKey::equal>
-       #ifdef ENABLE_PRIVATE_EPG
-               #define contentTimeMap std::unordered_map<time_t, std::pair<time_t, __u16> >
-               #define contentMap std::unordered_map<int, contentTimeMap >
-               #define contentMaps std::unordered_map<uniqueEPGKey, contentMap, hash_uniqueEPGKey, uniqueEPGKey::equal >
-       #endif
-#elif __GNUC_PREREQ(3,1)
-       #define eventCache __gnu_cxx::hash_map<uniqueEPGKey, std::pair<eventMap, timeMap>, hash_uniqueEPGKey, uniqueEPGKey::equal>
-       #ifdef ENABLE_PRIVATE_EPG
-               #define contentTimeMap __gnu_cxx::hash_map<time_t, std::pair<time_t, __u16> >
-               #define contentMap __gnu_cxx::hash_map<int, contentTimeMap >
-               #define contentMaps __gnu_cxx::hash_map<uniqueEPGKey, contentMap, hash_uniqueEPGKey, uniqueEPGKey::equal >
-       #endif
-#else // for older gcc use following
-       #define eventCache std::hash_map<uniqueEPGKey, std::pair<eventMap, timeMap>, hash_uniqueEPGKey, uniqueEPGKey::equal >
-       #ifdef ENABLE_PRIVATE_EPG
-               #define contentTimeMap std::hash_map<time_t, std::pair<time_t, __u16> >
-               #define contentMap std::hash_map<int, contentTimeMap >
-               #define contentMaps std::hash_map<uniqueEPGKey, contentMap, hash_uniqueEPGKey, uniqueEPGKey::equal>
-       #endif
+struct EventCacheItem {
+       eventMap byEvent;
+       timeMap byTime;
+};
+
+typedef std::set<uint32_t> tidMap;
+
+typedef std::tr1::unordered_map<uniqueEPGKey, EventCacheItem, hash_uniqueEPGKey, uniqueEPGKey::equal> eventCache;
+#ifdef ENABLE_PRIVATE_EPG
+       typedef std::tr1::unordered_map<time_t, std::pair<time_t, uint16_t> > contentTimeMap;
+       typedef std::tr1::unordered_map<int, contentTimeMap > contentMap;
+       typedef std::tr1::unordered_map<uniqueEPGKey, contentMap, hash_uniqueEPGKey, uniqueEPGKey::equal > contentMaps;
 #endif
 
 #endif
 
-#define descriptorPair std::pair<int,__u8*>
-#define descriptorMap std::map<__u32, descriptorPair >
+#endif
 
 
-class eventData
+#ifdef ENABLE_FREESAT
+#include <bitset>
+class freesatEITSubtableStatus
 {
 {
-       friend class eEPGCache;
 private:
 private:
-       __u8* EITdata;
-       __u8 ByteSize;
-       __u8 type;
-       static descriptorMap descriptors;
-       static __u8 data[4108];
-       static int CacheSize;
-       static void load(FILE *);
-       static void save(FILE *);
+       u_char version;
+       uint16_t sectionMap[32];
+       void initMap(uint8_t maxSection);
+
 public:
 public:
-       eventData(const eit_event_struct* e=NULL, int size=0, int type=0);
-       ~eventData();
-       const eit_event_struct* get() const;
-       operator const eit_event_struct*() const
-       {
-               return get();
-       }
-       int getEventID()
-       {
-               return (EITdata[0] << 8) | EITdata[1];
-       }
-       time_t getStartTime()
-       {
-               return parseDVBtime(EITdata[2], EITdata[3], EITdata[4], EITdata[5], EITdata[6]);
-       }
-       int getDuration()
-       {
-               return fromBCD(EITdata[7])*3600+fromBCD(EITdata[8])*60+fromBCD(EITdata[9]);
-       }
+       freesatEITSubtableStatus(u_char version, uint8_t maxSection);
+       bool isSectionPresent(uint8_t sectionNo);
+       void seen(uint8_t sectionNo, uint8_t maxSegmentSection);
+       bool isVersionChanged(u_char testVersion);
+       void updateVersion(u_char newVersion, uint8_t maxSection);
+       bool isCompleted();
 };
 #endif
 
 };
 #endif
 
@@ -178,11 +140,27 @@ class eEPGCache: public eMainloop, private eThread, public Object
                ePtr<eTimer> abortTimer, zapTimer;
                int prevChannelState;
                int state;
                ePtr<eTimer> abortTimer, zapTimer;
                int prevChannelState;
                int state;
-               __u8 isRunning, haveData;
+               unsigned int isRunning, haveData;
                ePtr<eDVBChannel> channel;
                ePtr<eConnection> m_stateChangedConn, m_NowNextConn, m_ScheduleConn, m_ScheduleOtherConn, m_ViasatConn;
                ePtr<iDVBSectionReader> m_NowNextReader, m_ScheduleReader, m_ScheduleOtherReader, m_ViasatReader;
                tidMap seenSections[4], calcedSections[4];
                ePtr<eDVBChannel> channel;
                ePtr<eConnection> m_stateChangedConn, m_NowNextConn, m_ScheduleConn, m_ScheduleOtherConn, m_ViasatConn;
                ePtr<iDVBSectionReader> m_NowNextReader, m_ScheduleReader, m_ScheduleOtherReader, m_ViasatReader;
                tidMap seenSections[4], calcedSections[4];
+#ifdef ENABLE_VIRGIN
+               ePtr<eConnection> m_VirginNowNextConn, m_VirginScheduleConn;
+               ePtr<iDVBSectionReader> m_VirginNowNextReader, m_VirginScheduleReader;
+#endif
+#ifdef ENABLE_NETMED
+               ePtr<eConnection> m_NetmedScheduleConn, m_NetmedScheduleOtherConn;
+               ePtr<iDVBSectionReader> m_NetmedScheduleReader, m_NetmedScheduleOtherReader;
+#endif
+#ifdef ENABLE_FREESAT
+               ePtr<eConnection> m_FreeSatScheduleOtherConn, m_FreeSatScheduleOtherConn2;
+               ePtr<iDVBSectionReader> m_FreeSatScheduleOtherReader, m_FreeSatScheduleOtherReader2;
+               std::map<uint32_t, freesatEITSubtableStatus> m_FreeSatSubTableStatus;
+               uint32_t m_FreesatTablesToComplete;
+               void readFreeSatScheduleOtherData(const uint8_t *data);
+               void cleanupFreeSat();
+#endif
 #ifdef ENABLE_PRIVATE_EPG
                ePtr<eTimer> startPrivateTimer;
                int m_PrevVersion;
 #ifdef ENABLE_PRIVATE_EPG
                ePtr<eTimer> startPrivateTimer;
                int m_PrevVersion;
@@ -190,51 +168,44 @@ class eEPGCache: public eMainloop, private eThread, public Object
                uniqueEPGKey m_PrivateService;
                ePtr<eConnection> m_PrivateConn;
                ePtr<iDVBSectionReader> m_PrivateReader;
                uniqueEPGKey m_PrivateService;
                ePtr<eConnection> m_PrivateConn;
                ePtr<iDVBSectionReader> m_PrivateReader;
-               std::set<__u8> seenPrivateSections;
-               void readPrivateData(const __u8 *data);
+               std::set<uint8_t> seenPrivateSections;
+               void readPrivateData(const uint8_t *data);
                void startPrivateReader();
 #endif
 #ifdef ENABLE_MHW_EPG
                std::vector<mhw_channel_name_t> m_channels;
                void startPrivateReader();
 #endif
 #ifdef ENABLE_MHW_EPG
                std::vector<mhw_channel_name_t> m_channels;
-               std::map<__u8, mhw_theme_name_t> m_themes;
-               std::map<__u32, mhw_title_t> m_titles;
-               std::multimap<__u32, __u32> m_program_ids;
+               std::map<uint8_t, mhw_theme_name_t> m_themes;
+               std::map<uint32_t, mhw_title_t> m_titles;
+               std::multimap<uint32_t, uint32_t> m_program_ids;
                ePtr<eConnection> m_MHWConn, m_MHWConn2;
                ePtr<iDVBSectionReader> m_MHWReader, m_MHWReader2;
                eDVBSectionFilterMask m_MHWFilterMask, m_MHWFilterMask2;
                ePtr<eTimer> m_MHWTimeoutTimer;
                ePtr<eConnection> m_MHWConn, m_MHWConn2;
                ePtr<iDVBSectionReader> m_MHWReader, m_MHWReader2;
                eDVBSectionFilterMask m_MHWFilterMask, m_MHWFilterMask2;
                ePtr<eTimer> m_MHWTimeoutTimer;
-               __u16 m_mhw2_channel_pid, m_mhw2_title_pid, m_mhw2_summary_pid;
+               uint16_t m_mhw2_channel_pid, m_mhw2_title_pid, m_mhw2_summary_pid;
                bool m_MHWTimeoutet;
                void MHWTimeout() { m_MHWTimeoutet=true; }
                bool m_MHWTimeoutet;
                void MHWTimeout() { m_MHWTimeoutet=true; }
-               void readMHWData(const __u8 *data);
-               void readMHWData2(const __u8 *data);
-               void startMHWReader(__u16 pid, __u8 tid);
-               void startMHWReader2(__u16 pid, __u8 tid, int ext=-1);
-               void startTimeout(int msek);
-               bool checkTimeout() { return m_MHWTimeoutet; }
-               void cleanup();
-               __u8 *delimitName( __u8 *in, __u8 *out, int len_in );
+               void readMHWData(const uint8_t *data);
+               void readMHWData2(const uint8_t *data);
+               void startMHWReader(uint16_t pid, uint8_t tid);
+               void startMHWReader2(uint16_t pid, uint8_t tid, int ext=-1);
+               void startMHWTimeout(int msek);
+               bool checkMHWTimeout() { return m_MHWTimeoutet; }
+               void cleanupMHW();
+               uint8_t *delimitName( uint8_t *in, uint8_t *out, int len_in );
                void timeMHW2DVB( u_char hours, u_char minutes, u_char *return_time);
                void timeMHW2DVB( int minutes, u_char *return_time);
                void timeMHW2DVB( u_char day, u_char hours, u_char minutes, u_char *return_time);
                void timeMHW2DVB( u_char hours, u_char minutes, u_char *return_time);
                void timeMHW2DVB( int minutes, u_char *return_time);
                void timeMHW2DVB( u_char day, u_char hours, u_char minutes, u_char *return_time);
-               void storeTitle(std::map<__u32, mhw_title_t>::iterator itTitle, std::string sumText, const __u8 *data);
+               void storeMHWTitle(std::map<uint32_t, mhw_title_t>::iterator itTitle, std::string sumText, const uint8_t *data);
 #endif
 #endif
-               void readData(const __u8 *data);
-               void readDataViasat(const __u8 *data);
+               void readData(const uint8_t *data, int source);
                void startChannel();
                void startEPG();
                void startChannel();
                void startEPG();
-               bool finishEPG();
+               void finishEPG();
                void abortEPG();
                void abortNonAvail();
        };
                void abortEPG();
                void abortNonAvail();
        };
-       bool FixOverlapping(std::pair<eventMap,timeMap> &servicemap, time_t TM, int duration, const timeMap::iterator &tm_it, const uniqueEPGKey &service);
+       bool FixOverlapping(EventCacheItem &servicemap, time_t TM, int duration, const timeMap::iterator &tm_it, const uniqueEPGKey &service);
 public:
 public:
-       enum {PRIVATE=0, NOWNEXT=1, SCHEDULE=2, SCHEDULE_OTHER=4
-#ifdef ENABLE_MHW_EPG
-       ,MHW=8
-#endif
-       ,VIASAT=16
-       };
        struct Message
        {
                enum
        struct Message
        {
                enum
@@ -274,15 +245,22 @@ public:
        eFixedMessagePump<Message> messages;
 private:
        friend class channel_data;
        eFixedMessagePump<Message> messages;
 private:
        friend class channel_data;
+       friend class eventData;
        static eEPGCache *instance;
 
        static eEPGCache *instance;
 
+       typedef std::map<iDVBChannel*, channel_data*> ChannelMap;
+
        ePtr<eTimer> cleanTimer;
        ePtr<eTimer> cleanTimer;
-       std::map<iDVBChannel*, channel_data*> m_knownChannels;
+       ChannelMap m_knownChannels;
        ePtr<eConnection> m_chanAddedConn;
 
        ePtr<eConnection> m_chanAddedConn;
 
+       unsigned int enabledSources;
+       unsigned int historySeconds;
+
        eventCache eventDB;
        updateMap channelLastUpdated;
        eventCache eventDB;
        updateMap channelLastUpdated;
-       static pthread_mutex_t cache_lock, channel_map_lock;
+       std::string m_filename;
+       bool m_running;
 
 #ifdef ENABLE_PRIVATE_EPG
        contentMaps content_time_tables;
 
 #ifdef ENABLE_PRIVATE_EPG
        contentMaps content_time_tables;
@@ -290,21 +268,15 @@ private:
 
        void thread();  // thread function
 
 
        void thread();  // thread function
 
-// called from epgcache thread
-       int m_running;
-       char m_filename[1024];
-       void save();
-       void load();
 #ifdef ENABLE_PRIVATE_EPG
 #ifdef ENABLE_PRIVATE_EPG
-       void privateSectionRead(const uniqueEPGKey &, const __u8 *);
+       void privateSectionRead(const uniqueEPGKey &, const uint8_t *);
 #endif
 #endif
-       void sectionRead(const __u8 *data, int source, channel_data *channel);
+       void sectionRead(const uint8_t *data, int source, channel_data *channel);
        void gotMessage(const Message &message);
        void gotMessage(const Message &message);
-       void flushEPG(const uniqueEPGKey & s=uniqueEPGKey());
        void cleanLoop();
        void cleanLoop();
+       void submitEventData(const std::vector<int>& sids, const std::vector<eDVBChannelID>& chids, long start, long duration, const char* title, const char* short_summary, const char* long_description, char event_type, int source);
 
 // called from main thread
 
 // called from main thread
-       void timeUpdated();
        void DVBChannelAdded(eDVBChannel*);
        void DVBChannelStateChanged(iDVBChannel*);
        void DVBChannelRunning(iDVBChannel *);
        void DVBChannelAdded(eDVBChannel*);
        void DVBChannelStateChanged(iDVBChannel*);
        void DVBChannelRunning(iDVBChannel *);
@@ -317,6 +289,11 @@ private:
 #endif // SWIG
 public:
        static eEPGCache *getInstance() { return instance; }
 #endif // SWIG
 public:
        static eEPGCache *getInstance() { return instance; }
+
+       void save();
+       void load();
+       void timeUpdated();
+       void flushEPG(const uniqueEPGKey & s=uniqueEPGKey());
 #ifndef SWIG
        eEPGCache();
        ~eEPGCache();
 #ifndef SWIG
        eEPGCache();
        ~eEPGCache();
@@ -331,28 +308,21 @@ public:
        // must be called once!
        void setCacheFile(const char *filename);
 
        // must be called once!
        void setCacheFile(const char *filename);
 
-       // called from main thread
-       inline void Lock();
-       inline void Unlock();
-
        // at moment just for one service..
        RESULT startTimeQuery(const eServiceReference &service, time_t begin=-1, int minutes=-1);
 
 #ifndef SWIG
        // at moment just for one service..
        RESULT startTimeQuery(const eServiceReference &service, time_t begin=-1, int minutes=-1);
 
 #ifndef SWIG
-       // eventData's are plain entrys out of the cache.. it's not safe to use them after cache unlock
-       // but its faster in use... its not allowed to delete this pointers via delete or free..
+private:
+       // For internal use only. Acquire the cache lock before calling.
        RESULT lookupEventId(const eServiceReference &service, int event_id, const eventData *&);
        RESULT lookupEventTime(const eServiceReference &service, time_t, const eventData *&, int direction=0);
        RESULT lookupEventId(const eServiceReference &service, int event_id, const eventData *&);
        RESULT lookupEventTime(const eServiceReference &service, time_t, const eventData *&, int direction=0);
-       RESULT getNextTimeEntry(const eventData *&);
 
 
-       // eit_event_struct's are plain dvb eit_events .. it's not safe to use them after cache unlock
-       // its not allowed to delete this pointers via delete or free..
-       RESULT lookupEventId(const eServiceReference &service, int event_id, const eit_event_struct *&);
-       RESULT lookupEventTime(const eServiceReference &service, time_t , const eit_event_struct *&, int direction=0);
-       RESULT getNextTimeEntry(const eit_event_struct *&);
+public:
+       /* Only used by servicedvbrecord.cpp to write the EIT file */
+       RESULT saveEventToFile(const char* filename, const eServiceReference &service, int eit_event_id, time_t begTime, time_t endTime);
 
 
-       // Event's are parsed epg events.. it's safe to use them after cache unlock
-       // after use this Events must be deleted (memleaks)
+       // Events are parsed epg events.. it's safe to use them after cache unlock
+       // after use the Event pointer must be released using "delete".
        RESULT lookupEventId(const eServiceReference &service, int event_id, Event* &);
        RESULT lookupEventTime(const eServiceReference &service, time_t, Event* &, int direction=0);
        RESULT getNextTimeEntry(Event *&);
        RESULT lookupEventId(const eServiceReference &service, int event_id, Event* &);
        RESULT lookupEventTime(const eServiceReference &service, time_t, Event* &, int direction=0);
        RESULT getNextTimeEntry(Event *&);
@@ -360,7 +330,8 @@ public:
        enum {
                SIMILAR_BROADCASTINGS_SEARCH,
                EXAKT_TITLE_SEARCH,
        enum {
                SIMILAR_BROADCASTINGS_SEARCH,
                EXAKT_TITLE_SEARCH,
-               PARTIAL_TITLE_SEARCH
+               PARTIAL_TITLE_SEARCH,
+               START_TITLE_SEARCH
        };
        enum {
                CASE_CHECK,
        };
        enum {
                CASE_CHECK,
@@ -374,18 +345,33 @@ public:
        SWIG_VOID(RESULT) lookupEventId(const eServiceReference &service, int event_id, ePtr<eServiceEvent> &SWIG_OUTPUT);
        SWIG_VOID(RESULT) lookupEventTime(const eServiceReference &service, time_t, ePtr<eServiceEvent> &SWIG_OUTPUT, int direction=0);
        SWIG_VOID(RESULT) getNextTimeEntry(ePtr<eServiceEvent> &SWIG_OUTPUT);
        SWIG_VOID(RESULT) lookupEventId(const eServiceReference &service, int event_id, ePtr<eServiceEvent> &SWIG_OUTPUT);
        SWIG_VOID(RESULT) lookupEventTime(const eServiceReference &service, time_t, ePtr<eServiceEvent> &SWIG_OUTPUT, int direction=0);
        SWIG_VOID(RESULT) getNextTimeEntry(ePtr<eServiceEvent> &SWIG_OUTPUT);
-};
 
 
-#ifndef SWIG
-inline void eEPGCache::Lock()
-{
-       pthread_mutex_lock(&cache_lock);
-}
-
-inline void eEPGCache::Unlock()
-{
-       pthread_mutex_unlock(&cache_lock);
-}
+       enum {PRIVATE=0, NOWNEXT=1, SCHEDULE=2, SCHEDULE_OTHER=4
+#ifdef ENABLE_MHW_EPG
+       ,MHW=8
+#endif
+#ifdef ENABLE_FREESAT
+       ,FREESAT_NOWNEXT=16
+       ,FREESAT_SCHEDULE=32
+       ,FREESAT_SCHEDULE_OTHER=64
+#endif
+       ,VIASAT=256
+#ifdef ENABLE_NETMED
+       ,NETMED_SCHEDULE=512
+       ,NETMED_SCHEDULE_OTHER=1024
 #endif
 #endif
+#ifdef ENABLE_VIRGIN
+       ,VIRGIN_NOWNEXT=2048
+       ,VIRGIN_SCHEDULE=4096
+#endif
+       ,EPG_IMPORT=0x80000000
+       };
+       void setEpgHistorySeconds(time_t seconds);
+       void setEpgSources(unsigned int mask);
+       unsigned int getEpgSources();
 
 
+       void submitEventData(const std::vector<eServiceReferenceDVB>& serviceRefs, long start, long duration, const char* title, const char* short_summary, const char* long_description, char event_type);
+       void importEvents(SWIG_PYOBJECT(ePyObject) serviceReferences, SWIG_PYOBJECT(ePyObject) list);
+       void importEvent(SWIG_PYOBJECT(ePyObject) serviceReference, SWIG_PYOBJECT(ePyObject) list);
+};
 #endif
 #endif
index affd06c..7dd3927 100644 (file)
@@ -8,16 +8,16 @@
  * 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.
  * 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.
  * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
  * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- * 
+ *
  * The author may be reached as dent@cosy.sbg.ac.at, or
  * Thomas Mirlacher, Jakob-Haringerstr. 2, A-5020 Salzburg,
  * Austria
  * The author may be reached as dent@cosy.sbg.ac.at, or
  * Thomas Mirlacher, Jakob-Haringerstr. 2, A-5020 Salzburg,
  * Austria
@@ -68,6 +68,16 @@ typedef struct {
        u_char  original_network_id_lo          : 8;
        u_char  segment_last_section_number     : 8;
        u_char  segment_last_table_id           : 8;
        u_char  original_network_id_lo          : 8;
        u_char  segment_last_section_number     : 8;
        u_char  segment_last_table_id           : 8;
+
+       int getSectionLength() const     { return section_length_hi << 8 | section_length_lo; };
+       int getServiceID() const         { return service_id_hi << 8 | service_id_lo; };
+       int getTransportStreamId() const { return transport_stream_id_hi << 8 | transport_stream_id_lo; };
+       int getOriginalNetworkId() const { return original_network_id_hi << 8 | original_network_id_lo; };
+
+       void setSectionLength(int length)  { section_length_hi = length >> 8; section_length_lo = length & 0xFF; };
+       void setServiceId(int serviceId)   { service_id_hi = serviceId >> 8; service_id_lo = serviceId & 0xFF; };
+       void setTransportStreamId(int tsi) { transport_stream_id_hi = tsi >> 8; transport_stream_id_lo = tsi & 0xFF; };
+       void setOriginalNetworkId(int oni) { original_network_id_hi = oni >> 8; original_network_id_lo = oni & 0xFF; };
 } eit_t;
 
 #define EIT_SIZE 14
 } eit_t;
 
 #define EIT_SIZE 14
@@ -103,20 +113,20 @@ struct eit_loop_struct1 {
 struct eit_short_event_descriptor_struct {
        u_char  descriptor_tag                  : 8;
        u_char  descriptor_length               : 8;
 struct eit_short_event_descriptor_struct {
        u_char  descriptor_tag                  : 8;
        u_char  descriptor_length               : 8;
-       
+
        u_char  language_code_1                 : 8;
        u_char  language_code_2                 : 8;
        u_char  language_code_3                 : 8;
 
        u_char  event_name_length               : 8;
 };
        u_char  language_code_1                 : 8;
        u_char  language_code_2                 : 8;
        u_char  language_code_3                 : 8;
 
        u_char  event_name_length               : 8;
 };
-       
+
 #define EIT_EXTENDED_EVENT_DESCRIPOR 0x4e
 
 typedef struct eit_event_struct {
        u_char  event_id_hi                     : 8;
        u_char  event_id_lo                     : 8;
 #define EIT_EXTENDED_EVENT_DESCRIPOR 0x4e
 
 typedef struct eit_event_struct {
        u_char  event_id_hi                     : 8;
        u_char  event_id_lo                     : 8;
-       
+
        u_char  start_time_1                    : 8;
        u_char  start_time_2                    : 8;
        u_char  start_time_3                    : 8;
        u_char  start_time_1                    : 8;
        u_char  start_time_2                    : 8;
        u_char  start_time_3                    : 8;
@@ -138,7 +148,13 @@ typedef struct eit_event_struct {
 #endif
 
        u_char  descriptors_loop_length_lo      : 8;
 #endif
 
        u_char  descriptors_loop_length_lo      : 8;
-       
+
+       uint16_t getEventId() const          { return event_id_hi << 8 | event_id_lo; };
+       int getDescriptorsLoopLength() const { return descriptors_loop_length_hi << 8 | descriptors_loop_length_lo; };
+
+       void setEventId(uint16_t eventId)      { event_id_hi = eventId >> 8; event_id_lo = eventId & 0xFF; };
+       void setDescriptorsLoopLength(int dll) { descriptors_loop_length_hi = dll >> 8; descriptors_loop_length_lo = dll & 0xFF; };
+
 } eit_event_t;
 #define EIT_LOOP_SIZE 12
 
 } eit_event_t;
 #define EIT_LOOP_SIZE 12
 
@@ -160,4 +176,4 @@ struct eit_extended_descriptor_struct {
 };
 
 
 };
 
 
-#endif 
+#endif
index f06c86e..f9f2f70 100644 (file)
@@ -85,6 +85,9 @@ typedef struct {
    u_char mhw2_mjd_lo                            :8;
    u_char mhw2_duration_hi                       :8;
    u_char mhw2_duration_lo                       :8;
    u_char mhw2_mjd_lo                            :8;
    u_char mhw2_duration_hi                       :8;
    u_char mhw2_duration_lo                       :8;
+
+   int getDuration() const     { return duration_hi << 8 | duration_lo; };
+   int getMhw2Duration() const { return mhw2_duration_hi << 8 | mhw2_duration_lo; };
 } mhw_title_t;
 
 typedef struct mhw_summary {
 } mhw_title_t;
 
 typedef struct mhw_summary {
index b1ec62d..6ccf328 100644 (file)
 from Components.Converter.Converter import Converter
 from Components.Element import cached
 from Components.Converter.Converter import Converter
 from Components.Element import cached
+from Components.Converter.genre import getGenreStringSub
 
 class EventName(Converter, object):
        NAME = 0
        SHORT_DESCRIPTION = 1
        EXTENDED_DESCRIPTION = 2
 
 class EventName(Converter, object):
        NAME = 0
        SHORT_DESCRIPTION = 1
        EXTENDED_DESCRIPTION = 2
-       ID = 3
-       
+       FULL_DESCRIPTION = 3
+       ID = 4
+       NAME_NOW = 5
+       NAME_NEXT = 6
+       GENRE = 7
+       RATING = 8
+       SRATING = 9
+       PDC = 10
+       PDCTIME = 11
+       PDCTIMESHORT = 12
+       ISRUNNINGSTATUS = 13
+
        def __init__(self, type):
                Converter.__init__(self, type)
                if type == "Description":
                        self.type = self.SHORT_DESCRIPTION
                elif type == "ExtendedDescription":
                        self.type = self.EXTENDED_DESCRIPTION
        def __init__(self, type):
                Converter.__init__(self, type)
                if type == "Description":
                        self.type = self.SHORT_DESCRIPTION
                elif type == "ExtendedDescription":
                        self.type = self.EXTENDED_DESCRIPTION
+               elif type == "FullDescription":
+                       self.type = self.FULL_DESCRIPTION
                elif type == "ID":
                        self.type = self.ID
                elif type == "ID":
                        self.type = self.ID
+               elif type == "NameNow":
+                       self.type = self.NAME_NOW
+               elif type == "NameNext":
+                       self.type = self.NAME_NEXT
+               elif type == "Genre":
+                       self.type = self.GENRE
+               elif type == "Rating":
+                       self.type = self.RATING
+               elif type == "SmallRating":
+                       self.type = self.SRATING
+               elif type == "Pdc":
+                       self.type = self.PDC
+               elif type == "PdcTime":
+                       self.type = self.PDCTIME
+               elif type == "PdcTimeShort":
+                       self.type = self.PDCTIMESHORT
+               elif type == "IsRunningStatus":
+                       self.type = self.ISRUNNINGSTATUS
                else:
                        self.type = self.NAME
 
        @cached
                else:
                        self.type = self.NAME
 
        @cached
+       def getBoolean(self):
+               event = self.source.event
+               if event is None:
+                       return False
+               if self.type == self.PDC:
+                       if event.getPdcPil():
+                               return True
+               return False
+
+       boolean = property(getBoolean)
+
+       @cached
        def getText(self):
                event = self.source.event
                if event is None:
                        return ""
        def getText(self):
                event = self.source.event
                if event is None:
                        return ""
-                       
+
                if self.type == self.NAME:
                        return event.getEventName()
                if self.type == self.NAME:
                        return event.getEventName()
+               elif self.type == self.SRATING:
+                       rating = event.getParentalData()
+                       if rating is None:
+                               return ""
+                       else:
+                               country = rating.getCountryCode()
+                               age = rating.getRating()
+                               if age == 0:
+                                       return _("All ages")
+                               elif age > 15:
+                                       return _("bc%s") % age
+                               else:
+                                       age += 3
+                                       return " %d+" % age
+               elif self.type == self.RATING:
+                       rating = event.getParentalData()
+                       if rating is None:
+                               return ""
+                       else:
+                               country = rating.getCountryCode()
+                               age = rating.getRating()
+                               if age == 0:
+                                       return _("Rating undefined")
+                               elif age > 15:
+                                       return _("Rating defined by broadcaster - %d") % age
+                               else:
+                                       age += 3
+                                       return _("Minimum age %d years") % age
+               elif self.type == self.GENRE:
+                       genre = event.getGenreData()
+                       if genre is None:
+                               return ""
+                       else:
+                               return getGenreStringSub(genre.getLevel1(), genre.getLevel2())
+               elif self.type == self.NAME_NOW:
+                       return pgettext("now/next: 'now' event label", "Now") + ": " + event.getEventName()
+               elif self.type == self.NAME_NEXT:
+                       return pgettext("now/next: 'next' event label", "Next") + ": " + event.getEventName()
                elif self.type == self.SHORT_DESCRIPTION:
                        return event.getShortDescription()
                elif self.type == self.EXTENDED_DESCRIPTION:
                elif self.type == self.SHORT_DESCRIPTION:
                        return event.getShortDescription()
                elif self.type == self.EXTENDED_DESCRIPTION:
-                       return event.getExtendedDescription()
+                       return event.getExtendedDescription() or event.getShortDescription()
+               elif self.type == self.FULL_DESCRIPTION:
+                       description = event.getShortDescription()
+                       extended = event.getExtendedDescription()
+                       if description and extended:
+                               if description.replace('\n','') == extended.replace('\n',''):
+                                       return extended
+                               description += '\n'
+                       return description + extended
                elif self.type == self.ID:
                        return str(event.getEventId())
                elif self.type == self.ID:
                        return str(event.getEventId())
-               
+               elif self.type == self.PDC:
+                       if event.getPdcPil():
+                               return _("PDC")
+                       return ""
+               elif self.type in (self.PDCTIME, self.PDCTIMESHORT):
+                       pil = event.getPdcPil()
+                       if pil:
+                               if self.type == self.PDCTIMESHORT:
+                                       return _("%02d:%02d") % ((pil & 0x7C0) >> 6, (pil & 0x3F))
+                               return _("%d.%02d. %02d:%02d") % ((pil & 0xF8000) >> 15, (pil & 0x7800) >> 11, (pil & 0x7C0) >> 6, (pil & 0x3F))
+                       return ""
+               elif self.type == self.ISRUNNINGSTATUS:
+                       if event.getPdcPil():
+                               running_status = event.getRunningStatus()
+                               if running_status == 1:
+                                       return _("not running")
+                               if running_status == 2:
+                                       return _("starts in a few seconds")
+                               if running_status == 3:
+                                       return _("pausing")
+                               if running_status == 4:
+                                       return _("running")
+                               if running_status == 5:
+                                       return _("service off-air")
+                               if running_status in (6,7):
+                                       return _("reserved for future use")
+                               return _("undefined")
+                       return ""
+
        text = property(getText)
        text = property(getText)
index ee817d4..a9871d5 100644 (file)
@@ -6,4 +6,4 @@ install_PYTHON = \
        ConditionalShowHide.py ServicePosition.py ValueRange.py RdsInfo.py Streaming.py \
        StaticMultiList.py ServiceTime.py MovieInfo.py MenuEntryCompare.py StringListSelection.py \
        ValueBitTest.py TunerInfo.py ConfigEntryTest.py TemplatedMultiContent.py ProgressToText.py \
        ConditionalShowHide.py ServicePosition.py ValueRange.py RdsInfo.py Streaming.py \
        StaticMultiList.py ServiceTime.py MovieInfo.py MenuEntryCompare.py StringListSelection.py \
        ValueBitTest.py TunerInfo.py ConfigEntryTest.py TemplatedMultiContent.py ProgressToText.py \
-       Combine.py SensorToText.py ValueToPixmap.py HbbtvApplicationInfo.py
+       Combine.py SensorToText.py ValueToPixmap.py HbbtvApplicationInfo.py genre.py
diff --git a/lib/python/Components/Converter/genre.py b/lib/python/Components/Converter/genre.py
new file mode 100644 (file)
index 0000000..50d4be7
--- /dev/null
@@ -0,0 +1,170 @@
+#
+# Genre types taken from DVB standards documentation
+#
+# some broadcaster do define other types so this list
+# may grow or be replaced..
+#
+maintype = [   _("Reserved"),
+               _("Movie/Drama"),
+               _("News Current Affairs"),
+               _("Show Games show"),
+               _("Sports"),
+               _("Children/Youth"),
+               _("Music/Ballet/Dance"),
+               _("Arts/Culture"),
+               _("Social/Political/Economics"),
+               _("Education/Science/..."),
+               _("Leisure hobbies"),
+               _("Other")]
+
+
+subtype = {}
+# Movie/Drama
+subtype[1] = [
+                                       _("movie/drama (general)"),
+                                       _("detective/thriller"),
+                                       _("adventure/western/war"),
+                                       _("science fiction/fantasy/horror"),
+                                       _("comedy"),
+                                       _("soap/melodram/folkloric"),
+                                       _("romance"),
+                                       _("serious/classical/religious/historical movie/drama"),
+                                       _("adult movie/drama")]
+
+# News Current Affairs
+subtype[2] = [
+                                       _("news/current affairs (general)"),
+                                       _("news/weather report"),
+                                       _("news magazine"),
+                                       _("documentary"),
+                                       _("discussion/interview/debate")]
+
+# Show Games show
+subtype[3] = [
+                                       _("show/game show (general)"),
+                                       _("game show/quiz/contest"),
+                                       _("variety show"),
+                                       _("talk show")]
+
+# Sports
+subtype[4] = [
+                                       _("sports (general)"),
+                                       _("special events"),
+                                       _("sports magazine"),
+                                       _("football/soccer"),
+                                       _("tennis/squash"),
+                                       _("team sports"),
+                                       _("athletics"),
+                                       _("motor sport"),
+                                       _("water sport"),
+                                       _("winter sport"),
+                                       _("equestrian"),
+                                       _("martial sports")]
+
+# Children/Youth
+subtype[5] = [
+                                       _("childrens's/youth program (general)"),
+                                       _("pre-school children's program"),
+                                       _("entertainment (6-14 year old)"),
+                                       _("entertainment (10-16 year old)"),
+                                       _("information/education/school program"),
+                                       _("cartoon/puppets")]
+
+# Music/Ballet/Dance
+subtype[6] = [
+                                       _("music/ballet/dance (general)"),
+                                       _("rock/pop"),
+                                       _("serious music/classic music"),
+                                       _("folk/traditional music"),
+                                       _("jazz"),
+                                       _("musical/opera"),
+                                       _("ballet")]
+
+# Arts/Culture
+subtype[7] = [
+                                       _("arts/culture (without music, general)"),
+                                       _("performing arts"),
+                                       _("fine arts"),
+                                       _("religion"),
+                                       _("popular culture/traditional arts"),
+                                       _("literature"),
+                                       _("film/cinema"),
+                                       _("experimental film/video"),
+                                       _("broadcasting/press"),
+                                       _("new media"),
+                                       _("arts/culture magazine"),
+                                       _("fashion")]
+
+# Social/Political/Economics
+subtype[8] = [
+                                       _("social/political issues/economics (general)"),
+                                       _("magazines/reports/documentary"),
+                                       _("economics/social advisory"),
+                                       _("remarkable people")]
+
+# Education/Science/...
+subtype[9] = [
+                                       _("education/science/factual topics (general)"),
+                                       _("nature/animals/environment"),
+                                       _("technology/natural science"),
+                                       _("medicine/physiology/psychology"),
+                                       _("foreign countries/expeditions"),
+                                       _("social/spiritual science"),
+                                       _("further education"),
+                                       _("languages")]
+
+# Leisure hobies
+subtype[10] = [
+                                       _("leisure hobbies (general)"),
+                                       _("tourism/travel"),
+                                       _("handicraft"),
+                                       _("motoring"),
+                                       _("fitness & health"),
+                                       _("cooking"),
+                                       _("advertisement/shopping"),
+                                       _("gardening")]
+
+# Other
+subtype[11] = [
+                                       _("original language"),
+                                       _("black & white"),
+                                       _("unpublished"),
+                                       _("live broadcast")]
+
+def getGenreStringMain(hn, ln):
+#      if hn == 0:
+#              return _("Undefined content")
+       if hn == 15:
+               return _("User defined")
+       if 0 < hn < len(maintype):
+               return maintype[hn]
+#      return _("Reserved") + " " + str(hn)
+       return ""
+
+def getGenreStringSub(hn, ln):
+#      if hn == 0:
+#              return _("Undefined content") + " " + str(ln)
+       if hn == 15:
+               return _("User defined") + " " + str(ln)
+       if 0 < hn < len(maintype):
+               if ln == 15:
+                       return _("User defined")
+               if ln < len(subtype[hn]):
+                       return subtype[hn][ln]
+#              return _("Reserved") " " + str(ln)
+#      return _("Reserved") + " " + str(hn) + "," + str(ln)
+       return ""
+
+def getGenreStringLong(hn, ln):
+#      if hn == 0:
+#              return _("Undefined content") + " " + str(ln)
+       if hn == 15:
+               return _("User defined") + " " + str(ln)
+       if 0 < hn < len(maintype):
+               return maintype[hn] + ": " + getGenreStringSub(hn, ln)
+#      return _("Reserved") + " " + str(hn) + "," + str(ln)
+       return ""
+
+#
+# The End
+#
index 36db2ad..52476ed 100644 (file)
@@ -1,10 +1,9 @@
 from Components.Harddisk import harddiskmanager
 from Components.NimManager import nimmanager
 from Components.Harddisk import harddiskmanager
 from Components.NimManager import nimmanager
-from config import ConfigSubsection, ConfigYesNo, config, ConfigSelection, ConfigText, ConfigNumber, ConfigSet, ConfigLocations
+from config import ConfigSubsection, ConfigYesNo, config, ConfigSelection, ConfigText, ConfigNumber, ConfigSet, ConfigLocations, ConfigSelectionNumber
 from Tools.Directories import defaultRecordingLocation
 from Tools.Directories import resolveFilename, SCOPE_HDD
 from Tools.Directories import defaultRecordingLocation
 from Tools.Directories import resolveFilename, SCOPE_HDD
-from enigma import Misc_Options, eEnv
-from enigma import setTunerTypePriorityOrder, setPreferredTuner
+from enigma import Misc_Options, eEnv, setTunerTypePriorityOrder, setPreferredTuner, eServiceEvent
 from SystemInfo import SystemInfo
 import os
 
 from SystemInfo import SystemInfo
 import os
 
@@ -94,6 +93,42 @@ def InitUsageConfig():
                setPreferredTuner(int(configElement.value))
        config.usage.frontend_priority.addNotifier(PreferredTunerChanged)
 
                setPreferredTuner(int(configElement.value))
        config.usage.frontend_priority.addNotifier(PreferredTunerChanged)
 
+       config.epg = ConfigSubsection()
+       config.epg.eit = ConfigYesNo(default = True)
+       config.epg.mhw = ConfigYesNo(default = False)
+       config.epg.freesat = ConfigYesNo(default = True)
+       config.epg.viasat = ConfigYesNo(default = True)
+       config.epg.netmed = ConfigYesNo(default = True)
+       config.epg.virgin = ConfigYesNo(default = False)
+       def EpgSettingsChanged(configElement):
+               from enigma import eEPGCache
+               mask = 0xffffffff
+               if not config.epg.eit.value:
+                       mask &= ~(eEPGCache.NOWNEXT | eEPGCache.SCHEDULE | eEPGCache.SCHEDULE_OTHER)
+               if not config.epg.mhw.value:
+                       mask &= ~eEPGCache.MHW
+               if not config.epg.freesat.value:
+                       mask &= ~(eEPGCache.FREESAT_NOWNEXT | eEPGCache.FREESAT_SCHEDULE | eEPGCache.FREESAT_SCHEDULE_OTHER)
+               if not config.epg.viasat.value:
+                       mask &= ~eEPGCache.VIASAT
+               #if not config.epg.netmed.value:
+               #       mask &= ~(eEPGCache.NETMED_SCHEDULE | eEPGCache.NETMED_SCHEDULE_OTHER)
+               #if not config.epg.virgin.value:
+               #       mask &= ~(eEPGCache.VIRGIN_NOWNEXT | eEPGCache.VIRGIN_SCHEDULE)
+               eEPGCache.getInstance().setEpgSources(mask)
+       config.epg.eit.addNotifier(EpgSettingsChanged)
+       config.epg.mhw.addNotifier(EpgSettingsChanged)
+       config.epg.freesat.addNotifier(EpgSettingsChanged)
+       config.epg.viasat.addNotifier(EpgSettingsChanged)
+       config.epg.netmed.addNotifier(EpgSettingsChanged)
+       config.epg.virgin.addNotifier(EpgSettingsChanged)
+
+       config.epg.histminutes = ConfigSelectionNumber(min = 0, max = 120, stepwidth = 15, default = 0, wraparound = True)
+       def EpgHistorySecondsChanged(configElement):
+               from enigma import eEPGCache
+               eEPGCache.getInstance().setEpgHistorySeconds(config.epg.histminutes.getValue()*60)
+       config.epg.histminutes.addNotifier(EpgHistorySecondsChanged)
+
        def setHDDStandby(configElement):
                for hdd in harddiskmanager.HDDList():
                        hdd[1].setIdleTime(int(configElement.value))
        def setHDDStandby(configElement):
                for hdd in harddiskmanager.HDDList():
                        hdd[1].setIdleTime(int(configElement.value))
@@ -213,6 +248,53 @@ def InitUsageConfig():
                ("30000", _("30"))])
        config.subtitles.pango_autoturnon = ConfigYesNo(default = True)
 
                ("30000", _("30"))])
        config.subtitles.pango_autoturnon = ConfigYesNo(default = True)
 
+       config.autolanguage = ConfigSubsection()
+       epg_language_choices=[
+               ("---", _("None")),
+               ("eng qaa", _("English")),
+               ("deu ger", _("German")),
+               ("ara", _("Arabic")),
+               ("eus baq", _("Basque")),
+               ("bul", _("Bulgarian")),
+               ("hrv", _("Croatian")),
+               ("ces cze", _("Czech")),
+               ("dan", _("Danish")),
+               ("dut ndl nld", _("Dutch")),
+               ("est", _("Estonian")),
+               ("fin", _("Finnish")),
+               ("fra fre", _("French")),
+               ("ell gre", _("Greek")),
+               ("heb", _("Hebrew")),
+               ("hun", _("Hungarian")),
+               ("ita", _("Italian")),
+               ("lav", _("Latvian")),
+               ("lit", _("Lithuanian")),
+               ("ltz", _("Luxembourgish")),
+               ("nor", _("Norwegian")),
+               ("fas per fa pes", _("Persian")),
+               ("pol", _("Polish")),
+               ("por dub Dub DUB ud1", _("Portuguese")),
+               ("ron rum", _("Romanian")),
+               ("rus", _("Russian")),
+               ("srp", _("Serbian")),
+               ("slk slo", _("Slovak")),
+               ("slv", _("Slovenian")),
+               ("spa", _("Spanish")),
+               ("swe", _("Swedish")),
+               ("tha", _("Thai")),
+               ("tur Audio_TUR", _("Turkish")),
+               ("ukr Ukr", _("Ukrainian"))]
+
+       def setEpgLanguage(configElement):
+               eServiceEvent.setEPGLanguage(configElement.value)
+       config.autolanguage.epglanguage = ConfigSelection(epg_language_choices, default="---")
+       config.autolanguage.epglanguage.addNotifier(setEpgLanguage)
+
+       def setEpgLanguageAlternative(configElement):
+               eServiceEvent.setEPGLanguageAlternative(configElement.value)
+       config.autolanguage.epglanguage_alternative = ConfigSelection(epg_language_choices, default="---")
+       config.autolanguage.epglanguage_alternative.addNotifier(setEpgLanguageAlternative)
+
 def updateChoices(sel, choices):
        if choices:
                defval = None
 def updateChoices(sel, choices):
        if choices:
                defval = None
old mode 100755 (executable)
new mode 100644 (file)
index d1c6c84..bc66f1f
@@ -44,6 +44,9 @@ from RecordTimer import RecordTimerEntry, RecordTimer, findSafeRecordPath
 # hack alert!
 from Menu import MainMenu, mdom
 
 # hack alert!
 from Menu import MainMenu, mdom
 
+def isStandardInfoBar(self):
+       return self.__class__.__name__ == "InfoBar"
+
 class InfoBarDish:
        def __init__(self):
                self.dishDialog = self.session.instantiateDialog(Dish)
 class InfoBarDish:
        def __init__(self):
                self.dishDialog = self.session.instantiateDialog(Dish)
@@ -852,7 +855,7 @@ class InfoBarSeek:
                return seek
 
        def isSeekable(self):
                return seek
 
        def isSeekable(self):
-               if self.getSeek() is None:
+               if self.getSeek() is None or (isStandardInfoBar(self) and not self.timeshift_enabled):
                        return False
                return True
 
                        return False
                return True
 
index 2a4cb0d..596e327 100644 (file)
@@ -8,70 +8,30 @@
 #include <dvbsi++/extended_event_descriptor.h>
 #include <dvbsi++/linkage_descriptor.h>
 #include <dvbsi++/component_descriptor.h>
 #include <dvbsi++/extended_event_descriptor.h>
 #include <dvbsi++/linkage_descriptor.h>
 #include <dvbsi++/component_descriptor.h>
+#include <dvbsi++/content_descriptor.h>
+#include <dvbsi++/parental_rating_descriptor.h>
 #include <dvbsi++/descriptor_tag.h>
 #include <dvbsi++/descriptor_tag.h>
+#include <dvbsi++/pdc_descriptor.h>
 
 #include <sys/types.h>
 #include <fcntl.h>
 
 // static members / methods
 
 #include <sys/types.h>
 #include <fcntl.h>
 
 // static members / methods
-std::string eServiceEvent::m_language = "de_DE";
+std::string eServiceEvent::m_language = "---";
+std::string eServiceEvent::m_language_alternative = "---";
 
 
-void eServiceEvent::setEPGLanguage( const std::string language )
-{
-       m_language = language;
-}
 ///////////////////////////
 
 DEFINE_REF(eServiceEvent);
 DEFINE_REF(eComponentData);
 ///////////////////////////
 
 DEFINE_REF(eServiceEvent);
 DEFINE_REF(eComponentData);
-
-const char MAX_LANG = 37;
-/* OSD language (see /share/locales/locales) to iso639 conversion table */
-std::string ISOtbl[MAX_LANG][2] =
-{
-       {"ar_AE","ara"},
-       {"C","eng"},
-       {"cs_CZ","ces"},     /* or 'cze' */
-       {"cs_CZ","cze"},
-       {"da_DK","dan"},
-       {"de_DE","deu"},     /* also 'ger' is valid iso639 code!! */
-       {"de_DE","ger"},
-       {"el_GR","gre"},     /* also 'ell' is valid */
-       {"el_GR","ell"},
-       {"es_ES","esl"},     /* also 'spa' is ok */
-       {"es_ES","spa"},
-       {"et_EE","est"},
-       {"fi_FI","fin"},
-       {"fr_FR","fra"},
-       {"hr_HR","hrv"},     /* or 'scr' */
-       {"hr_HR","scr"},
-       {"hu_HU","hun"},
-       {"is_IS","isl"},     /* or 'ice' */
-       {"is_IS","ice"},
-       {"it_IT","ita"},
-       {"lt_LT","lit"},
-       {"nl_NL","nld"},     /* or 'dut' */
-       {"nl_NL","dut"},
-       {"no_NO","nor"},
-       {"pl_PL","pol"},
-       {"pt_PT","por"},
-       {"ro_RO","ron"},     /* or 'rum' */
-       {"ro_RO","rum"},
-       {"ru_RU","rus"},
-       {"sk_SK","slk"},     /* or 'slo' */
-       {"sk_SK","slo"},
-       {"sl_SI","slv"},
-       {"sr_YU","srp"},     /* or 'scc' */
-       {"sr_YU","scc"},
-       {"sv_SE","swe"},
-       {"tr_TR","tur"},
-       {"ur_IN","urd"}
-};
+DEFINE_REF(eGenreData);
+DEFINE_REF(eParentalData);
 
 /* search for the presence of language from given EIT event descriptors*/
 
 /* search for the presence of language from given EIT event descriptors*/
-bool eServiceEvent::loadLanguage(Event *evt, std::string lang, int tsidonid)
+bool eServiceEvent::loadLanguage(Event *evt, const std::string &lang, int tsidonid)
 {
        bool retval=0;
 {
        bool retval=0;
+       std::string language = lang;
        for (DescriptorConstIterator desc = evt->getDescriptors()->begin(); desc != evt->getDescriptors()->end(); ++desc)
        {
                switch ((*desc)->getTag())
        for (DescriptorConstIterator desc = evt->getDescriptors()->begin(); desc != evt->getDescriptors()->end(); ++desc)
        {
                switch ((*desc)->getTag())
@@ -82,14 +42,15 @@ bool eServiceEvent::loadLanguage(Event *evt, std::string lang, int tsidonid)
                        case SHORT_EVENT_DESCRIPTOR:
                        {
                                const ShortEventDescriptor *sed = (ShortEventDescriptor*)*desc;
                        case SHORT_EVENT_DESCRIPTOR:
                        {
                                const ShortEventDescriptor *sed = (ShortEventDescriptor*)*desc;
-                               const std::string &cc = sed->getIso639LanguageCode();
+                               std::string cc = sed->getIso639LanguageCode();
+                               std::transform(cc.begin(), cc.end(), cc.begin(), tolower);
                                int table=encodingHandler.getCountryCodeDefaultMapping(cc);
                                int table=encodingHandler.getCountryCodeDefaultMapping(cc);
-                               if (lang.empty())
-                                       lang = cc;  // use first found language
-                               if (!strncasecmp(lang.c_str(), cc.c_str(), 3))
+                               if (language == "---" || language.find(cc) != std::string::npos)
                                {
                                {
-                                       m_event_name = convertDVBUTF8(replace_all(replace_all(sed->getEventName(), "\n", " "), "\t", " "), table, tsidonid);
-                                       m_short_description = convertDVBUTF8(sed->getText(), table, tsidonid);
+                                       /* stick to this language, avoid merging or mixing descriptors of different languages */
+                                       language = cc;
+                                       m_event_name += replace_all(replace_all(convertDVBUTF8(sed->getEventName(), table, tsidonid), "\n", " ",table), "\t", " ",table);
+                                       m_short_description += convertDVBUTF8(sed->getText(), table, tsidonid);
                                        retval=1;
                                }
                                break;
                                        retval=1;
                                }
                                break;
@@ -97,13 +58,37 @@ bool eServiceEvent::loadLanguage(Event *evt, std::string lang, int tsidonid)
                        case EXTENDED_EVENT_DESCRIPTOR:
                        {
                                const ExtendedEventDescriptor *eed = (ExtendedEventDescriptor*)*desc;
                        case EXTENDED_EVENT_DESCRIPTOR:
                        {
                                const ExtendedEventDescriptor *eed = (ExtendedEventDescriptor*)*desc;
-                               const std::string &cc = eed->getIso639LanguageCode();
+                               std::string cc = eed->getIso639LanguageCode();
+                               std::transform(cc.begin(), cc.end(), cc.begin(), tolower);
                                int table=encodingHandler.getCountryCodeDefaultMapping(cc);
                                int table=encodingHandler.getCountryCodeDefaultMapping(cc);
-                               if (lang.empty())
-                                       lang = cc;  // use first found language
-                               if (!strncasecmp(lang.c_str(), cc.c_str(), 3))
+                               if (language == "---" || language.find(cc) != std::string::npos)
                                {
                                {
-                                       m_extended_description += convertDVBUTF8(eed->getText(), table, tsidonid);
+                                       /* stick to this language, avoid merging or mixing descriptors of different languages */
+                                       language = cc;
+                                       /*
+                                        * Bit of a hack, some providers put the event description partly in the short descriptor,
+                                        * and the remainder in extended event descriptors.
+                                        * In that case, we cannot really treat short/extended description as separate descriptions.
+                                        * Unfortunately we cannot recognise this, but we'll use the length of the short description
+                                        * to guess whether we should concatenate both descriptions (without any spaces)
+                                        */
+                                       if (eed->getText().empty() && m_short_description.size() >= 180)
+                                       {
+                                               m_extended_description = m_short_description;
+                                               m_short_description = "";
+                                       }
+                                       if (table == 0) // Two Char Mapping EED must be processed in one pass
+                                       {
+                                               m_tmp_extended_description += eed->getText();
+                                               if (eed->getDescriptorNumber() == eed->getLastDescriptorNumber())
+                                               {
+                                                       m_extended_description += convertDVBUTF8(m_tmp_extended_description, table, tsidonid);
+                                               }
+                                       }
+                                       else
+                                       {
+                                               m_extended_description += convertDVBUTF8(eed->getText(), table, tsidonid);
+                                       }
                                        retval=1;
                                }
 #if 0
                                        retval=1;
                                }
 #if 0
@@ -136,6 +121,7 @@ bool eServiceEvent::loadLanguage(Event *evt, std::string lang, int tsidonid)
                                        data.m_componentType = cp->getComponentType();
                                        data.m_componentTag = cp->getComponentTag();
                                        data.m_iso639LanguageCode = cp->getIso639LanguageCode();
                                        data.m_componentType = cp->getComponentType();
                                        data.m_componentTag = cp->getComponentTag();
                                        data.m_iso639LanguageCode = cp->getIso639LanguageCode();
+                                       std::transform(data.m_iso639LanguageCode.begin(), data.m_iso639LanguageCode.end(), data.m_iso639LanguageCode.begin(), tolower);
                                        int table=encodingHandler.getCountryCodeDefaultMapping(data.m_iso639LanguageCode);
                                        data.m_text = convertDVBUTF8(cp->getText(),table,tsidonid);
                                        m_component_data.push_back(data);
                                        int table=encodingHandler.getCountryCodeDefaultMapping(data.m_iso639LanguageCode);
                                        data.m_text = convertDVBUTF8(cp->getText(),table,tsidonid);
                                        m_component_data.push_back(data);
@@ -146,19 +132,53 @@ bool eServiceEvent::loadLanguage(Event *evt, std::string lang, int tsidonid)
                                        const LinkageDescriptor  *ld = (LinkageDescriptor*)*desc;
                                        if ( ld->getLinkageType() == 0xB0 )
                                        {
                                        const LinkageDescriptor  *ld = (LinkageDescriptor*)*desc;
                                        if ( ld->getLinkageType() == 0xB0 )
                                        {
-                                               eServiceReference ref;
-                                               ref.type = eServiceReference::idDVB;
-                                               eServiceReferenceDVB &dvb_ref = (eServiceReferenceDVB&) ref;
+                                               eServiceReferenceDVB dvb_ref;
+                                               dvb_ref.type = eServiceReference::idDVB;
                                                dvb_ref.setServiceType(1);
                                                dvb_ref.setTransportStreamID(ld->getTransportStreamId());
                                                dvb_ref.setOriginalNetworkID(ld->getOriginalNetworkId());
                                                dvb_ref.setServiceID(ld->getServiceId());
                                                const PrivateDataByteVector *privateData = ld->getPrivateDataBytes();
                                                dvb_ref.name = convertDVBUTF8((const unsigned char*)&((*privateData)[0]), privateData->size(), 1, tsidonid);
                                                dvb_ref.setServiceType(1);
                                                dvb_ref.setTransportStreamID(ld->getTransportStreamId());
                                                dvb_ref.setOriginalNetworkID(ld->getOriginalNetworkId());
                                                dvb_ref.setServiceID(ld->getServiceId());
                                                const PrivateDataByteVector *privateData = ld->getPrivateDataBytes();
                                                dvb_ref.name = convertDVBUTF8((const unsigned char*)&((*privateData)[0]), privateData->size(), 1, tsidonid);
-                                               m_linkage_services.push_back(ref);
+                                               m_linkage_services.push_back(dvb_ref);
+                                       }
+                                       break;
+                               }
+                               case CONTENT_DESCRIPTOR:
+                               {
+                                       const ContentDescriptor *cd = (ContentDescriptor *)*desc;
+                                       const ContentClassificationList *con = cd->getClassifications();
+                                       for (ContentClassificationConstIterator it = con->begin(); it != con->end(); ++it)
+                                       {
+                                               eGenreData data;
+                                               data.m_level1 = (*it)->getContentNibbleLevel1();
+                                               data.m_level2 = (*it)->getContentNibbleLevel2();
+                                               data.m_user1  = (*it)->getUserNibble1();
+                                               data.m_user2  = (*it)->getUserNibble2();
+                                               m_genres.push_back(data);
                                        }
                                        break;
                                }
                                        }
                                        break;
                                }
+                               case PARENTAL_RATING_DESCRIPTOR:
+                               {
+                                       const ParentalRatingDescriptor *prd = (ParentalRatingDescriptor *)*desc;
+                                       const ParentalRatingList *par = prd->getParentalRatings();
+                                       for (ParentalRatingConstIterator it = par->begin(); it != par->end(); ++it)
+                                       {
+                                               eParentalData data;
+
+                                               data.m_country_code = (*it)->getCountryCode();
+                                               data.m_rating = (*it)->getRating();
+                                               m_ratings.push_back(data);
+                                       }
+                                       break;
+                               }
+                               case PDC_DESCRIPTOR:
+                               {
+                                       const PdcDescriptor *pdcd = (PdcDescriptor *)*desc;
+                                       m_pdc_pil = pdcd->getProgrammeIdentificationLabel();
+                                       break;
+                               }
                        }
                }
        }
                        }
                }
        }
@@ -169,37 +189,29 @@ bool eServiceEvent::loadLanguage(Event *evt, std::string lang, int tsidonid)
 
 RESULT eServiceEvent::parseFrom(Event *evt, int tsidonid)
 {
 
 RESULT eServiceEvent::parseFrom(Event *evt, int tsidonid)
 {
-       uint16_t stime_mjd = evt->getStartTimeMjd();
-       uint32_t stime_bcd = evt->getStartTimeBcd();
-       uint32_t duration = evt->getDuration();
-       m_begin = parseDVBtime(
-               stime_mjd >> 8,
-               stime_mjd&0xFF,
-               stime_bcd >> 16,
-               (stime_bcd >> 8)&0xFF,
-               stime_bcd & 0xFF
-       );
+       m_begin = parseDVBtime(evt->getStartTimeMjd(), evt->getStartTimeBcd());
        m_event_id = evt->getEventId();
        m_event_id = evt->getEventId();
+       uint32_t duration = evt->getDuration();
        m_duration = fromBCD(duration>>16)*3600+fromBCD(duration>>8)*60+fromBCD(duration);
        m_duration = fromBCD(duration>>16)*3600+fromBCD(duration>>8)*60+fromBCD(duration);
-       for (int i=0; i < MAX_LANG; i++)
-               if (m_language==ISOtbl[i][0])
-                       if (loadLanguage(evt, ISOtbl[i][1], tsidonid))
-                               return 0;
-       if (loadLanguage(evt, "eng", tsidonid))
+       uint8_t running_status = evt->getRunningStatus();
+       m_running_status = running_status;
+       if (m_language != "---" && loadLanguage(evt, m_language, tsidonid))
                return 0;
                return 0;
-       if (loadLanguage(evt, std::string(), tsidonid))
+       if (m_language_alternative != "---" && loadLanguage(evt, m_language_alternative, tsidonid))
+               return 0;
+       if (loadLanguage(evt, "---", tsidonid))
                return 0;
        return 0;
 }
 
                return 0;
        return 0;
 }
 
-RESULT eServiceEvent::parseFrom(const std::string filename, int tsidonid)
+RESULT eServiceEvent::parseFrom(const std::string &filename, int tsidonid)
 {
        if (!filename.empty())
        {
                int fd = ::open( filename.c_str(), O_RDONLY );
                if ( fd > -1 )
                {
 {
        if (!filename.empty())
        {
                int fd = ::open( filename.c_str(), O_RDONLY );
                if ( fd > -1 )
                {
-                       __u8 buf[4096];
+                       uint8_t buf[4096];
                        int rd = ::read(fd, buf, 4096);
                        ::close(fd);
                        if ( rd > 12 /*EIT_LOOP_SIZE*/ )
                        int rd = ::read(fd, buf, 4096);
                        ::close(fd);
                        if ( rd > 12 /*EIT_LOOP_SIZE*/ )
@@ -224,6 +236,60 @@ std::string eServiceEvent::getBeginTimeString() const
        return std::string(tmp, 12);
 }
 
        return std::string(tmp, 12);
 }
 
+RESULT eServiceEvent::getGenreData(ePtr<eGenreData> &dest) const
+{
+       std::list<eGenreData>::const_iterator it = m_genres.begin();
+       for(;it != m_genres.end(); ++it) {
+               dest = new eGenreData(*it);
+               //  for now just return the first item on the list
+               return 0;
+       }
+       dest = 0;
+       return -1;
+}
+
+PyObject *eServiceEvent::getGenreData() const
+{
+       ePyObject ret = PyList_New(m_genres.size());
+       int cnt=0;
+       for (std::list<eGenreData>::const_iterator it(m_genres.begin()); it != m_genres.end(); ++it)
+       {
+               ePyObject tuple = PyTuple_New(4);
+               PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(it->getLevel1()));
+               PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->getLevel2()));
+               PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(it->getUser1()));
+               PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(it->getUser2()));
+               PyList_SET_ITEM(ret, cnt++, tuple);
+       }
+       return ret;
+}
+
+RESULT eServiceEvent::getParentalData(ePtr<eParentalData> &dest) const
+{
+       std::list<eParentalData>::const_iterator it = m_ratings.begin();
+       for(;it != m_ratings.end(); ++it) {
+               dest = new eParentalData(*it);
+               //  for now just return the first item on the list
+               return 0;
+       }
+       dest = 0;
+       return -1;
+}
+
+PyObject *eServiceEvent::getParentalData() const
+{
+       ePyObject ret = PyList_New(m_ratings.size());
+       int cnt = 0;
+       for (std::list<eParentalData>::const_iterator it(m_ratings.begin()); it != m_ratings.end(); ++it)
+       {
+               ePyObject tuple = PyTuple_New(2);
+               PyTuple_SET_ITEM(tuple, 0, PyString_FromString(it->getCountryCode().c_str()));
+               PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->getRating()));
+               PyList_SET_ITEM(ret, cnt++, tuple);
+       }
+       return ret;
+}
+
 RESULT eServiceEvent::getComponentData(ePtr<eComponentData> &dest, int tagnum) const
 {
        std::list<eComponentData>::const_iterator it =
 RESULT eServiceEvent::getComponentData(ePtr<eComponentData> &dest, int tagnum) const
 {
        std::list<eComponentData>::const_iterator it =
@@ -236,14 +302,14 @@ RESULT eServiceEvent::getComponentData(ePtr<eComponentData> &dest, int tagnum) c
                        return 0;
                }
        }
                        return 0;
                }
        }
-       dest=0;
+       dest = 0;
        return -1;
 }
 
 PyObject *eServiceEvent::getComponentData() const
 {
        ePyObject ret = PyList_New(m_component_data.size());
        return -1;
 }
 
 PyObject *eServiceEvent::getComponentData() const
 {
        ePyObject ret = PyList_New(m_component_data.size());
-       int cnt=0;
+       int cnt = 0;
        for (std::list<eComponentData>::const_iterator it(m_component_data.begin()); it != m_component_data.end(); ++it)
        {
                ePyObject tuple = PyTuple_New(5);
        for (std::list<eComponentData>::const_iterator it(m_component_data.begin()); it != m_component_data.end(); ++it)
        {
                ePyObject tuple = PyTuple_New(5);
@@ -291,9 +357,4 @@ RESULT eServiceEvent::getLinkageService(eServiceReference &service, eServiceRefe
        return -1;
 }
 
        return -1;
 }
 
-void setServiceEventLanguage(const std::string language)
-{
-       eServiceEvent::setEPGLanguage(language);
-}
-
 DEFINE_REF(eDebugClass);
 DEFINE_REF(eDebugClass);
index 4c35407..e637b55 100644 (file)
@@ -22,7 +22,7 @@ struct eComponentData
        std::string m_iso639LanguageCode;
        std::string m_text;
 public:
        std::string m_iso639LanguageCode;
        std::string m_text;
 public:
-       eComponentData(const eComponentData& d) { *this = d; } 
+       eComponentData(const eComponentData& d) { *this = d; }
        eComponentData() { m_streamContent = m_componentType = m_componentTag = 0; }
        int getStreamContent(void) const { return m_streamContent; }
        int getComponentType(void) const { return m_componentType; }
        eComponentData() { m_streamContent = m_componentType = m_componentTag = 0; }
        int getStreamContent(void) const { return m_streamContent; }
        int getComponentType(void) const { return m_componentType; }
@@ -32,30 +32,72 @@ public:
 };
 SWIG_TEMPLATE_TYPEDEF(ePtr<eComponentData>, eComponentDataPtr);
 
 };
 SWIG_TEMPLATE_TYPEDEF(ePtr<eComponentData>, eComponentDataPtr);
 
+SWIG_IGNORE(eGenreData);
+struct eGenreData
+{
+       friend class eServiceEvent;
+       DECLARE_REF(eGenreData);
+       uint8_t m_level1;
+       uint8_t m_level2;
+       uint8_t m_user1;
+       uint8_t m_user2;
+public:
+       eGenreData(const eGenreData& d) { *this = d; }
+       eGenreData() { m_level1 = m_level2 = m_user1 = m_user2 = 0; }
+       int getLevel1(void) const { return m_level1; }
+       int getLevel2(void) const { return m_level2; }
+       int getUser1(void) const { return m_user1; }
+       int getUser2(void) const { return m_user2; }
+};
+SWIG_TEMPLATE_TYPEDEF(ePtr<eGenreData>, eGenreDataPtr);
+
+SWIG_IGNORE(eParentalData);
+struct eParentalData
+{
+       friend class eServiceEvent;
+       DECLARE_REF(eParentalData);
+       std::string m_country_code;
+       uint8_t m_rating;
+public:
+       eParentalData(const eParentalData& d) { *this = d; }
+       eParentalData() { m_country_code = ""; m_rating = 0; }
+       std::string getCountryCode(void) const { return m_country_code; }
+       int getRating(void) const { return m_rating; }
+};
+SWIG_TEMPLATE_TYPEDEF(ePtr<eParentalData>, eParentalDataPtr);
+
+
 SWIG_ALLOW_OUTPUT_SIMPLE(eServiceReference);  // needed for SWIG_OUTPUT in eServiceEvent::getLinkageService
 
 SWIG_IGNORE(eServiceEvent);
 class eServiceEvent: public iObject
 {
        DECLARE_REF(eServiceEvent);
 SWIG_ALLOW_OUTPUT_SIMPLE(eServiceReference);  // needed for SWIG_OUTPUT in eServiceEvent::getLinkageService
 
 SWIG_IGNORE(eServiceEvent);
 class eServiceEvent: public iObject
 {
        DECLARE_REF(eServiceEvent);
-       bool loadLanguage(Event *event, std::string lang, int tsidonid);
+       bool loadLanguage(Event *event, const std::string &lang, int tsidonid);
        std::list<eComponentData> m_component_data;
        std::list<eServiceReference> m_linkage_services;
        std::list<eComponentData> m_component_data;
        std::list<eServiceReference> m_linkage_services;
+       std::list<eGenreData> m_genres;
+       std::list<eParentalData> m_ratings;
        time_t m_begin;
        int m_duration;
        int m_event_id;
        time_t m_begin;
        int m_duration;
        int m_event_id;
-       std::string m_event_name, m_short_description, m_extended_description;
-       static std::string m_language;
+       int m_pdc_pil;
+       int m_running_status;
+       std::string m_event_name, m_short_description, m_extended_description, m_tmp_extended_description;
+       static std::string m_language, m_language_alternative;
        // .. additional info
 public:
 #ifndef SWIG
        RESULT parseFrom(Event *evt, int tsidonid=0);
        // .. additional info
 public:
 #ifndef SWIG
        RESULT parseFrom(Event *evt, int tsidonid=0);
-       RESULT parseFrom(const std::string filename, int tsidonid=0);
-       static void setEPGLanguage( const std::string language );
+       RESULT parseFrom(const std::string &filename, int tsidonid=0);
+       static void setEPGLanguage(const std::string &language) { m_language = language; }
+       static void setEPGLanguageAlternative(const std::string &language) { m_language_alternative = language; }
 #endif
        time_t getBeginTime() const { return m_begin; }
        int getDuration() const { return m_duration; }
        int getEventId() const { return m_event_id; }
 #endif
        time_t getBeginTime() const { return m_begin; }
        int getDuration() const { return m_duration; }
        int getEventId() const { return m_event_id; }
+       int getPdcPil() const { return m_pdc_pil; }
+       int getRunningStatus() const { return m_running_status; }
        std::string getEventName() const { return m_event_name; }
        std::string getShortDescription() const { return m_short_description; }
        std::string getExtendedDescription() const { return m_extended_description; }
        std::string getEventName() const { return m_event_name; }
        std::string getShortDescription() const { return m_short_description; }
        std::string getExtendedDescription() const { return m_extended_description; }
@@ -64,13 +106,22 @@ public:
        PyObject *getComponentData() const;
        int getNumOfLinkageServices() const { return m_linkage_services.size(); }
        SWIG_VOID(RESULT) getLinkageService(eServiceReference &SWIG_OUTPUT, eServiceReference &parent, int num) const;
        PyObject *getComponentData() const;
        int getNumOfLinkageServices() const { return m_linkage_services.size(); }
        SWIG_VOID(RESULT) getLinkageService(eServiceReference &SWIG_OUTPUT, eServiceReference &parent, int num) const;
+       SWIG_VOID(RESULT) getGenreData(ePtr<eGenreData> &SWIG_OUTPUT) const;
+       PyObject *getGenreData() const;
+       SWIG_VOID(RESULT) getParentalData(ePtr<eParentalData> &SWIG_OUTPUT) const;
+       PyObject *getParentalData() const;
 };
 SWIG_TEMPLATE_TYPEDEF(ePtr<eServiceEvent>, eServiceEvent);
 SWIG_EXTEND(ePtr<eServiceEvent>,
 };
 SWIG_TEMPLATE_TYPEDEF(ePtr<eServiceEvent>, eServiceEvent);
 SWIG_EXTEND(ePtr<eServiceEvent>,
-       static void setEPGLanguage( const std::string language )
+       static void setEPGLanguage(const std::string &language)
+       {
+               eServiceEvent::setEPGLanguage(language);
+       }
+);
+SWIG_EXTEND(ePtr<eServiceEvent>,
+       static void setEPGLanguageAlternative(const std::string &language)
        {
        {
-               extern void setServiceEventLanguage(const std::string language);
-               setServiceEventLanguage(language);
+               eServiceEvent::setEPGLanguageAlternative(language);
        }
 );
 
        }
 );
 
index bc0f872..74ec80e 100644 (file)
@@ -19,7 +19,8 @@ public:
                idStructure,    // service_id == 0 is root
                idDVB,
                idFile,
                idStructure,    // service_id == 0 is root
                idDVB,
                idFile,
-               idUser=0x1000
+               idUser=0x1000,
+               idServiceMP3=0x1001
        };
        int type;
 
        };
        int type;
 
index 6ce66ae..b3d0992 100644 (file)
@@ -171,43 +171,10 @@ RESULT eDVBServiceRecord::prepare(const char *filename, time_t begTime, time_t e
                        ret = meta.updateMeta(m_filename) ? -255 : 0;
                        if (!ret)
                        {
                        ret = meta.updateMeta(m_filename) ? -255 : 0;
                        if (!ret)
                        {
-                               const eit_event_struct *event = 0;
-                               eEPGCache::getInstance()->Lock();
-                               if ( eit_event_id != -1 )
-                               {
-                                       eDebug("query epg event id %d", eit_event_id);
-                                       eEPGCache::getInstance()->lookupEventId(ref, eit_event_id, event);
-                               }
-                               if ( !event && (begTime != -1 && endTime != -1) )
-                               {
-                                       time_t queryTime = begTime + ((endTime-begTime)/2);
-                                       tm beg, end, query;
-                                       localtime_r(&begTime, &beg);
-                                       localtime_r(&endTime, &end);
-                                       localtime_r(&queryTime, &query);
-                                       eDebug("query stime %d:%d:%d, etime %d:%d:%d, qtime %d:%d:%d",
-                                               beg.tm_hour, beg.tm_min, beg.tm_sec,
-                                               end.tm_hour, end.tm_min, end.tm_sec,
-                                               query.tm_hour, query.tm_min, query.tm_sec);
-                                       eEPGCache::getInstance()->lookupEventTime(ref, queryTime, event);
-                               }
-                               if ( event )
-                               {
-                                       eDebug("found event.. store to disc");
-                                       std::string fname = m_filename;
-                                       fname.erase(fname.length()-2, 2);
-                                       fname+="eit";
-                                       int fd = open(fname.c_str(), O_CREAT|O_WRONLY, 0777);
-                                       if (fd>-1)
-                                       {
-                                               int evLen=HILO(event->descriptors_loop_length)+12/*EIT_LOOP_SIZE*/;
-                                               int wr = ::write( fd, (unsigned char*)event, evLen );
-                                               if ( wr != evLen )
-                                                       eDebug("eit write error (%m)");
-                                               ::close(fd);
-                                       }
-                               }
-                               eEPGCache::getInstance()->Unlock();
+                               std::string fname = filename;
+                               fname.erase(fname.length()-2, 2);
+                               fname += "eit";
+                               eEPGCache::getInstance()->saveEventToFile(fname.c_str(), ref, eit_event_id, begTime, endTime);
                        }
                }
                return ret;
                        }
                }
                return ret;
old mode 100755 (executable)
new mode 100644 (file)
index b3281a9..fbc8811
@@ -6,6 +6,7 @@
 #include <lib/base/init.h>
 #include <lib/base/nconfig.h>
 #include <lib/base/object.h>
 #include <lib/base/init.h>
 #include <lib/base/nconfig.h>
 #include <lib/base/object.h>
+#include <lib/dvb/epgcache.h>
 #include <lib/dvb/decoder.h>
 #include <lib/components/file_eraser.h>
 #include <lib/gui/esubtitle.h>
 #include <lib/dvb/decoder.h>
 #include <lib/components/file_eraser.h>
 #include <lib/gui/esubtitle.h>
@@ -228,14 +229,28 @@ int eStaticServiceMP3Info::getInfo(const eServiceReference &ref, int w)
        }
        return iServiceInformation::resNA;
 }
        }
        return iServiceInformation::resNA;
 }
+
+RESULT eStaticServiceMP3Info::getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &evt, time_t start_time)
+{
+       if (ref.path.find("://") != std::string::npos)
+       {
+               eServiceReference equivalentref(ref);
+               equivalentref.type = eServiceFactoryMP3::id;
+               equivalentref.path.clear();
+               return eEPGCache::getInstance()->lookupEventTime(equivalentref, start_time, evt);
+       }
+       evt = 0;
+       return -1;
+}
 
 // eServiceMP3
 int eServiceMP3::ac3_delay,
     eServiceMP3::pcm_delay;
 
 eServiceMP3::eServiceMP3(eServiceReference ref)
 
 // eServiceMP3
 int eServiceMP3::ac3_delay,
     eServiceMP3::pcm_delay;
 
 eServiceMP3::eServiceMP3(eServiceReference ref)
-       :m_ref(ref), m_pump(eApp, 1)
+       :m_ref(ref),
+       m_pump(eApp, 1),
+       m_nownext_timer(eTimer::create(eApp))
 {
        m_subtitle_sync_timer = eTimer::create(eApp);
        m_streamingsrc_timeout = 0;
 {
        m_subtitle_sync_timer = eTimer::create(eApp);
        m_streamingsrc_timeout = 0;
@@ -252,6 +267,7 @@ eServiceMP3::eServiceMP3(eServiceReference ref)
        audioSink = videoSink = NULL;
        CONNECT(m_subtitle_sync_timer->timeout, eServiceMP3::pushSubtitles);
        CONNECT(m_pump.recv_msg, eServiceMP3::gstPoll);
        audioSink = videoSink = NULL;
        CONNECT(m_subtitle_sync_timer->timeout, eServiceMP3::pushSubtitles);
        CONNECT(m_pump.recv_msg, eServiceMP3::gstPoll);
+       CONNECT(m_nownext_timer->timeout, eServiceMP3::updateEpgCacheNowNext);
        m_aspect = m_width = m_height = m_framerate = m_progressive = -1;
 
        m_state = stIdle;
        m_aspect = m_width = m_height = m_framerate = m_progressive = -1;
 
        m_state = stIdle;
@@ -462,6 +478,53 @@ eServiceMP3::~eServiceMP3()
        }
 }
 
        }
 }
 
+void eServiceMP3::updateEpgCacheNowNext()
+{
+       bool update = false;
+       ePtr<eServiceEvent> next = 0;
+       ePtr<eServiceEvent> ptr = 0;
+       eServiceReference ref(m_ref);
+       ref.type = eServiceFactoryMP3::id;
+       ref.path.clear();
+
+       if (eEPGCache::getInstance() && eEPGCache::getInstance()->lookupEventTime(ref, -1, ptr) >= 0)
+       {
+               ePtr<eServiceEvent> current = m_event_now;
+               if (!current || !ptr || current->getEventId() != ptr->getEventId())
+               {
+                       update = true;
+                       m_event_now = ptr;
+                       time_t next_time = ptr->getBeginTime() + ptr->getDuration();
+                       if (eEPGCache::getInstance()->lookupEventTime(ref, next_time, ptr) >= 0)
+                       {
+                               next = ptr;
+                               m_event_next = ptr;
+                       }
+               }
+       }
+
+       int refreshtime = 60;
+       if (!next)
+       {
+               next = m_event_next;
+       }
+       if (next)
+       {
+               time_t now = ::time(0);
+               refreshtime = (int)(next->getBeginTime() - now) + 3;
+               if (refreshtime <= 0 || refreshtime > 60)
+               {
+                       refreshtime = 60;
+               }
+       }
+
+       m_nownext_timer->startLongTimer(refreshtime);
+       if (update)
+       {
+               m_event((iPlayableService*)this, evUpdatedEventInfo);
+       }
+}
+
 DEFINE_REF(eServiceMP3);
 
 RESULT eServiceMP3::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
 DEFINE_REF(eServiceMP3);
 
 RESULT eServiceMP3::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
@@ -504,6 +567,7 @@ RESULT eServiceMP3::stop()
        //eDebug("eServiceMP3::stop %s", m_ref.path.c_str());
        gst_element_set_state(m_gst_playbin, GST_STATE_NULL);
        m_state = stStopped;
        //eDebug("eServiceMP3::stop %s", m_ref.path.c_str());
        gst_element_set_state(m_gst_playbin, GST_STATE_NULL);
        m_state = stStopped;
+       m_nownext_timer->stop();
 
        return 0;
 }
 
        return 0;
 }
@@ -786,6 +850,14 @@ RESULT eServiceMP3::getName(std::string &name)
        return 0;
 }
 
        return 0;
 }
 
+RESULT eServiceMP3::getEvent(ePtr<eServiceEvent> &evt, int nownext)
+{
+       evt = nownext ? m_event_next : m_event_now;
+       if (!evt)
+               return -1;
+       return 0;
+}
+
 int eServiceMP3::getInfo(int w)
 {
        const gchar *tag = 0;
 int eServiceMP3::getInfo(int w)
 {
        const gchar *tag = 0;
@@ -888,6 +960,24 @@ int eServiceMP3::getInfo(int w)
 
 std::string eServiceMP3::getInfoString(int w)
 {
 
 std::string eServiceMP3::getInfoString(int w)
 {
+       if ( m_sourceinfo.is_streaming )
+       {
+               switch (w)
+               {
+               case sProvider:
+                       return "IPTV";
+               case sServiceref:
+               {
+                       eServiceReference ref(m_ref);
+                       ref.type = eServiceFactoryMP3::id;
+                       ref.path.clear();
+                       return ref.toString();
+               }
+               default:
+                       break;
+               }
+       }
+
        if ( !m_stream_tags && w < sUser && w > 26 )
                return "";
        const gchar *tag = 0;
        if ( !m_stream_tags && w < sUser && w > 26 )
                return "";
        const gchar *tag = 0;
@@ -1373,6 +1463,8 @@ void eServiceMP3::gstBusCall(GstBus *bus, GstMessage *msg)
                                        setAC3Delay(ac3_delay);
                                        setPCMDelay(pcm_delay);
 
                                        setAC3Delay(ac3_delay);
                                        setPCMDelay(pcm_delay);
 
+                                       updateEpgCacheNowNext();
+
                                }       break;
                                case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
                                {
                                }       break;
                                case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
                                {
index 8ada1b5..4cbedf5 100644 (file)
@@ -41,6 +41,8 @@ public:
        RESULT getName(const eServiceReference &ref, std::string &name);
        int getLength(const eServiceReference &ref);
        int getInfo(const eServiceReference &ref, int w);
        RESULT getName(const eServiceReference &ref, std::string &name);
        int getLength(const eServiceReference &ref);
        int getInfo(const eServiceReference &ref, int w);
+       int isPlayable(const eServiceReference &ref, const eServiceReference &ignore, bool simulate) { return 1; }
+       RESULT getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &ptr, time_t start_time);
 };
 
 typedef struct _GstElement GstElement;
 };
 
 typedef struct _GstElement GstElement;
@@ -101,6 +103,7 @@ public:
 
                // iServiceInformation
        RESULT getName(std::string &name);
 
                // iServiceInformation
        RESULT getName(std::string &name);
+       RESULT getEvent(ePtr<eServiceEvent> &evt, int nownext);
        int getInfo(int w);
        std::string getInfoString(int w);
        PyObject *getInfoObject(int w);
        int getInfo(int w);
        std::string getInfoString(int w);
        PyObject *getInfoObject(int w);
@@ -181,6 +184,10 @@ public:
                std::string missing_codec;
        };
 
                std::string missing_codec;
        };
 
+protected:
+       ePtr<eTimer> m_nownext_timer;
+       ePtr<eServiceEvent> m_event_now, m_event_next;
+       void updateEpgCacheNowNext();
 private:
        static int pcm_delay;
        static int ac3_delay;
 private:
        static int pcm_delay;
        static int ac3_delay;