fix deprecated conversion from string constant to char* by using const char* instead...
[enigma2.git] / lib / dvb / epgcache.cpp
index 633310618bf6b5f8cf7651592847fbea9454fd3c..cab02201c3236b3820ccc12d5cb0586023463e26 100644 (file)
@@ -12,6 +12,7 @@
 #include <sys/vfs.h> // for statfs
 // #include <libmd5sum.h>
 #include <lib/base/eerror.h>
+#include <lib/base/estring.h>
 #include <lib/dvb/pmt.h>
 #include <lib/dvb/db.h>
 #include <lib/python/python.h>
@@ -45,7 +46,6 @@ 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)
 {
@@ -226,7 +226,11 @@ eEPGCache::eEPGCache()
        if (!res_mgr)
                eDebug("[eEPGCache] no resource manager !!!!!!!");
        else
+       {
                res_mgr->connectChannelAdded(slot(*this,&eEPGCache::DVBChannelAdded), m_chanAddedConn);
+               if (eDVBLocalTimeHandler::getInstance()->ready())
+                       timeUpdated();
+       }
        instance=this;
 }
 
@@ -368,8 +372,9 @@ void eEPGCache::DVBChannelStateChanged(iDVBChannel *chan)
        }
 }
 
-void eEPGCache::FixOverlapping(std::pair<eventMap,timeMap> &servicemap, time_t TM, int duration, const timeMap::iterator &tm_it, const uniqueEPGKey &service)
+bool eEPGCache::FixOverlapping(std::pair<eventMap,timeMap> &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)
        {
@@ -402,6 +407,7 @@ void eEPGCache::FixOverlapping(std::pair<eventMap,timeMap> &servicemap, time_t T
                        }
                        else
                                servicemap.second.erase(tmp--);
+                       ret = true;
                }
                else
                {
@@ -430,12 +436,14 @@ void eEPGCache::FixOverlapping(std::pair<eventMap,timeMap> &servicemap, time_t T
 #endif
                        delete tmp->second;
                        servicemap.second.erase(tmp++);
+                       ret = true;
                }
                else
                        ++tmp;
                if (tmp == servicemap.second.end())
                        break;
        }
+       return ret;
 }
 
 void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel)
@@ -452,7 +460,14 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel)
        if ( data[ptr-1] < 0x40 )
                --ptr;
 
-       uniqueEPGKey service( HILO(eit->service_id), HILO(eit->original_network_id), HILO(eit->transport_stream_id) );
+       // 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));
+
        eit_event_struct* eit_event = (eit_event_struct*) (data+ptr);
        int eit_event_size;
        int duration;
@@ -519,7 +534,11 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel)
                                                eventData *tmp = ev_it->second;
                                                ev_it->second = tm_it_tmp->second =
                                                        new eventData(eit_event, eit_event_size, source);
-                                               FixOverlapping(servicemap, TM, duration, tm_it_tmp, service);
+                                               if (FixOverlapping(servicemap, TM, duration, tm_it_tmp, service))
+                                               {
+                                                       prevEventIt = servicemap.first.end();
+                                                       prevTimeIt = servicemap.second.end();
+                                               }
                                                delete tmp;
                                                goto next;
                                        }
@@ -563,29 +582,25 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel)
 #endif
                        if (ev_erase_count > 0 && tm_erase_count > 0) // 2 different pairs have been removed
                        {
-                               eventData *tmp1 = ev_it->second,
-                                               *tmp2 = tm_it->second;
+                               // exempt memory
+                               delete ev_it->second;
+                               delete tm_it->second;
                                ev_it->second=evt;
                                tm_it->second=evt;
-                               // exempt memory
-                               delete tmp1;
-                               delete tmp2;
                        }
                        else if (ev_erase_count == 0 && tm_erase_count > 0)
                        {
-                               eventData *tmp = ev_it->second;
+                               // exempt memory
+                               delete ev_it->second;
                                tm_it=prevTimeIt=servicemap.second.insert( prevTimeIt, std::pair<const time_t, eventData*>( TM, evt ) );
                                ev_it->second=evt;
-                               // exempt memory
-                               delete tmp;
                        }
                        else if (ev_erase_count > 0 && tm_erase_count == 0)
                        {
-                               eventData *tmp = tm_it->second;
+                               // 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;
-                               // exempt memory
-                               delete tmp;
                        }
                        else // added new eventData
                        {
@@ -596,8 +611,6 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel)
                                tm_it=prevTimeIt=servicemap.second.insert( prevTimeIt, std::pair<const time_t, eventData*>( TM, evt ) );
                        }
 
