Update EPG Cache(thanks to open source community)
[vuplus_dvbapp] / lib / dvb / epgcache.cpp
index 4d32474..0d2545f 100644 (file)
@@ -1,26 +1,78 @@
 #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
 
+#include <deque>
+#include <string>
 #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/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>
 
-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)
@@ -33,7 +85,7 @@ const eServiceReference &handleGroup(const eServiceReference &ref)
                        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());
@@ -46,22 +98,30 @@ const eServiceReference &handleGroup(const eServiceReference &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)
-               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)
        {
-               __u8 *descr = data+ptr;
+               uint8_t *descr = data + ptr;
                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:
-                               case SHORT_EVENT_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;
-                                               __u8 *d = new __u8[descr_len];
+                                               uint8_t *d = new uint8_t[descr_len];
                                                memcpy(d, descr, descr_len);
-                                               descriptors[crc] = descriptorPair(1, d);
+                                               descriptors[crc] = DescriptorPair(1, d);
                                        }
                                        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
-                                       ptr += descr_len;
                                        break;
                        }
+                       ptr += descr_len;
                        size -= descr_len;
                }
                else
                        break;
        }
+       memcpy(rawEITdata, (uint8_t*)e, 10);
        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
 {
-       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
-                       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;
@@ -139,83 +288,95 @@ const eit_event_struct* eventData::get() const
 
 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)
 {
-       int size=0;
+       int size = 0;
        int id=0;
-       __u8 header[2];
-       descriptorPair p;
+       DescriptorPair p;
+       uint8_t header[2];
        fread(&size, sizeof(int), 1, f);
+       descriptors.rehash(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;
-               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;
-               CacheSize+=bytes;
        }
 }
 
 void eventData::save(FILE *f)
 {
+       if (isCacheCorrupt)
+               return;
        int size=descriptors.size();
-       descriptorMap::iterator it(descriptors.begin());
+       DescriptorMap::iterator it(descriptors.begin());
        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;
        }
 }
 
+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;
-pthread_mutex_t eEPGCache::cache_lock=
+static pthread_mutex_t cache_lock =
        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()
-       :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);
@@ -229,16 +390,15 @@ eEPGCache::eEPGCache()
                res_mgr->connectChannelAdded(slot(*this,&eEPGCache::DVBChannelAdded), m_chanAddedConn);
 
        instance=this;
-       memset(m_filename, 0, sizeof(m_filename));
 }
 
 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)
        {
-               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();
        }
@@ -246,15 +406,15 @@ void eEPGCache::setCacheFile(const char *path)
 
 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();
+                       m_running = true;
                        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;
@@ -265,7 +425,7 @@ void eEPGCache::timeUpdated()
                        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)
@@ -292,8 +452,7 @@ void eEPGCache::DVBChannelAdded(eDVBChannel *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
@@ -333,6 +492,36 @@ void eEPGCache::DVBChannelRunning(iDVBChannel *chan)
                                        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 )
                                {
@@ -361,8 +550,23 @@ void eEPGCache::DVBChannelRunning(iDVBChannel *chan)
                                        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
                                }
@@ -375,8 +579,7 @@ void eEPGCache::DVBChannelRunning(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;
@@ -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));
-                                       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
-                                       break;
+                                       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;
-       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
-                       && tmp->second->type != PRIVATE 
+                       && tmp->second->type != PRIVATE
 #endif
-#ifdef ENABLE_MHW
+#ifdef ENABLE_MHW_EPG
                        && 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);
-                       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;
-                       if (tmp == servicemap.second.begin())
+                       if (tmp == servicemap.byTime.begin())
                        {
-                               servicemap.second.erase(tmp);
+                               servicemap.byTime.erase(tmp);
                                break;
                        }
                        else
-                               servicemap.second.erase(tmp--);
+                               servicemap.byTime.erase(tmp--);
                        ret = true;
                }
                else
                {
-                       if (tmp == servicemap.second.begin())
+                       if (tmp == servicemap.byTime.begin())
                                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)
                {
-                       __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);
-                       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;
-                       servicemap.second.erase(tmp++);
+                       servicemap.byTime.erase(tmp++);
                        ret = true;
                }
                else
                        ++tmp;
