Merge commit 'origin/bug_202_networkconfig_cleanup' into experimental
[enigma2.git] / lib / dvb / epgcache.cpp
index 1a07755f7eec10e1c897e68a23c0b5626e589139..48cbfbfdf4dc378621276d0d34fb3dcfb3668c3e 100644 (file)
@@ -213,13 +213,13 @@ pthread_mutex_t eEPGCache::channel_map_lock=
 DEFINE_REF(eEPGCache)
 
 eEPGCache::eEPGCache()
-       :messages(this,1), cleanTimer(this)//, paused(0)
+       :messages(this,1), cleanTimer(eTimer::create(this))//, paused(0)
 {
        eDebug("[EPGC] Initialized EPGCache");
 
        CONNECT(messages.recv_msg, eEPGCache::gotMessage);
        CONNECT(eDVBLocalTimeHandler::getInstance()->m_timeUpdated, eEPGCache::timeUpdated);
-       CONNECT(cleanTimer.timeout, eEPGCache::cleanLoop);
+       CONNECT(cleanTimer->timeout, eEPGCache::cleanLoop);
 
        ePtr<eDVBResourceManager> res_mgr;
        eDVBResourceManager::getInstance(res_mgr);
@@ -254,6 +254,11 @@ void eEPGCache::DVBChannelAdded(eDVBChannel *chan)
                data->prevChannelState = -1;
 #ifdef ENABLE_PRIVATE_EPG
                data->m_PrivatePid = -1;
+#endif
+#ifdef ENABLE_MHW_EPG
+               data->m_mhw2_channel_pid = 0x231; // defaults for astra 19.2 D+
+               data->m_mhw2_title_pid = 0x234; // defaults for astra 19.2 D+
+               data->m_mhw2_summary_pid = 0x236; // defaults for astra 19.2 D+
 #endif
                singleLock s(channel_map_lock);
                m_knownChannels.insert( std::pair<iDVBChannel*, channel_data* >(chan, data) );
@@ -303,6 +308,13 @@ void eEPGCache::DVBChannelRunning(iDVBChannel *chan)
                                        eDebug("[eEPGCache] couldnt initialize schedule other reader!!");
                                        return;
                                }
+
+                               res = demux->createSectionReader( this, data.m_ViasatReader );
+                               if ( res )
+                               {
+                                       eDebug("[eEPGCache] couldnt initialize viasat reader!!");
+                                       return;
+                               }
 #ifdef ENABLE_PRIVATE_EPG
                                res = demux->createSectionReader( this, data.m_PrivateReader );
                                if ( res )
@@ -472,7 +484,12 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel)
        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(
+                       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 now = ::time(0);
 
        if ( TM != 3599 && TM > -1)
@@ -487,6 +504,7 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel)
 
        while (ptr<len)
        {
+               __u16 event_hash;
                eit_event_size = HILO(eit_event->descriptors_loop_length)+EIT_LOOP_SIZE;
 
                duration = fromBCD(eit_event->duration_1)*3600+fromBCD(eit_event->duration_2)*60+fromBCD(eit_event->duration_3);
@@ -495,7 +513,8 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel)
                        eit_event->start_time_2,
                        eit_event->start_time_3,
                        eit_event->start_time_4,
-                       eit_event->start_time_5);
+                       eit_event->start_time_5,
+                       &event_hash);
 
                if ( TM == 3599 )
                        goto next;
@@ -506,16 +525,24 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel)
                if ( now <= (TM+duration) || TM == 3599 /*NVOD Service*/ )  // old events should not be cached
                {
                        __u16 event_id = HILO(eit_event->event_id);
-//                     eDebug("event_id is %d sid is %04x", event_id, service.sid);
-
                        eventData *evt = 0;
                        int ev_erase_count = 0;
                        int tm_erase_count = 0;
 
+                       if (event_id == 0) {
+                               // hack for some polsat services on 13.0E..... but this also replaces other valid event_ids with value 0..
+                               // but we dont care about it...
+                               event_id = event_hash;
+                               eit_event->event_id_hi = event_hash >> 8;
+                               eit_event->event_id_lo = event_hash & 0xFF;
+                       }
+
                        // search in eventmap
                        eventMap::iterator ev_it =
                                servicemap.first.find(event_id);
 
+//                     eDebug("event_id is %d sid is %04x", event_id, service.sid);
+
                        // entry with this event_id is already exist ?
                        if ( ev_it != servicemap.first.end() )
                        {
@@ -783,7 +810,7 @@ void eEPGCache::cleanLoop()
                eDebug("[EPGC] stop cleanloop");
                eDebug("[EPGC] %i bytes for cache used", eventData::CacheSize);
        }
-       cleanTimer.start(CLEAN_INTERVAL,true);
+       cleanTimer->start(CLEAN_INTERVAL,true);
 }
 
 eEPGCache::~eEPGCache()