-                       FixOverlapping(servicemap, TM, duration, tm_it, service);
-
 #ifdef EPG_DEBUG
                        if ( consistencyCheck )
                        {
@@ -617,6 +630,11 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel)
                                                ev_it->first, event_id );
                        }
 #endif
+                       if (FixOverlapping(servicemap, TM, duration, tm_it, service))
+                       {
+                               prevEventIt = servicemap.first.end();
+                               prevTimeIt = servicemap.second.end();
+                       }
                }
 next:
 #ifdef EPG_DEBUG
@@ -861,10 +879,10 @@ void eEPGCache::thread()
 
 void eEPGCache::load()
 {
-       singleLock s(cache_lock);
        FILE *f = fopen("/hdd/epg.dat", "r");
        if (f)
        {
+               unlink("/hdd/epg.dat");
                int size=0;
                int cnt=0;
 #if 0
@@ -898,6 +916,7 @@ void eEPGCache::load()
                        fread( text1, 13, 1, f);
                        if ( !strncmp( text1, "ENIGMA_EPG_V7", 13) )
                        {
+                               singleLock s(cache_lock);
                                fread( &size, sizeof(int), 1, f);
                                while(size--)
                                {
@@ -1162,7 +1181,7 @@ void eEPGCache::channel_data::startEPG()
        m_ScheduleOtherReader->start(mask);
        isRunning |= SCHEDULE_OTHER;
 
-//     abortTimer.start(7000,true);
+       abortTimer.start(7000,true);
 }
 
 void eEPGCache::channel_data::abortNonAvail()
@@ -1285,7 +1304,6 @@ void eEPGCache::channel_data::abortEPG()
 
 void eEPGCache::channel_data::readData( const __u8 *data)
 {
-#if 0
        int source;
        int map;
        iDVBSectionReader *reader=NULL;
@@ -1368,7 +1386,6 @@ void eEPGCache::channel_data::readData( const __u8 *data)
                        cache->sectionRead(data, source, this);
                }
        }
-#endif
 }
 
 RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, const eventData *&result, int direction)