-               if (tmp == servicemap.second.end())
+               if (tmp == servicemap.byTime.end())
                        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 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;
+#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)
-       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;
 
-       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);
 
-       if ( TM != 3599 && TM > -1)
+       if ( TM != 3599 && TM > -1 && channel)
                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
-       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)
        {
-               __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);
-               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;
@@ -569,32 +784,31 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel)
 
                        // 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 ?
-                       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 =
-                                       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;
-                                               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))
                                                {
-                                                       prevEventIt = servicemap.first.end();
-                                                       prevTimeIt = servicemap.second.end();
+                                                       prevEventIt = servicemap.byEvent.end();
+                                                       prevTimeIt = servicemap.byTime.end();
                                                }
                                                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
-                                               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 =
-                               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 &&
-                                       ev_it == servicemap.first.end() )
+                                       ev_it == servicemap.byEvent.end() )
                                        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
-                                       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
@@ -649,90 +862,90 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel)
                        {
                                // 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;
-                               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
-                               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 )
-                                       eFatal("tm_it->second != ev_it->second");
+                                       eFatal("[eEPGCache] tm_it->second != ev_it->second");
                                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 )
-                                       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 )
-                                       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 )
-                                       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))
                        {
-                               prevEventIt = servicemap.first.end();
-                               prevTimeIt = servicemap.second.end();
+                               prevEventIt = servicemap.byEvent.end();
+                               prevTimeIt = servicemap.byTime.end();
                        }
                }
 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;
-                       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;
-                       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);
 
-                       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;
-               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)
 {
-       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() )
                {
-                       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;
@@ -756,8 +969,8 @@ void eEPGCache::flushEPG(const uniqueEPGKey & s)
                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();
@@ -769,42 +982,38 @@ void eEPGCache::flushEPG(const uniqueEPGKey & s)
 #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();
        }
-       eDebug("[EPGC] %i bytes for cache used", eventData::CacheSize);
 }
 
 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 (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
-                                       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 ....)
-//                                             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
-//                                     eDebug("[EPGC] release heap mem");
+                                       //eDebug("[eEPGCache] release heap mem");
                                        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
@@ -817,7 +1026,7 @@ void eEPGCache::cleanLoop()
                                        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());
@@ -837,19 +1046,18 @@ void eEPGCache::cleanLoop()
                        }
 #endif
                }
-               eDebug("[EPGC] stop cleanloop");
-               eDebug("[EPGC] %i bytes for cache used", eventData::CacheSize);
-       }
+       } /* release lock */
        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++)
-               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;
 }
 
@@ -863,8 +1071,7 @@ void eEPGCache::gotMessage( const Message &msg )
                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;
@@ -872,8 +1079,7 @@ void eEPGCache::gotMessage( const Message &msg )
                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;
@@ -885,7 +1091,7 @@ void eEPGCache::gotMessage( const Message &msg )
                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;
@@ -906,9 +1112,9 @@ void eEPGCache::gotMessage( const Message &msg )
                                                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)
-                                               eDebug("[EPGC] next private update in %i sec", update/1000);
+                                               eDebug("[eEPGCache] next private update in %i sec", update/1000);
                                        break;
                                }
                        }
@@ -919,7 +1125,7 @@ void eEPGCache::gotMessage( const Message &msg )
                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;
@@ -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;
-                                       eDebug("[EPGC] got mhw2 channel pid %04x", msg.pid);
+                                       eDebug("[eEPGCache] got mhw2 channel pid %04x", msg.pid);
                                        break;
                                }
                        }
@@ -937,7 +1143,7 @@ void eEPGCache::gotMessage( const Message &msg )
                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;
@@ -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;
-                                       eDebug("[EPGC] got mhw2 title pid %04x", msg.pid);
+                                       eDebug("[eEPGCache] got mhw2 title pid %04x", msg.pid);
                                        break;
                                }
                        }
@@ -955,7 +1161,7 @@ void eEPGCache::gotMessage( const Message &msg )
                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;