@@ -847,7 +874,7 @@ void eEPGCache::gotMessage( const Message &msg )
                                        int update = ( It != channelLastUpdated.end() ? ( UPDATE_INTERVAL - ( (::time(0)-It->second) * 1000 ) ) : ZAP_DELAY );
                                        if (update < ZAP_DELAY)
                                                update = ZAP_DELAY;
-                                       data->startPrivateTimer.start(update, 1);
+                                       data->startPrivateTimer->start(update, 1);
                                        if (update >= 60000)
                                                eDebug("[EPGC] next private update in %i min", update/60000);
                                        else if (update >= 1000)
@@ -857,6 +884,62 @@ void eEPGCache::gotMessage( const Message &msg )
                        }
                        break;
                }
+#endif
+#ifdef ENABLE_MHW_EPG
+               case Message::got_mhw2_channel_pid:
+               {
+                       singleLock s(channel_map_lock);
+                       for (channelMapIterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it)
+                       {
+                               eDVBChannel *channel = (eDVBChannel*) it->first;
+                               channel_data *data = it->second;
+                               eDVBChannelID chid = channel->getChannelID();
+                               if ( chid.transport_stream_id.get() == msg.service.tsid &&
+                                       chid.original_network_id.get() == msg.service.onid )
+                               {
+                                       data->m_mhw2_channel_pid = msg.pid;
+                                       eDebug("[EPGC] got mhw2 channel pid %04x", msg.pid);
+                                       break;
+                               }
+                       }
+                       break;
+               }
+               case Message::got_mhw2_title_pid:
+               {
+                       singleLock s(channel_map_lock);
+                       for (channelMapIterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it)
+                       {
+                               eDVBChannel *channel = (eDVBChannel*) it->first;
+                               channel_data *data = it->second;
+                               eDVBChannelID chid = channel->getChannelID();
+                               if ( chid.transport_stream_id.get() == msg.service.tsid &&
+                                       chid.original_network_id.get() == msg.service.onid )
+                               {
+                                       data->m_mhw2_title_pid = msg.pid;
+                                       eDebug("[EPGC] got mhw2 title pid %04x", msg.pid);
+                                       break;
+                               }
+                       }
+                       break;
+               }
+               case Message::got_mhw2_summary_pid:
+               {
+                       singleLock s(channel_map_lock);
+                       for (channelMapIterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it)
+                       {
+                               eDVBChannel *channel = (eDVBChannel*) it->first;
+                               channel_data *data = it->second;
+                               eDVBChannelID chid = channel->getChannelID();
+                               if ( chid.transport_stream_id.get() == msg.service.tsid &&
+                                       chid.original_network_id.get() == msg.service.onid )
+                               {
+                                       data->m_mhw2_summary_pid = msg.pid;
+                                       eDebug("[EPGC] got mhw2 summary pid %04x", msg.pid);
+                                       break;
+                               }
+                       }
+                       break;
+               }
 #endif
                case Message::timeChanged:
                        cleanLoop();
@@ -1088,22 +1171,22 @@ void eEPGCache::save()
 
 eEPGCache::channel_data::channel_data(eEPGCache *ml)
        :cache(ml)
-       ,abortTimer(ml), zapTimer(ml), state(0)
+       ,abortTimer(eTimer::create(ml)), zapTimer(eTimer::create(ml)), state(0)
        ,isRunning(0), haveData(0)
 #ifdef ENABLE_PRIVATE_EPG
-       ,startPrivateTimer(ml)
+       ,startPrivateTimer(eTimer::create(ml))
 #endif
 #ifdef ENABLE_MHW_EPG