@@ -1387,13 +1404,13 @@ RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, co
                        It->second.second.upper_bound(t); // just >
                if ( i != It->second.second.end() )
                {
-                       if ( direction < 0 || (direction == 0 && i->second->getStartTime() > t) )
+                       if ( direction < 0 || (direction == 0 && i->first > t) )
                        {
                                timeMap::iterator x = i;
                                --x;
                                if ( x != It->second.second.end() )
                                {
-                                       time_t start_time = x->second->getStartTime();
+                                       time_t start_time = x->first;
                                        if (direction >= 0)
                                        {
                                                if (t < start_time)
@@ -1508,37 +1525,37 @@ RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id,
 
 RESULT eEPGCache::startTimeQuery(const eServiceReference &service, time_t begin, int minutes)
 {
-       Lock();
-       eventCache::iterator It = eventDB.find(handleGroup(service));
+       singleLock s(cache_lock);
+       const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)handleGroup(service);
+       if (begin == -1)
+               begin = eDVBLocalTimeHandler::getInstance()->nowTime();
+       eventCache::iterator It = eventDB.find(ref);
        if ( It != eventDB.end() && It->second.second.size() )
        {
-               m_timemap_end = minutes != -1 ? It->second.second.upper_bound(begin+minutes*60) : It->second.second.end();
-               if ( begin != -1 )
+               m_timemap_cursor = It->second.second.lower_bound(begin);
+               if ( m_timemap_cursor != It->second.second.end() )
                {
-                       m_timemap_cursor = It->second.second.lower_bound(begin);
-                       if ( m_timemap_cursor != It->second.second.end() )
+                       if ( m_timemap_cursor->first != begin )
                        {
-                               if ( m_timemap_cursor->second->getStartTime() != begin )
+                               timeMap::iterator x = m_timemap_cursor;
+                               --x;
+                               if ( x != It->second.second.end() )
                                {
-                                       timeMap::iterator x = m_timemap_cursor;
-                                       --x;
-                                       if ( x != It->second.second.end() )
-                                       {
-                                               time_t start_time = x->second->getStartTime();
-                                               if ( begin > start_time && begin < (start_time+x->second->getDuration()))
-                                                       m_timemap_cursor = x;
-                                       }
+                                       time_t start_time = x->first;
+                                       if ( begin > start_time && begin < (start_time+x->second->getDuration()))
+                                               m_timemap_cursor = x;
                                }
                        }
                }
+
+               if (minutes != -1)
+                       m_timemap_end = It->second.second.lower_bound(begin+minutes*60);
                else
-                       m_timemap_cursor = It->second.second.begin();
-               const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)handleGroup(service);
+                       m_timemap_end = It->second.second.end();
+
                currentQueryTsidOnid = (ref.getTransportStreamID().get()<<16) | ref.getOriginalNetworkID().get();
-               Unlock();
-               return 0;
+               return m_timemap_cursor == m_timemap_end ? -1 : 0;
        }
-       Unlock();
        return -1;
 }
 
@@ -1583,14 +1600,15 @@ RESULT eEPGCache::getNextTimeEntry(ePtr<eServiceEvent> &result)
        return -1;
 }
 
-void fillTuple(ePyObject tuple, char *argstring, int argcount, ePyObject service, ePtr<eServiceEvent> &ptr, ePyObject nowTime, ePyObject service_name )
+void fillTuple(ePyObject tuple, const char *argstring, int argcount, ePyObject service, eServiceEvent *ptr, ePyObject nowTime, ePyObject service_name )
 {
        ePyObject tmp;
-       int pos=0;
-       while(pos < argcount)
+       int spos=0, tpos=0;
+       char c;
+       while(spos < argcount)
        {
                bool inc_refcount=false;
-               switch(argstring[pos])
+               switch((c=argstring[spos++]))
                {
                        case '0': // PyLong 0
                                tmp = PyLong_FromLong(0);
@@ -1621,9 +1639,16 @@ void fillTuple(ePyObject tuple, char *argstring, int argcount, ePyObject service
                                tmp = service;
                                inc_refcount = true;
                                break;
+                       case 'n': // short service name
                        case 'N': // service name
                                tmp = service_name;
                                inc_refcount = true;
+                               break;
+                       case 'X':
+                               ++argcount;
+                               continue;
+                       default:  // ignore unknown
+                               eDebug("fillTuple unknown '%c'... insert 'None' in result", c);
                }
                if (!tmp)
                {
@@ -1632,11 +1657,11 @@ void fillTuple(ePyObject tuple, char *argstring, int argcount, ePyObject service
                }
                if (inc_refcount)
                        Py_INCREF(tmp);
-               PyTuple_SET_ITEM(tuple, pos++, tmp);
+               PyTuple_SET_ITEM(tuple, tpos++, tmp);
        }
 }
 
-int handleEvent(ePtr<eServiceEvent> &ptr, ePyObject dest_list, char* argstring, int argcount, ePyObject service, ePyObject nowTime, ePyObject service_name, ePyObject convertFunc, ePyObject convertFuncArgs)
+int handleEvent(eServiceEvent *ptr, ePyObject dest_list, const char* argstring, int argcount, ePyObject service, ePyObject nowTime, ePyObject service_name, ePyObject convertFunc, ePyObject convertFuncArgs)
 {
        if (convertFunc)
        {
@@ -1680,6 +1705,10 @@ int handleEvent(ePtr<eServiceEvent> &ptr, ePyObject dest_list, char* argstring,
 //   C = Current Time
 //   R = Service Reference
 //   N = Service Name
+//   n = Short Service Name
+//   X = Return a minimum of one tuple per service in the result list... even when no event was found.
+//       The returned tuple is filled with all available infos... non avail is filled as None
+//       The position and existence of 'X' in the format string has no influence on the result tuple... its completely ignored..
 // then for each service follows a tuple
 //   first tuple entry is the servicereference (as string... use the ref.toString() function)
 //   the second is the type of query
@@ -1689,14 +1718,14 @@ int handleEvent(ePtr<eServiceEvent> &ptr, ePyObject dest_list, char* argstring,
 //    +1 = event after given start_time
 //   the third
 //      when type is eventid it is the event_id
-//      when type is time then it is the start_time ( 0 for now_time )
+//      when type is time then it is the start_time ( -1 for now_time )
 //   the fourth is the end_time .. ( optional .. for query all events in time range)
 
 PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc)
 {
        ePyObject convertFuncArgs;
        int argcount=0;
-       char *argstring=NULL;
+       const char *argstring=NULL;
        if (!PyList_Check(list))
        {
                PyErr_SetString(PyExc_StandardError,
@@ -1726,6 +1755,11 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc)
                argcount = strlen(argstring);
 //             eDebug("have %d args('%s')", argcount, argstring);
        }
+
+       bool forceReturnOne = strchr(argstring, 'X') ? true : false;
+       if (forceReturnOne)
+               --argcount;
+
        if (convertFunc)
        {
                if (!PyCallable_Check(convertFunc))
@@ -1742,7 +1776,7 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc)
                PyLong_FromLong(eDVBLocalTimeHandler::getInstance()->nowTime()) :
                ePyObject();
 
-       bool must_get_service_name = strchr(argstring, 'N') ? true : false;
+       int must_get_service_name = strchr(argstring, 'N') ? 1 : strchr(argstring, 'n') ? 2 : 0;
 
        // create dest list
        ePyObject dest_list=PyList_New(0);
@@ -1793,6 +1827,10 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc)
                                                break;
                                }
                        }
+
+                       if (minutes && stime == -1)
+                               stime = eDVBLocalTimeHandler::getInstance()->nowTime();
+
                        eServiceReference ref(handleGroup(eServiceReference(PyString_AS_STRING(service))));
                        if (ref.type != eServiceReference::idDVB)
                        {
@@ -1830,6 +1868,19 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc)
                                        {
                                                std::string name;
                                                sptr->getName(ref, name);
+
+                                               if (must_get_service_name == 1)
+                                               {
+                                                       unsigned int 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());
                                        }
@@ -1839,32 +1890,45 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc)
                        }
                        if (minutes)
                        {
-                               Lock();
+                               singleLock s(cache_lock);
                                if (!startTimeQuery(ref, stime, minutes))
                                {
-                                       ePtr<eServiceEvent> ptr;
-                                       while (!getNextTimeEntry(ptr))
+                                       while ( m_timemap_cursor != m_timemap_end )
                                        {
-                                               if (handleEvent(ptr, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs))
-                                               {
-                                                       Unlock();
+                                               Event ev((uint8_t*)m_timemap_cursor++->second->get());
+                                               eServiceEvent evt;
+                                               evt.parseFrom(&ev, currentQueryTsidOnid);
+                                               if (handleEvent(&evt, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs))
                                                        return 0;  // error
-                                               }
                                        }
                                }
-                               Unlock();
+                               else if (forceReturnOne && handleEvent(0, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs))
+                                       return 0;  // error
                        }
                        else
                        {
-                               ePtr<eServiceEvent> ptr;
+                               eServiceEvent evt;
+                               const eventData *ev_data=0;
                                if (stime)
                                {
+                                       singleLock s(cache_lock);
                                        if (type == 2)
-                                               lookupEventId(ref, event_id, ptr);
+                                               lookupEventId(ref, event_id, ev_data);
                                        else
-                                               lookupEventTime(ref, stime, ptr, type);
+                                               lookupEventTime(ref, stime, ev_data, type);
+                                       if (ev_data)
+                                       {
+                                               const eServiceReferenceDVB &dref = (const eServiceReferenceDVB&)ref;
+                                               Event ev((uint8_t*)ev_data->get());
+                                               evt.parseFrom(&ev, (dref.getTransportStreamID().get()<<16)|dref.getOriginalNetworkID().get());
+                                       }
+                               }
+                               if (ev_data)
+                               {
+                                       if (handleEvent(&evt, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs))
+                                               return 0; // error
                                }
-                               if (handleEvent(ptr, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs))
+                               else if (forceReturnOne && handleEvent(0, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs))
                                        return 0; // error
                        }
                        if (service_changed)
@@ -1882,7 +1946,7 @@ skip_entry:
        return dest_list;
 }
 
-void fillTuple2(ePyObject tuple, const char *argstring, int argcount, eventData *evData, ePtr<eServiceEvent> &ptr, ePyObject service_name, ePyObject service_reference)
+void fillTuple2(ePyObject tuple, const char *argstring, int argcount, eventData *evData, eServiceEvent *ptr, ePyObject service_name, ePyObject service_reference)
 {
        ePyObject tmp;
        int pos=0;
@@ -1922,10 +1986,13 @@ void fillTuple2(ePyObject tuple, const char *argstring, int argcount, eventData
                                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
+                               eDebug("fillTuple2 unknown '%c'... insert None in Result", argstring[pos]);
                }
                if (!tmp)
                {
@@ -1948,6 +2015,7 @@ void fillTuple2(ePyObject tuple, const char *argstring, int argcount, eventData
 //   E = Event Extended Description
 //   R = Service Reference
 //   N = Service Name
+//   n = Short Service Name
 //  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)
@@ -2052,16 +2120,14 @@ PyObject *eEPGCache::search(ePyObject arg)
                                        }
                                        else
                                        {
-                                               PyErr_SetString(PyExc_StandardError,
-                                                       "type error");
+                                               PyErr_SetString(PyExc_StandardError, "type error");
                                                eDebug("tuple arg 4 is not a valid service reference string");
                                                return NULL;
                                        }
                                }
                                else
                                {
-                                       PyErr_SetString(PyExc_StandardError,
-                                       "type error");
+                                       PyErr_SetString(PyExc_StandardError, "type error");
                                        eDebug("tuple arg 4 is not a string");
                                        return NULL;
                                }
@@ -2218,32 +2284,55 @@ PyObject *eEPGCache::search(ePyObject arg)
                                        if (ref.valid())
                                        {
                                        // create servive event
-                                               ePtr<eServiceEvent> ptr;
+                                               eServiceEvent ptr;
+                                               const eventData *ev_data=0;
                                                if (needServiceEvent)
                                                {
-                                                       lookupEventId(ref, evid, ptr);
-                                                       if (!ptr)
+                                                       if (lookupEventId(ref, evid, ev_data))
                                                                eDebug("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 (!service_name && strchr(argstring,'N'))
+                                               if (!service_name)
                                                {
-                                                       ePtr<iStaticServiceInformation> sptr;
-                                                       eServiceCenterPtr service_center;
-                                                       eServiceCenter::getPrivInstance(service_center);
-                                                       if (service_center)
+                                                       int must_get_service_name = strchr(argstring, 'N') ? 1 : strchr(argstring, 'n') ? 2 : 0;
+                                                       if (must_get_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 (name.length())
-                                                                               service_name = PyString_FromString(name.c_str());
+                                                                       service_center->info(ref, sptr);
+                                                                       if (sptr)
+                                                                       {
+                                                                               std::string name;
+                                                                               sptr->getName(ref, name);
+
+                                                                               if (must_get_service_name == 1)
+                                                                               {
+                                                                                       unsigned int 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'))
@@ -2254,7 +2343,7 @@ PyObject *eEPGCache::search(ePyObject arg)
                                        // create tuple
                                                ePyObject tuple = PyTuple_New(argcount);
                                        // fill tuple
-                                               fillTuple2(tuple, argstring, argcount, evit->second, ptr, service_name, service_reference);
+                                               fillTuple2(tuple, argstring, argcount, evit->second, ev_data ? &ptr : 0, service_name, service_reference);
                                                PyList_Append(ret, tuple);
                                                Py_DECREF(tuple);
                                                --maxcount;
@@ -2438,7 +2527,7 @@ void eEPGCache::privateSectionRead(const uniqueEPGKey &current_service, const __
                                int sid = data[ptr++] << 8;
                                sid |= data[ptr++];
 
-// WORKAROUND for wrong transmitted epg data (01.08.2006)
+// WORKAROUND for wrong transmitted epg data (01.10.2007)
                                if ( onid == 0x85 )
                                {
                                        switch( (tsid << 16) | sid )
@@ -2449,6 +2538,7 @@ void eEPGCache::privateSectionRead(const uniqueEPGKey &current_service, const __
                                                case 0x0300f5: sid = 0xdc; break;
                                                case 0x0400d2: sid = 0xe2; tsid = 0x11; break;
                                                case 0x1100d3: sid = 0xe3; break;
+                                               case 0x0100d4: sid = 0xe4; tsid = 4; break;
                                        }
                                }
 ////////////////////////////////////////////
@@ -2680,6 +2770,7 @@ void eEPGCache::channel_data::storeTitle(std::map<__u32, mhw_title_t>::iterator
 // data is borrowed from calling proc to save memory space.
 {
        __u8 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 ||
                itTitle->second.mhw2_duration_hi || itTitle->second.mhw2_duration_lo;
@@ -2687,6 +2778,7 @@ void eEPGCache::channel_data::storeTitle(std::map<__u32, mhw_title_t>::iterator
        eit_t *packet = (eit_t *) data;
        packet->table_id = 0x50;
        packet->section_syntax_indicator = 1;
+
        packet->service_id_hi = m_channels[ itTitle->second.channel_id - 1 ].channel_id_hi;
        packet->service_id_lo = m_channels[ itTitle->second.channel_id - 1 ].channel_id_lo;
        packet->version_number = 0;     // eEPGCache::sectionRead() will dig this for the moment
@@ -2871,10 +2963,11 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data)
                int record_size = sizeof( mhw_channel_name_t );
                int nbr_records = int (len/record_size);
 
+               m_channels.resize(nbr_records);
                for ( int i = 0; i < nbr_records; i++ )
                {
                        mhw_channel_name_t *channel = (mhw_channel_name_t*) &data[4 + i*record_size];
-                       m_channels.push_back( *channel );
+                       m_channels[i]=*channel;
                }
                haveData |= MHW;
 
@@ -2940,7 +3033,7 @@ 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[ program_id ] = title_id;
+                                       m_program_ids.insert(std::pair<__u32,__u32>(program_id,title_id));
                                return; // Continue reading of the current table.
                        }
                        else if (!checkTimeout())
@@ -2973,7 +3066,7 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data)
                memcpy(&tmp, &data, sizeof(void*));
                tmp[len+3] = 0; // Terminate as a string.
 
-               std::map<__u32, __u32>::iterator itProgid( m_program_ids.find( program_id ) );
+               std::multimap<__u32, __u32>::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. */
@@ -3032,10 +3125,11 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data)
        else if (m_MHWFilterMask2.pid == 0x231 && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 0)
        // Channels table
        {
-               int num_channels = data[120];
-               if(dataLen > 120)
+               int num_channels = data[119];
+               m_channels.resize(num_channels);
+               if(dataLen > 119)
                {
-                       int ptr = 121 + 6 * num_channels;
+                       int ptr = 120 + 8 * num_channels;
                        if( dataLen > ptr )
                        {
                                for( int chid = 0; chid < num_channels; ++chid )
@@ -3051,18 +3145,17 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data)
                else
                        goto abort;
                // data seems consistent...
-               const __u8 *tmp = data+121;
+               const __u8 *tmp = data+120;
                for (int i=0; i < num_channels; ++i)
                {
                        mhw_channel_name_t channel;
+                       channel.network_id_hi = *(tmp++);
+                       channel.network_id_lo = *(tmp++);
                        channel.transport_stream_id_hi = *(tmp++);
                        channel.transport_stream_id_lo = *(tmp++);
                        channel.channel_id_hi = *(tmp++);
                        channel.channel_id_lo = *(tmp++);
-#warning FIXME hardcoded network_id in mhw2 epg
-                       channel.network_id_hi = 0; // hardcoded astra 19.2
-                       channel.network_id_lo = 1;
-                       m_channels.push_back(channel);
+                       m_channels[i]=channel;
                        tmp+=2;
                }
                for (int i=0; i < num_channels; ++i)
@@ -3141,7 +3234,7 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data)
                        __u8 slen = data[pos+10] & 0x3f;
                        __u8 *dest = ((__u8*)title.title)-4;
                        memcpy(dest, &data[pos+11], slen>33 ? 33 : slen);
-                       memset(dest+slen, 0x20, 33-slen);
+                       memset(dest+slen, 0, 33-slen);
                        pos += 11 + slen;
 //                     not used theme id (data[7] & 0x3f) + (data[pos] & 0x3f);
                        __u32 summary_id = (data[pos+1] << 8) | data[pos+2];
@@ -3149,19 +3242,27 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data)
                        // Create unique key per title
                        __u32 title_id = (title.channel_id<<16) | (title.program_id_ml<<8) | title.program_id_lo;
 
-//                     eDebug("program_id: %08x, %s", program_id,
-//                             std::string((const char *)title.title, (int)(slen > 23 ? 23 : slen)).c_str());
-
                        pos += 4;
 
-                       if ( m_titles.find( title_id ) == m_titles.end() )
+                       std::map<__u32, mhw_title_t>::iterator it = m_titles.find( title_id );
+                       if ( it == m_titles.end() )
                        {
-                               startTimeout(4000);
+                               startTimeout(5000);
                                m_titles[ title_id ] = title;
-                               if (summary_id != 0xFFFF &&  // no summary avail
-                                       m_program_ids.find(summary_id) == m_program_ids.end())
+                               if (summary_id != 0xFFFF)
                                {
-                                       m_program_ids[ summary_id ] = title_id;
+                                       bool add=true;
+                                       std::multimap<__u32, __u32>::iterator it(m_program_ids.lower_bound(summary_id));
+                                       while (it != m_program_ids.end() && it->first == summary_id)
+                                       {
+                                               if (it->second == title_id) {
+                                                       add=false;
+                                                       break;
+                                               }
+                                               ++it;
+                                       }
+                                       if (add)
+                                               m_program_ids.insert(std::pair<__u32,__u32>(summary_id,title_id));
                                }
                        }
                        else
@@ -3181,7 +3282,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);
-                               startTimeout(4000);
+                               startTimeout(15000);
                                return;
                        }
                }
@@ -3191,84 +3292,91 @@ start_summary:
        else if (m_MHWFilterMask2.pid == 0x236 && m_MHWFilterMask2.data[0] == 0x96)
        // Summaries table
        {
-               int len, loop, pos, lenline;
-               bool valid;
-               valid = true;
-               if( dataLen > 18 )
+               if (!checkTimeout())
                {
-                       loop = data[12];
-                       pos = 13 + loop;
-                       if( dataLen > pos )
+                       int len, loop, pos, lenline;
+                       bool valid;
+                       valid = true;
+                       if( dataLen > 15 )
                        {
-                               loop = data[pos] & 0x0f;
-                               pos += 1;
+                               loop = data[14];
+                               pos = 15 + loop;
                                if( dataLen > pos )
                                {
-                                       len = 0;
-                                       for( ; loop > 0; --loop )
+                                       loop = data[pos] & 0x0f;
+                                       pos += 1;
+                                       if( dataLen > pos )
                                        {
-                                               if( dataLen > (pos+len) )
+                                               len = 0;
+                                               for( ; loop > 0; --loop )
                                                {
-                                                       lenline = data[pos+len];
-                                                       len += lenline + 1;
+                                                       if( dataLen > (pos+len) )
+                                                       {
+                                                               lenline = data[pos+len];
+                                                               len += lenline + 1;
+                                                       }
+                                                       else
+                                                               valid=false;
                                                }
-                                               else
-                                                       valid=false;
                                        }
                                }
                        }
-               }
-               else if (!checkTimeout())
-                       return;  // continue reading
-               if (valid && !checkTimeout())
-               {
-                       // data seems consistent...
-                       __u32 summary_id = (data[3]<<8)|data[4];
-
-                       // ugly workaround to convert const __u8* to char*
-                       char *tmp=0;
-                       memcpy(&tmp, &data, sizeof(void*));
-
-                       len = 0;
-                       loop = data[12];
-                       pos = 13 + loop;
-                       loop = tmp[pos] & 0x0f;
-                       pos += 1;
-                       for( ; loop > 0; loop -- )
-                       {
-                               lenline = tmp[pos+len];
-                               tmp[pos+len] = ' ';
-                               len += lenline + 1;
-                       }
-                       if( len > 0 )
-                           tmp[pos+len] = 0;
-                       else
-                               tmp[pos+1] = 0;
-
-                       std::map<__u32, __u32>::iterator itProgid( m_program_ids.find( summary_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() )
-                                       return; // Continue reading of the current table.
-                       }
                        else
+                               return;  // continue reading
+                       if (valid)
                        {
-                               startTimeout(4000);
-                               std::string the_text = (char *) (data + pos + 1);
+                               // data seems consistent...
+                               __u32 summary_id = (data[3]<<8)|data[4];
+
+                               // ugly workaround to convert const __u8* to char*
+                               char *tmp=0;
+                               memcpy(&tmp, &data, sizeof(void*));
 
-                               // 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() )
+                               len = 0;
+                               loop = data[14];
+                               pos = 15 + loop;
+                               loop = tmp[pos] & 0x0f;
+                               pos += 1;
+                               for( ; loop > 0; loop -- )
+                               {
+                                       lenline = tmp[pos+len];
+                                       tmp[pos+len] = ' ';
+                                       len += lenline + 1;
+                               }
+                               if( len > 0 )
+                                   tmp[pos+len] = 0;
+                               else
+                                       tmp[pos+1] = 0;
+
+                               std::multimap<__u32, __u32>::iterator itProgId( m_program_ids.lower_bound(summary_id) );
+                               if ( itProgId == m_program_ids.end() || itProgId->first != summary_id)
+                               { /*    This part is to prevent to looping forever if some summaries are not received yet.
+                                       There is a timeout of 4 sec. after the last successfully read summary. */
+                                       if ( !m_program_ids.empty() )
+                                               return; // Continue reading of the current table.
+                               }
+                               else
                                {
-                                       storeTitle( itTitle, the_text, data );
-                                       m_titles.erase( itTitle );
+                                       startTimeout(15000);
+                                       std::string the_text = (char *) (data + pos + 1);
+
+                                       while( itProgId != m_program_ids.end() && itProgId->first == summary_id )
+                                       {
+                                               // 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() )
+                                               {
+                                                       storeTitle( itTitle, the_text, data );
+                                                       m_titles.erase( itTitle );
+                                               }
+                                               m_program_ids.erase( itProgId++ );
+                                       }
+                                       if ( !m_program_ids.empty() )
+                                               return; // Continue reading of the current table.
                                }
-                               m_program_ids.erase( itProgid );
-                               if ( !m_program_ids.empty() )
-                                       return; // Continue reading of the current table.
                        }
+                       else
+                               return;  // continue reading
                }
        }
        if (isRunning & eEPGCache::MHW)