@@ -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;
-                                       eDebug("[EPGC] got mhw2 summary pid %04x", msg.pid);
+                                       eDebug("[eEPGCache] got mhw2 summary pid %04x", msg.pid);
                                        break;
                                }
                        }
@@ -975,7 +1181,7 @@ void eEPGCache::gotMessage( const Message &msg )
                        cleanLoop();
                        break;
                default:
-                       eDebug("unhandled EPGCache Message!!");
+                       eDebug("[eEPGCache] unhandled EPGCache Message!!");
                        break;
        }
 }
@@ -983,137 +1189,177 @@ void eEPGCache::gotMessage( const Message &msg )
 void eEPGCache::thread()
 {
        hasStarted();
-       m_running=1;
        nice(4);
        load();
        cleanLoop();
        runLoop();
        save();
-       m_running=0;
 }
 
+static const char* EPGDAT_IN_FLASH = "/epg.dat";
+
 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;
-
+               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);
+                               EventCacheItem& item = eventDB[key]; /* Constructs new entry */
                                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
-                               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--)
                                        {
-                                               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--)
                                                {
-                                                       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()
 {
-       /* 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)
        {
-               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)
        {
-               eDebug("[EPGC] realpath to '%s' failed in save (%m)", m_filename);
+               eDebug("[eEPGCache] realpath to '%s' failed in save (%m)", EPGDAT);
                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) {
-               eDebug("[EPGC] statfs '%s' failed in save (%m)", buf);
+               eDebug("[eEPGCache] statfs '%s' failed in save (%m)", buf);
                fclose(f);
+               free(buf);
                return;
        }
 
@@ -1124,7 +1370,7 @@ void eEPGCache::save()
        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;
        }
@@ -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)
        {
-               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)
                {
-                       __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;
                }
        }
-       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";
@@ -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->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);
 }
 
-bool eEPGCache::channel_data::finishEPG()
+void eEPGCache::channel_data::finishEPG()
 {
        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);
-               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();
                }
-               singleLock l(cache->cache_lock);
-               cache->channelLastUpdated[channel->getChannelID()] = ::time(0);
 #ifdef ENABLE_MHW_EPG
-               cleanup();
+               cleanupMHW();
 #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()
 {
-       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)
@@ -1241,60 +1489,145 @@ void eEPGCache::channel_data::startEPG()
                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
-       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
-
        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);
 }
@@ -1305,28 +1638,72 @@ void eEPGCache::channel_data::abortNonAvail()
        {
                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) )
                {
-                       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) )
                {
-                       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;
                }
+#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) )
                {
-                       eDebug("[EPGC] abort non avail viasat reading");
+                       eDebug("[eEPGCache] abort non avail viasat reading");
                        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) )
                {
-                       eDebug("[EPGC] abort non avail mhw reading");
+                       eDebug("[eEPGCache] abort non avail mhw reading");
                        isRunning &= ~MHW;
                        m_MHWReader->stop();
                        m_MHWConn=0;
@@ -1354,6 +1731,12 @@ void eEPGCache::channel_data::abortNonAvail()
                                seenSections[i].clear();
                                calcedSections[i].clear();
                        }
+#ifdef ENABLE_MHW_EPG
+                       cleanupMHW();
+#endif
+#ifdef ENABLE_FREESAT
+                       cleanupFreeSat();
+#endif
                }
        }
        ++state;
@@ -1371,9 +1754,9 @@ void eEPGCache::channel_data::startChannel()
 
        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)
-               eDebug("[EPGC] next update in %i sec", update/1000);
+               eDebug("[eEPGCache] next update in %i sec", update/1000);
 }
 
 void eEPGCache::channel_data::abortEPG()
@@ -1383,11 +1766,17 @@ void eEPGCache::channel_data::abortEPG()
                seenSections[i].clear();
                calcedSections[i].clear();
        }
+#ifdef ENABLE_MHW_EPG
+       cleanupMHW();
+#endif
+#ifdef ENABLE_FREESAT
+       cleanupFreeSat();
+#endif
        abortTimer->stop();
        zapTimer->stop();
        if (isRunning)
        {
-               eDebug("[EPGC] abort caching events !!");
+               eDebug("[eEPGCache] abort caching events !!");
                if (isRunning & SCHEDULE)
                {
                        isRunning &= ~SCHEDULE;
@@ -1406,6 +1795,44 @@ void eEPGCache::channel_data::abortEPG()
                        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;
@@ -1432,52 +1859,57 @@ void eEPGCache::channel_data::abortEPG()
        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;
-       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;
-               case 0x50 ... 0x5F:
-                       reader=m_ScheduleReader;
-                       source=SCHEDULE;
-                       map=1;
+#ifdef ENABLE_NETMED
+               case NETMED_SCHEDULE:
+                       reader = m_NetmedScheduleReader;
+                       map = 1;
                        break;
-               case 0x60 ... 0x6F:
-                       reader=m_ScheduleOtherReader;
-                       source=SCHEDULE_OTHER;
-                       map=2;
+               case NETMED_SCHEDULE_OTHER:
+                       reader = m_NetmedScheduleOtherReader;
+                       map = 2;
                        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;
+#endif
                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 )
        {
-               eDebugNoNewLine("[EPGC] ");
+               eDebugNoNewLine("[eEPGCache] ");
                switch (source)
                {
                        case NOWNEXT:
@@ -1496,9 +1928,29 @@ void eEPGCache::channel_data::readData( const __u8 *data)
                                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;
                }
-               eDebug(" finished(%ld)", ::time(0));
+               eDebugNoNewLine(" finished(%ld)\n", ::time(0));
                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;
-               __u32 sectionNo = data[0] << 24;
+               uint32_t sectionNo = data[0] << 24;
                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);
-                       __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)
+                                       {
                                                calcedSections.insert(tmpval|(x&0xFF));
+                                       }
                                }
                                else
+                               {
                                        calcedSections.insert(tmpval|(i&0xFF));
+                               }
                        }
                        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 );
-       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);
-               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 ( x != It->second.second.end() )
+                               if ( x != It->second.byTime.end() )
                                {
                                        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;
 }
 
-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);
@@ -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);
+       result = NULL;
        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 )
 {
-       singleLock s(cache_lock);
        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;
@@ -1631,19 +2194,48 @@ RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id,
                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;
 }
 
-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);
-       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;
 }
 
@@ -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);
+       result = NULL;
        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 ( 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 ( 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()))
@@ -1698,9 +2291,9 @@ RESULT eEPGCache::startTimeQuery(const eServiceReference &service, time_t begin,
                }
 
                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
-                       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;
@@ -1708,26 +2301,6 @@ RESULT eEPGCache::startTimeQuery(const eServiceReference &service, time_t begin,
        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 )
@@ -1749,8 +2322,9 @@ RESULT eEPGCache::getNextTimeEntry(ePtr<eServiceEvent> &result)
        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;
@@ -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 = ptr ? PyLong_FromLong(ptr->getEventId()) : ePyObject();
+                               tmp = evData ? PyLong_FromLong(evData->getEventID()) : (ptr ? PyLong_FromLong(ptr->getEventId()) : ePyObject());
                                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
-                               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();
@@ -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 '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
-                               tmp = service;
+                               tmp = service_reference;
                                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();
-                               eDebug("fillTuple unknown '%c'... insert 'None' in result", c);
+                               eDebug("[eEPGCache] fillTuple unknown '%c'... insert 'None' in result", c);
                }
                if (!tmp)
                {
@@ -1815,7 +2395,7 @@ int handleEvent(eServiceEvent *ptr, ePyObject dest_list, const char* argstring,
 {
        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)
                {
@@ -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");
-                       eDebug("error in convertFunc execute");
+                       eDebug("[eEPGCache] handleEvent: error in convertFunc execute");
                        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);
-               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);
        }
@@ -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
+//   P = Event Parental Rating
+//   W = Event Content Description ('W'hat)
 //   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");
-               eDebug("no list");
+               eDebug("[eEPGCache] no list");
                return NULL;
        }
        int listIt=0;
@@ -1888,11 +2470,11 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc)
        if (!listSize)
        {
                PyErr_SetString(PyExc_StandardError,
-                       "not params given");
-               eDebug("not params given");
+                       "no params given");
+               eDebug("[eEPGCache] no params given");
                return NULL;
        }
-       else 
+       else
        {
                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);
-//             eDebug("have %d args('%s')", argcount, argstring);
+//             eDebug("[eEPGCache] have %d args('%s')", argcount, argstring);
        }
 
        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");
-                       eDebug("convertFunc is not callable");
+                       eDebug("[eEPGCache] convertFunc is not callable");
                        return NULL;
                }
                convertFuncArgs = PyTuple_New(argcount);
@@ -1952,7 +2534,7 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc)
                                        {
                                                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;
@@ -1962,7 +2544,7 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc)
                                                type=PyInt_AsLong(entry);
                                                if (type < -1 || type > 2)
                                                {
-                                                       eDebug("unknown type %d", type);
+                                                       eDebug("[eEPGCache] unknown type %d", type);
                                                        goto skip_entry;
                                                }
                                                break;
@@ -1973,7 +2555,7 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc)
                                                minutes=PyInt_AsLong(entry);
                                                break;
                                        default:
-                                               eDebug("unneeded extra argument");
+                                               eDebug("[eEPGCache] unneeded extra argument");
                                                break;
                                }
                        }
@@ -1982,12 +2564,6 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc)
                                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
@@ -2096,63 +2672,302 @@ skip_entry:
        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
+//   P = Event Parental Rating
+//   W = Event Content Description
 //   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)
-//     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)
+//     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 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)
@@ -2184,8 +3002,7 @@ void fillTuple2(ePyObject tuple, const char *argstring, int argcount, eventData
 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;
@@ -2211,11 +3028,14 @@ PyObject *eEPGCache::search(ePyObject arg)
 #endif
                                argstring = PyString_AS_STRING(obj);
                                for (int i=0; i < argcount; ++i)
+                               {
                                        switch(argstring[i])
                                        {
                                        case 'S':
                                        case 'E':
                                        case 'T':
+                                       case 'P':
+                                       case 'W':
                                                needServiceEvent=true;
                                                break;
                                        case 'N':
@@ -2230,20 +3050,24 @@ PyObject *eEPGCache::search(ePyObject arg)
                                        default:
                                                break;
                                        }
+                               }
                        }
                        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)
+               {
                        maxmatches = PyLong_AsLong(PyTuple_GET_ITEM(arg, 1));
+               }
                if (tuplesize > 2)
                {
                        querytype = PyLong_AsLong(PyTuple_GET_ITEM(arg, 2));
+
                        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)
                                                {
-                                                       __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())
                                                                {
-                                                                       __u8 *descr_data = it->second.second;
+                                                                       uint8_t *descr_data = it->second.data;
                                                                        switch(descr_data[0])
                                                                        {
                                                                        case 0x4D ... 0x4E:
-                                                                               descr[++descridx]=crc;
+                                                                               descr.push_back(crc);
+                                                                               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");
-                                               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");
-                                       eDebug("tuple arg 4 is not a string");
+                                       eDebug("[eEPGCache] tuple arg 4 is not a string");
                                        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))
@@ -2311,83 +3132,85 @@ PyObject *eEPGCache::search(ePyObject arg)
 #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);
-                                       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];
-                                                       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 ( 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
                                                        {
-                                                               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;
                                                                        }
-                                                                       ++idx;
+                                                                       title_len--;
+                                                                       titleptr++;
                                                                }
                                                        }
                                                }
                                        }
+                                       Py_END_ALLOW_THREADS;
                                }
                                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;
                                }
                        }
@@ -2395,7 +3218,7 @@ PyObject *eEPGCache::search(ePyObject arg)
                        {
                                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;
                        }
                }
@@ -2403,7 +3226,7 @@ PyObject *eEPGCache::search(ePyObject arg)
                {
                        PyErr_SetString(PyExc_StandardError,
                                "type error");
-                       eDebug("not enough args in tuple");
+                       eDebug("[eEPGCache] not enough args in tuple");
                        return NULL;
                }
        }
@@ -2411,11 +3234,11 @@ PyObject *eEPGCache::search(ePyObject arg)
        {
                PyErr_SetString(PyExc_StandardError,
                        "type error");
-               eDebug("arg 0 is not a tuple");
+               eDebug("[eEPGCache] arg 0 is not a tuple");
                return NULL;
        }
 
-       if (descridx > -1)
+       if (!descr.empty())
        {
                int maxcount=maxmatches;
                eServiceReferenceDVB ref(refstr?(const eServiceReferenceDVB&)handleGroup(eServiceReference(refstr)):eServiceReferenceDVB(""));
@@ -2432,105 +3255,118 @@ PyObject *eEPGCache::search(ePyObject arg)
                                ++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)
                        {
-                               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
-                               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;
+                                                       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;
-                                       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 )
@@ -2576,11 +3412,11 @@ void eEPGCache::PMTready(eDVBServicePMTHandler *pmthandler)
                                                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);
-                                                                       if (!strncmp((const char *)buffer+2, "EPGDATA", 7))
+                                                                       if (!memcmp((const char *)buffer+2, "EPGDATA", 7))
                                                                        {
                                                                                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));
                                                                                }
                                                                        }
-                                                                       else if(!strncmp((const char *)buffer+2, "FICHAS", 6))
+                                                                       else if(!memcmp((const char *)buffer+2, "FICHAS", 6))
                                                                        {
                                                                                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));
                                                                                }
                                                                        }
-                                                                       else if(!strncmp((const char *)buffer+2, "GENEROS", 7))
+                                                                       else if(!memcmp((const char *)buffer+2, "GENEROS", 7))
                                                                        {
                                                                                eServiceReferenceDVB ref;
                                                                                if (!pmthandler->getServiceReference(ref))
@@ -2625,7 +3461,7 @@ void eEPGCache::PMTready(eDVBServicePMTHandler *pmthandler)
                                                                break;
                                                        case 0x90:
                                                        {
-                                                               UnknownDescriptor *descr = (UnknownDescriptor*)*desc;
+                                                               Descriptor *descr = (Descriptor*)*desc;
                                                                int descr_len = descr->getLength();
                                                                if (descr_len == 4)
                                                                {
@@ -2657,27 +3493,27 @@ void eEPGCache::PMTready(eDVBServicePMTHandler *pmthandler)
                }
        }
        else
-               eDebug("PMTready but no pmt!!");
+               eDebug("[eEPGCache] PMTready but no pmt!!");
 }
 
 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;
        }
-       date_time( const __u8 data[5])
+       date_time( const uint8_t data[5])
        {
                memcpy(this->data, data, 5);
-               tm = parseDVBtime(data[0], data[1], data[2], data[3], data[4]);
+               tm = parseDVBtime(data);
        }
        date_time()
        {
        }
-       const __u8& operator[](int pos) const
+       const uint8_t& operator[](int pos) const
        {
                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;
-       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++];
 
-       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() )
                {
+                       // time_event_map can have other timestamp -> get timestamp from eventData
+                       time_t ev_time = evIt->second->getStartTime();
                        delete evIt->second;
                        evMap.erase(evIt);
+                       tmMap.erase(ev_time);
                }
-               tmMap.erase(it->second.first);
        }
        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]);
 
-       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++];
@@ -2768,7 +3606,7 @@ void eEPGCache::privateSectionRead(const uniqueEPGKey &current_service, const __
                                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++];
@@ -2795,13 +3633,13 @@ void eEPGCache::privateSectionRead(const uniqueEPGKey &current_service, const __
                }
        }
        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;
-       const __u8 **d=descriptors;
+       const uint8_t **d=descriptors;
        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;
-                       __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;
@@ -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);
-               __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);
-               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;
@@ -2860,7 +3698,7 @@ void eEPGCache::channel_data::startPrivateReader()
        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;
@@ -2873,7 +3711,7 @@ void eEPGCache::channel_data::startPrivateReader()
        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() )
        {
@@ -2882,7 +3720,7 @@ void eEPGCache::channel_data::readPrivateData( const __u8 *data)
        }
        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
@@ -2896,15 +3734,16 @@ void eEPGCache::channel_data::readPrivateData( const __u8 *data)
 #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();
 }
 
-__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.
@@ -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.
-       __u8 local_hours = hours;
+       uint8_t local_hours = hours;
        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);
-       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;
@@ -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 );
 }
 
-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.
 {
-       __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 ||
@@ -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;
 
-       __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();
 
@@ -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;
-               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 );
-               timeMHW2DVB( HILO(itTitle->second.duration), (u_char *) event_data+7 );
+               timeMHW2DVB( itTitle->second.getDuration(), (u_char *) event_data+7 );
        }
 
        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 );
 }
 
-void eEPGCache::channel_data::startTimeout(int msec)
+void eEPGCache::channel_data::startMHWTimeout(int msec)
 {
        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);
-//     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;
@@ -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;
-//             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;
-//             eDebug("start 0x%02x 0x%02x", pid, tid);
+//             eDebug("[eEPGCache] start 0x%02x 0x%02x", pid, tid);
        }
        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();
@@ -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)) )
        {
-               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
@@ -3195,7 +4034,7 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data)
                }
                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);
@@ -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;
-               __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];
@@ -3218,7 +4057,7 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data)
                        {
                                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
@@ -3226,30 +4065,32 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data)
 
                        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);
-               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;
+               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
-                       __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);
-                       __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() )
                        {
-                               startTimeout(4000);
+                               startMHWTimeout(4000);
                                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_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.
                        }
-                       else if (!checkTimeout())
+                       else if (!checkMHWTimeout())
                                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);
-                       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());
-                       startTimeout(4000);
+                       startMHWTimeout(4000);
                        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
-               __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];
 
-               // 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.
 
-               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 (!m_program_ids.empty() && !checkTimeout())
+                       if (!m_program_ids.empty() && !checkMHWTimeout())
                                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.
-                       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() )
                        {
-                               startTimeout(4000);
-                               storeTitle( itTitle, the_text, data );
+                               startMHWTimeout(4000);
+                               storeMHWTitle( itTitle, the_text, data );
                                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.
                }
        }
-       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.
-       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 )
@@ -3333,7 +4174,7 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data)
                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;
 
@@ -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)) )
        {
-               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
@@ -3369,7 +4210,7 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data)
                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;
@@ -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;
-//                     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)
@@ -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;
-//                     eDebug("%d(%02x) %s", i, i, channel.name);
+//                     eDebug("[eEPGCache] %d(%02x) %s", i, i, channel.name);
                }
                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
-               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
@@ -3408,7 +4249,7 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data)
                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] );
 
@@ -3423,11 +4264,11 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data)
                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())
-                               startTimeout(5000);
+                               startMHWTimeout(5000);
                        return; // continue reading
                }
 
@@ -3436,7 +4277,7 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data)
                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;
@@ -3450,37 +4291,37 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data)
                        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);
-                       __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())
-//                             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);
 
-//                     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;
 
-                       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() )
                        {
-                               startTimeout(5000);
+                               startMHWTimeout(5000);
                                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) {
@@ -3490,27 +4331,26 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data)
                                                ++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
                        {
-                               if ( !checkTimeout() )
+                               if ( !checkMHWTimeout() )
                                        continue;       // Continue reading of the current table.
                                finish=true;
                                break;
                        }
                }
-start_summary:
                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);
-                               startTimeout(15000);
+                               startMHWTimeout(15000);
                                return;
                        }
                }
@@ -3520,7 +4360,7 @@ start_summary:
        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;
@@ -3555,11 +4395,11 @@ start_summary:
                        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*));
 
@@ -3579,7 +4419,7 @@ start_summary:
                                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. */
@@ -3588,19 +4428,19 @@ start_summary:
                                }
                                else
                                {
-                                       startTimeout(15000);
+                                       startMHWTimeout(15000);
                                        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 )
                                        {
-//                                             eDebug(".");
+//                                             eDebug("[eEPGCache] .");
                                                // 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() )
                                                {
-                                                       storeTitle( itTitle, the_text, data );
+                                                       storeMHWTitle( itTitle, the_text, data );
                                                        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.
-                       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());
                }