-       ,m_MHWTimeoutTimer(ml)
+       ,m_MHWTimeoutTimer(eTimer::create(ml))
 #endif
 {
 #ifdef ENABLE_MHW_EPG
-       CONNECT(m_MHWTimeoutTimer.timeout, eEPGCache::channel_data::MHWTimeout);
+       CONNECT(m_MHWTimeoutTimer->timeout, eEPGCache::channel_data::MHWTimeout);
 #endif
-       CONNECT(zapTimer.timeout, eEPGCache::channel_data::startEPG);
-       CONNECT(abortTimer.timeout, eEPGCache::channel_data::abortNonAvail);
+       CONNECT(zapTimer->timeout, eEPGCache::channel_data::startEPG);
+       CONNECT(abortTimer->timeout, eEPGCache::channel_data::abortNonAvail);
 #ifdef ENABLE_PRIVATE_EPG
-       CONNECT(startPrivateTimer.timeout, eEPGCache::channel_data::startPrivateReader);
+       CONNECT(startPrivateTimer->timeout, eEPGCache::channel_data::startPrivateReader);
 #endif
        pthread_mutex_init(&channel_active, 0);
 }
@@ -1113,9 +1196,9 @@ bool eEPGCache::channel_data::finishEPG()
        if (!isRunning)  // epg ready
        {
                eDebug("[EPGC] stop caching events(%ld)", ::time(0));
-               zapTimer.start(UPDATE_INTERVAL, 1);
+               zapTimer->start(UPDATE_INTERVAL, 1);
                eDebug("[EPGC] next update in %i min", UPDATE_INTERVAL / 60000);
-               for (int i=0; i < 3; ++i)
+               for (unsigned int i=0; i < sizeof(seenSections)/sizeof(tidMap); ++i)
                {
                        seenSections[i].clear();
                        calcedSections[i].clear();
@@ -1135,7 +1218,7 @@ void eEPGCache::channel_data::startEPG()
        eDebug("[EPGC] start caching events(%ld)", ::time(0));
        state=0;
        haveData=0;
-       for (int i=0; i < 3; ++i)
+       for (unsigned int i=0; i < sizeof(seenSections)/sizeof(tidMap); ++i)
        {
                seenSections[i].clear();
                calcedSections[i].clear();
@@ -1153,7 +1236,7 @@ void eEPGCache::channel_data::startEPG()
        isRunning |= MHW;
        memcpy(&m_MHWFilterMask, &mask, sizeof(eDVBSectionFilterMask));
 
-       mask.pid = 0x231;
+       mask.pid = m_mhw2_channel_pid;
        mask.data[0] = 0xC8;
        mask.mask[0] = 0xFF;
        mask.data[1] = 0;
@@ -1164,6 +1247,7 @@ void eEPGCache::channel_data::startEPG()
        memcpy(&m_MHWFilterMask2, &mask, sizeof(eDVBSectionFilterMask));
        mask.data[1] = 0;
        mask.mask[1] = 0;
+       m_MHWTimeoutet=false;
 #endif
 
        mask.pid = 0x12;
@@ -1186,7 +1270,15 @@ void eEPGCache::channel_data::startEPG()
        m_ScheduleOtherReader->start(mask);
        isRunning |= SCHEDULE_OTHER;
 
-       abortTimer.start(7000,true);
+       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;
+
+       abortTimer->start(7000,true);
 }
 
 void eEPGCache::channel_data::abortNonAvail()
@@ -1209,11 +1301,18 @@ void eEPGCache::channel_data::abortNonAvail()
                }
                if ( !(haveData&SCHEDULE_OTHER) && (isRunning&SCHEDULE_OTHER) )
                {
-                       eDebug("[EPGC] abort non avail schedule_other reading");
+                       eDebug("[EPGC] abort non avail schedule other reading");
                        isRunning &= ~SCHEDULE_OTHER;
                        m_ScheduleOtherReader->stop();
                        m_ScheduleOtherConn=0;
                }
+               if ( !(haveData&VIASAT) && (isRunning&VIASAT) )
+               {
+                       eDebug("[EPGC] abort non avail viasat reading");
+                       isRunning &= ~VIASAT;
+                       m_ViasatReader->stop();
+                       m_ViasatConn=0;
+               }
 #ifdef ENABLE_MHW_EPG
                if ( !(haveData&MHW) && (isRunning&MHW) )
                {
@@ -1225,12 +1324,14 @@ void eEPGCache::channel_data::abortNonAvail()
                        m_MHWConn2=0;
                }
 #endif
-               if ( isRunning )
-                       abortTimer.start(90000, true);
+               if ( isRunning & VIASAT )
+                       abortTimer->start(300000, true);
+               else if ( isRunning )
+                       abortTimer->start(90000, true);
                else
                {
                        ++state;
-                       for (int i=0; i < 3; ++i)
+                       for (unsigned int i=0; i < sizeof(seenSections)/sizeof(tidMap); ++i)
                        {
                                seenSections[i].clear();
                                calcedSections[i].clear();
@@ -1250,7 +1351,7 @@ void eEPGCache::channel_data::startChannel()
        if (update < ZAP_DELAY)
                update = ZAP_DELAY;
 
-       zapTimer.start(update, 1);
+       zapTimer->start(update, 1);
        if (update >= 60000)
                eDebug("[EPGC] next update in %i min", update/60000);
        else if (update >= 1000)
@@ -1259,13 +1360,13 @@ void eEPGCache::channel_data::startChannel()
 
 void eEPGCache::channel_data::abortEPG()
 {
-       for (int i=0; i < 3; ++i)
+       for (unsigned int i=0; i < sizeof(seenSections)/sizeof(tidMap); ++i)
        {
                seenSections[i].clear();
                calcedSections[i].clear();
        }
-       abortTimer.stop();
-       zapTimer.stop();
+       abortTimer->stop();
+       zapTimer->stop();
        if (isRunning)
        {
                eDebug("[EPGC] abort caching events !!");
@@ -1287,6 +1388,12 @@ void eEPGCache::channel_data::abortEPG()
                        m_ScheduleOtherReader->stop();
                        m_ScheduleOtherConn=0;
                }
+               if (isRunning & VIASAT)
+               {
+                       isRunning &= ~VIASAT;
+                       m_ViasatReader->stop();
+                       m_ViasatConn=0;
+               }
 #ifdef ENABLE_MHW_EPG
                if (isRunning & MHW)
                {
@@ -1307,6 +1414,15 @@ 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)
 {
        int source;
@@ -1329,6 +1445,12 @@ void eEPGCache::channel_data::readData( const __u8 *data)
                        source=SCHEDULE_OTHER;
                        map=2;
                        break;
+               case 0xD0 ... 0xDF:
+               case 0xE0 ... 0xEF:
+                       reader=m_ViasatReader;
+                       source=VIASAT;
+                       map=3;
+                       break;
                default:
                        eDebug("[EPGC] unknown table_id !!!");
                        return;
@@ -1352,6 +1474,10 @@ void eEPGCache::channel_data::readData( const __u8 *data)
                                m_ScheduleOtherConn=0;
                                eDebugNoNewLine("schedule other");
                                break;
+                       case VIASAT:
+                               m_ViasatConn=0;
+                               eDebugNoNewLine("viasat");
+                               break;
                        default: eDebugNoNewLine("unknown");break;
                }
                eDebug(" finished(%ld)", ::time(0));
@@ -1653,6 +1779,7 @@ void fillTuple(ePyObject tuple, const char *argstring, int argcount, ePyObject s
                                ++argcount;
                                continue;
                        default:  // ignore unknown
+                               tmp = ePyObject();
                                eDebug("fillTuple unknown '%c'... insert 'None' in result", c);
                }
                if (!tmp)
@@ -1672,7 +1799,7 @@ int handleEvent(eServiceEvent *ptr, ePyObject dest_list, const char* argstring,
        {
                fillTuple(convertFuncArgs, argstring, argcount, service, ptr, nowTime, service_name);
                ePyObject result = PyObject_CallObject(convertFunc, convertFuncArgs);
-               if (result)
+               if (!result)
                {
                        if (service_name)
                                Py_DECREF(service_name);
@@ -1997,6 +2124,7 @@ void fillTuple2(ePyObject tuple, const char *argstring, int argcount, eventData
                                inc_refcount = true;
                                break;
                        default:  // ignore unknown
+                               tmp = ePyObject();
                                eDebug("fillTuple2 unknown '%c'... insert None in Result", argstring[pos]);
                }
                if (!tmp)
@@ -2047,6 +2175,8 @@ PyObject *eEPGCache::search(ePyObject arg)
        int querytype=-1;
        bool needServiceEvent=false;
        int maxmatches=0;
+       int must_get_service_name = 0;
+       bool must_get_service_reference = false;
 
        if (PyTuple_Check(arg))
        {
@@ -2056,7 +2186,11 @@ PyObject *eEPGCache::search(ePyObject arg)
                        ePyObject obj = PyTuple_GET_ITEM(arg,0);
                        if (PyString_Check(obj))
                        {
+#if PY_VERSION_HEX < 0x02060000
                                argcount = PyString_GET_SIZE(obj);
+#else
+                               argcount = PyString_Size(obj);
+#endif
                                argstring = PyString_AS_STRING(obj);
                                for (int i=0; i < argcount; ++i)
                                        switch(argstring[i])
@@ -2065,6 +2199,16 @@ PyObject *eEPGCache::search(ePyObject arg)
                                        case 'E':
                                        case 'T':
                                                needServiceEvent=true;
+                                               break;
+                                       case 'N':
+                                               must_get_service_name = 1;
+                                               break;
+                                       case 'n':
+                                               must_get_service_name = 2;
+                                               break;
+                                       case 'R':
+                                               must_get_service_reference = true;
+                                               break;
                                        default:
                                                break;
                                        }
@@ -2144,7 +2288,11 @@ PyObject *eEPGCache::search(ePyObject arg)
                                {
                                        int casetype = PyLong_AsLong(PyTuple_GET_ITEM(arg, 4));
                                        const char *str = PyString_AS_STRING(obj);
+#if PY_VERSION_HEX < 0x02060000
                                        int textlen = PyString_GET_SIZE(obj);
+#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
@@ -2159,22 +2307,32 @@ PyObject *eEPGCache::search(ePyObject arg)
                                                        int title_len = data[5];
                                                        if ( querytype == 1 )
                                                        {
-                                                               if (title_len > textlen)
-                                                                       continue;
-                                                               else if (title_len < textlen)
+                                                               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;
+                                                               }
+                                                               if (title_len != textlen)
                                                                        continue;
                                                                if ( casetype )
                                                                {
-                                                                       if ( !strncasecmp((const char*)data+6, str, title_len) )
+                                                                       if ( !strncasecmp((const char*)data+offs, str, title_len) )
                                                                        {
-//                                                                             std::string s((const char*)data+6, title_len);
+//                                                                             std::string s((const char*)data+offs, title_len);
 //                                                                             eDebug("match1 %s %s", str, s.c_str() );
                                                                                descr[++descridx] = it->first;
                                                                        }
                                                                }
-                                                               else if ( !strncmp((const char*)data+6, str, title_len) )
+                                                               else if ( !strncmp((const char*)data+offs, str, title_len) )
                                                                {
-//                                                                     std::string s((const char*)data+6, title_len);
+//                                                                     std::string s((const char*)data+offs, title_len);
 //                                                                     eDebug("match2 %s %s", str, s.c_str() );
                                                                        descr[++descridx] = it->first;
                                                                }
@@ -2193,13 +2351,13 @@ PyObject *eEPGCache::search(ePyObject arg)
 //                                                                                     eDebug("match 3 %s %s", str, s.c_str() );
                                                                                        break;
                                                                                }
-                                                                               else if (!strncmp((const char*)data+6+idx, str, textlen) )
-                                                                               {
-                                                                                       descr[++descridx] = it->first;
-//                                                                                     std::string s((const char*)data+6, title_len);
-//                                                                                     eDebug("match 4 %s %s", str, s.c_str() );
-                                                                                       break;
-                                                                               }
+                                                                       }
+                                                                       else if (!strncmp((const char*)data+6+idx, str, textlen) )
+                                                                       {
+                                                                               descr[++descridx] = it->first;
+//                                                                             std::string s((const char*)data+6, title_len);
+//                                                                             eDebug("match 4 %s %s", str, s.c_str() );
+                                                                               break;
                                                                        }
                                                                        ++idx;
                                                                }
@@ -2303,44 +2461,40 @@ PyObject *eEPGCache::search(ePyObject arg)
                                                        }
                                                }
                                        // create service name
-                                               if (!service_name)
+                                               if (must_get_service_name && !service_name)
                                                {
-                                                       int must_get_service_name = strchr(argstring, 'N') ? 1 : strchr(argstring, 'n') ? 2 : 0;
-                                                       if (must_get_service_name)
+                                                       ePtr<iStaticServiceInformation> sptr;
+                                                       eServiceCenterPtr service_center;
+                                                       eServiceCenter::getPrivInstance(service_center);
+                                                       if (service_center)
                                                        {
-                                                               ePtr<iStaticServiceInformation> sptr;
-                                                               eServiceCenterPtr service_center;
-                                                               eServiceCenter::getPrivInstance(service_center);
-                                                               if (service_center)
+                                                               service_center->info(ref, sptr);
+                                                               if (sptr)
                                                                {
-                                                                       service_center->info(ref, sptr);
-                                                                       if (sptr)
-                                                                       {
-                                                                               std::string name;
-                                                                               sptr->getName(ref, name);
-
-                                                                               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);
+                                                                       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 (!service_reference && strchr(argstring,'R'))
+                                               if (must_get_service_reference && !service_reference)
                                                        service_reference = PyString_FromString(ref.toString().c_str());
                                        // create list
                                                if (!ret)
@@ -2397,6 +2551,50 @@ void eEPGCache::PMTready(eDVBServicePMTHandler *pmthandler)
                                int tmp=0;
                                switch ((*es)->getType())
                                {
+                               case 0xC1: // user private
+                                       for (DescriptorConstIterator desc = (*es)->getDescriptors()->begin();
+                                               desc != (*es)->getDescriptors()->end(); ++desc)
+                                       {
+                                               switch ((*desc)->getTag())
+                                               {
+                                                       case 0xC2: // user defined
+                                                               if ((*desc)->getLength() == 8) 
+                                                               {
+                                                                       __u8 buffer[10];
+                                                                       (*desc)->writeToBuffer(buffer);
+                                                                       if (!strncmp((unsigned char*)buffer+2, "EPGDATA", 7))
+                                                                       {
+                                                                               eServiceReferenceDVB ref;
+                                                                               if (!pmthandler->getServiceReference(ref))
+                                                                               {
+                                                                                       int pid = (*es)->getPid();
+                                                                                       messages.send(Message(Message::got_mhw2_channel_pid, ref, pid));
+                                                                               }
+                                                                       }
+                                                                       else if(!strncmp((unsigned char*)buffer+2, "FICHAS", 6))
+                                                                       {
+                                                                               eServiceReferenceDVB ref;
+                                                                               if (!pmthandler->getServiceReference(ref))
+                                                                               {
+                                                                                       int pid = (*es)->getPid();
+                                                                                       messages.send(Message(Message::got_mhw2_summary_pid, ref, pid));
+                                                                               }
+                                                                       }
+                                                                       else if(!strncmp((unsigned char*)buffer+2, "GENEROS", 7))
+                                                                       {
+                                                                               eServiceReferenceDVB ref;
+                                                                               if (!pmthandler->getServiceReference(ref))
+                                                                               {
+                                                                                       int pid = (*es)->getPid();
+                                                                                       messages.send(Message(Message::got_mhw2_title_pid, ref, pid));
+                                                                               }
+                                                                       }
+                                                               }
+                                                               break;
+                                                       default:
+                                                               break;
+                                               }
+                                       }
                                case 0x05: // private
                                        for (DescriptorConstIterator desc = (*es)->getDescriptors()->begin();
                                                desc != (*es)->getDescriptors()->end(); ++desc)
@@ -2578,7 +2776,7 @@ void eEPGCache::privateSectionRead(const uniqueEPGKey &current_service, const __
                        }
                }
        }
-       ASSERT(pdescr <= &descriptors[65])
+       ASSERT(pdescr <= &descriptors[65]);
        __u8 event[4098];
        eit_event_struct *ev_struct = (eit_event_struct*) event;
        ev_struct->running_status = 0;
@@ -2721,6 +2919,7 @@ void eEPGCache::channel_data::timeMHW2DVB( int minutes, u_char *return_time)
 void eEPGCache::channel_data::timeMHW2DVB( u_char day, u_char hours, u_char minutes, u_char *return_time)
 // For date plus time of day
 {
+       char tz_saved[1024];
        // Remove offset in mhw time.
        __u8 local_hours = hours;
        if ( hours >= 16 )
@@ -2733,6 +2932,8 @@ void eEPGCache::channel_data::timeMHW2DVB( u_char day, u_char hours, u_char minu
        time_t dt = ::time(0);
 
        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");
        tzset();
 
@@ -2755,7 +2956,7 @@ void eEPGCache::channel_data::timeMHW2DVB( u_char day, u_char hours, u_char minu
        if ( old_tz == NULL )
                unsetenv( "TZ" );
        else
-               putenv( old_tz );
+               setenv("TZ", tz_saved, 1);
        tzset();
 
        // Calculate MJD according to annex in ETSI EN 300 468
@@ -2798,7 +2999,7 @@ void eEPGCache::channel_data::storeTitle(std::map<__u32, mhw_title_t>::iterator
        packet->segment_last_table_id = 0x50;
 
        __u8 *title = isMHW2 ? ((__u8*)(itTitle->second.title))-4 : (__u8*)itTitle->second.title;
-       std::string prog_title = (char *) delimitName( title, name, isMHW2 ? 33 : 23 );
+       std::string prog_title = (char *) delimitName( title, name, isMHW2 ? 35 : 23 );
        int prog_title_length = prog_title.length();
 
        int packet_length = EIT_SIZE + EIT_LOOP_SIZE + EIT_SHORT_EVENT_DESCRIPTOR_SIZE +
@@ -2919,7 +3120,7 @@ void eEPGCache::channel_data::storeTitle(std::map<__u32, mhw_title_t>::iterator
 
 void eEPGCache::channel_data::startTimeout(int msec)
 {
-       m_MHWTimeoutTimer.start(msec,true);
+       m_MHWTimeoutTimer->start(msec,true);
        m_MHWTimeoutet=false;
 }
 
@@ -2957,7 +3158,7 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data)
 
        if ( state > 1 || // aborted
                // have si data.. so we dont read mhw data
-               (haveData & (SCHEDULE|SCHEDULE_OTHER)) )
+               (haveData & (SCHEDULE|SCHEDULE_OTHER|VIASAT)) )
        {
                eDebug("[EPGC] mhw aborted %d", state);
        }
@@ -3123,18 +3324,18 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data)
 
        if ( state > 1 || // aborted
                // have si data.. so we dont read mhw data
-               (haveData & (eEPGCache::SCHEDULE|eEPGCache::SCHEDULE_OTHER)) )
+               (haveData & (SCHEDULE|SCHEDULE_OTHER|VIASAT)) )
        {
                eDebug("[EPGC] mhw2 aborted %d", state);
        }
-       else if (m_MHWFilterMask2.pid == 0x231 && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 0)
+       else if (m_MHWFilterMask2.pid == m_mhw2_channel_pid && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 0)
        // Channels table
        {
-               int num_channels = data[119];
+               int num_channels = data[120];
                m_channels.resize(num_channels);
-               if(dataLen > 119)
+               if(dataLen > 120)
                {
-                       int ptr = 120 + 8 * num_channels;
+                       int ptr = 121 + 8 * num_channels;
                        if( dataLen > ptr )
                        {
                                for( int chid = 0; chid < num_channels; ++chid )
@@ -3150,7 +3351,7 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data)
                else
                        goto abort;
                // data seems consistent...
-               const __u8 *tmp = data+120;
+               const __u8 *tmp = data+121;
                for (int i=0; i < num_channels; ++i)
                {
                        mhw_channel_name_t channel;
@@ -3161,6 +3362,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));
                        tmp+=2;
                }
                for (int i=0; i < num_channels; ++i)
@@ -3171,83 +3373,86 @@ 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);
                }
                haveData |= MHW;
                eDebug("[EPGC] mhw2 %d channels found", m_channels.size());
        }
-       else if (m_MHWFilterMask2.pid == 0x231 && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 1)
+       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");
        }
-       else if (m_MHWFilterMask2.pid == 0x234 && m_MHWFilterMask2.data[0] == 0xe6)
+       else if (m_MHWFilterMask2.pid == m_mhw2_title_pid && m_MHWFilterMask2.data[0] == 0xe6)
        // Titles table
        {
                int pos=18;
-               bool valid=true;
-               int len = ((data[1]&0xf)<<8) + data[2] - 16;
+               bool valid=false;
                bool finish=false;
-               if(data[dataLen-1] != 0xff)
-                       return;
-               while( pos < dataLen )
+
+//             eDebug("%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] );
+
+               while( pos < dataLen && !valid)
                {
-                       valid = false;
-                       pos += 7;
-                       if( pos < dataLen )
-                       {
-                               pos += 3;
-                               if( pos < dataLen )
-                               {
-                                       if( data[pos] > 0xc0 )
-                                       {
-                                               pos += ( data[pos] - 0xc0 );
-                                               pos += 4;
-                                               if( pos < dataLen )
-                                               {
-                                                       if( data[pos] == 0xff )
-                                                       {
-                                                               ++pos;
-                                                               valid = true;
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-                       if( !valid )
-                       {
-                               if (checkTimeout())
-                                       goto start_summary;
-                               return;
-                       }
+                       pos += 18;
+                       pos += (data[pos] & 0x3F) + 4;
+                       if( pos == dataLen )
+                               valid = true;
+               }
+
+               if (!valid)
+               {
+                       if (dataLen > 18)
+                               eDebug("mhw2 title table invalid!!");
+                       if (checkTimeout())
+                               goto abort;
+                       if (!m_MHWTimeoutTimer->isActive())
+                               startTimeout(5000);
+                       return; // continue reading
                }
+
                // data seems consistent...
                mhw_title_t title;
                pos = 18;
-               while (pos < len)
+               while (pos < dataLen)
                {
+//                     eDebugNoNewLine("    [%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;
-                       title.program_id_ml = data[pos+1];
-                       title.program_id_lo = data[pos+2];
-                       title.mhw2_mjd_hi = data[pos+3];
-                       title.mhw2_mjd_lo = data[pos+4];
-                       title.mhw2_hours = data[pos+5];
-                       title.mhw2_minutes = data[pos+6];
-                       title.mhw2_seconds = data[pos+7];
-                       int duration = ((data[pos+8] << 8)|data[pos+9]) >> 4;
+                       title.mhw2_mjd_hi = data[pos+11];
+                       title.mhw2_mjd_lo = data[pos+12];
+                       title.mhw2_hours = data[pos+13];
+                       title.mhw2_minutes = data[pos+14];
+                       title.mhw2_seconds = data[pos+15];
+                       int duration = ((data[pos+16] << 8)|data[pos+17]) >> 4;
                        title.mhw2_duration_hi = (duration&0xFF00) >> 8;
                        title.mhw2_duration_lo = duration&0xFF;
-                       __u8 slen = data[pos+10] & 0x3f;
+
+                       // Create unique key per title
+                       __u32 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;
-                       memcpy(dest, &data[pos+11], slen>33 ? 33 : slen);
-                       memset(dest+slen, 0, 33-slen);
-                       pos += 11 + slen;
+                       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];
 
-                       // Create unique key per title
-                       __u32 title_id = (title.channel_id<<16) | (title.program_id_ml<<8) | title.program_id_lo;
+//                     if (title.channel_id > m_channels.size())
+//                             eDebug("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",
+//                             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);
 
-                       pos += 4;
+                       pos += 3;
 
                        std::map<__u32, mhw_title_t>::iterator it = m_titles.find( title_id );
                        if ( it == m_titles.end() )
@@ -3286,7 +3491,7 @@ start_summary:
                        {
                                // Titles table has been read, there are summaries to read.
                                // Start reading summaries, store corresponding titles on the fly.
-                               startMHWReader2(0x236, 0x96);
+                               startMHWReader2(m_mhw2_summary_pid, 0x96);
                                startTimeout(15000);
                                return;
                        }
@@ -3294,7 +3499,7 @@ start_summary:
                else
                        return;
        }
-       else if (m_MHWFilterMask2.pid == 0x236 && m_MHWFilterMask2.data[0] == 0x96)
+       else if (m_MHWFilterMask2.pid == m_mhw2_summary_pid && m_MHWFilterMask2.data[0] == 0x96)
        // Summaries table
        {
                if (!checkTimeout())
@@ -3328,10 +3533,13 @@ start_summary:
                        }
                        else
                                return;  // continue reading
+
                        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] );
 
                                // ugly workaround to convert const __u8* to char*
                                char *tmp=0;
@@ -3349,7 +3557,7 @@ start_summary:
                                        len += lenline + 1;
                                }
                                if( len > 0 )
-                                   tmp[pos+len] = 0;
+                                       tmp[pos+len] = 0;
                                else
                                        tmp[pos+1] = 0;
 
@@ -3365,8 +3573,11 @@ start_summary:
                                        startTimeout(15000);
                                        std::string the_text = (char *) (data + pos + 1);
 
+//                                     eDebug ("summary id %04x : %s\n", summary_id, data+pos+1);
+
                                        while( itProgId != m_program_ids.end() && itProgId->first == summary_id )
                                        {
+//                                             eDebug(".");
                                                // Find corresponding title, store title and summary in epgcache.
                                                std::map<__u32, mhw_title_t>::iterator itTitle( m_titles.find( itProgId->second ) );
                                                if ( itTitle != m_titles.end() )
@@ -3386,16 +3597,16 @@ start_summary:
        }
        if (isRunning & eEPGCache::MHW)
        {
-               if ( m_MHWFilterMask2.pid == 0x231 && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 0)
+               if ( m_MHWFilterMask2.pid == m_mhw2_channel_pid && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 0)
                {
                        // Channels table has been read, start reading the themes table.
-                       startMHWReader2(0x231, 0xC8, 1);
+                       startMHWReader2(m_mhw2_channel_pid, 0xC8, 1);
                        return;
                }
-               else if ( m_MHWFilterMask2.pid == 0x231 && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 1)
+               else if ( m_MHWFilterMask2.pid == m_mhw2_channel_pid && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 1)
                {
                        // Themes table has been read, start reading the titles table.
-                       startMHWReader2(0x234, 0xe6);
+                       startMHWReader2(m_mhw2_title_pid, 0xe6);
                        return;
                }
                else