allow gstreamer to signalize missing plugins to the gui (requires reconfiguring enigm...
[enigma2.git] / lib / dvb / epgcache.cpp
index 6767c4ad4a93ed574736b797b7426428bdabc14c..1a07755f7eec10e1c897e68a23c0b5626e589139 100644 (file)
@@ -372,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)
        {
@@ -406,6 +407,7 @@ void eEPGCache::FixOverlapping(std::pair<eventMap,timeMap> &servicemap, time_t T
                        }
                        else
                                servicemap.second.erase(tmp--);
+                       ret = true;
                }
                else
                {
@@ -434,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)
@@ -456,13 +460,20 @@ 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;
 
        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 = eDVBLocalTimeHandler::getInstance()->nowTime();
+       time_t now = ::time(0);
 
        if ( TM != 3599 && TM > -1)
                channel->haveData |= source;
@@ -523,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;
                                        }
@@ -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
@@ -707,7 +725,7 @@ void eEPGCache::cleanLoop()
        {
                eDebug("[EPGC] start cleanloop");
 
-               time_t now = eDVBLocalTimeHandler::getInstance()->nowTime();
+               time_t now = ::time(0);
 
                for (eventCache::iterator DBIt = eventDB.begin(); DBIt != eventDB.end(); DBIt++)
                {
@@ -826,7 +844,7 @@ void eEPGCache::gotMessage( const Message &msg )
                                        onid |= 0x80000000;  // we use highest bit as private epg indicator
                                        chid.original_network_id = onid;
                                        updateMap::iterator It = channelLastUpdated.find( chid );
-                                       int update = ( It != channelLastUpdated.end() ? ( UPDATE_INTERVAL - ( (eDVBLocalTimeHandler::getInstance()->nowTime()-It->second) * 1000 ) ) : ZAP_DELAY );
+                                       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);
@@ -1000,7 +1018,7 @@ void eEPGCache::save()
        {
                unsigned int magic = 0x98765432;
                fwrite( &magic, sizeof(int), 1, f);
-               const char *text = "ENIGMA_EPG_V7";
+               const char *text = "UNFINISHED_V7";
                fwrite( text, 13, 1, f );
                int size = eventDB.size();
                fwrite( &size, sizeof(int), 1, f );
@@ -1047,6 +1065,11 @@ void eEPGCache::save()
                        }
                }
 #endif
+               // write version string after binary data
+               // has been written to disk.
+               fsync(fileno(f));
+               fseek(f, sizeof(int), SEEK_SET);
+               fwrite("ENIGMA_EPG_V7", 13, 1, f);
                fclose(f);
 #if 0
                unsigned char md5[16];
@@ -1089,7 +1112,7 @@ bool eEPGCache::channel_data::finishEPG()
 {
        if (!isRunning)  // epg ready
        {
-               eDebug("[EPGC] stop caching events(%ld)", eDVBLocalTimeHandler::getInstance()->nowTime());
+               eDebug("[EPGC] stop caching events(%ld)", ::time(0));
                zapTimer.start(UPDATE_INTERVAL, 1);
                eDebug("[EPGC] next update in %i min", UPDATE_INTERVAL / 60000);
                for (int i=0; i < 3; ++i)
@@ -1098,7 +1121,7 @@ bool eEPGCache::channel_data::finishEPG()
                        calcedSections[i].clear();
                }
                singleLock l(cache->cache_lock);
-               cache->channelLastUpdated[channel->getChannelID()] = eDVBLocalTimeHandler::getInstance()->nowTime();
+               cache->channelLastUpdated[channel->getChannelID()] = ::time(0);
 #ifdef ENABLE_MHW_EPG
                cleanup();
 #endif
@@ -1109,7 +1132,7 @@ bool eEPGCache::channel_data::finishEPG()
 
 void eEPGCache::channel_data::startEPG()
 {
-       eDebug("[EPGC] start caching events(%ld)", eDVBLocalTimeHandler::getInstance()->nowTime());
+       eDebug("[EPGC] start caching events(%ld)", ::time(0));
        state=0;
        haveData=0;
        for (int i=0; i < 3; ++i)
@@ -1222,7 +1245,7 @@ void eEPGCache::channel_data::startChannel()
        pthread_mutex_lock(&channel_active);
        updateMap::iterator It = cache->channelLastUpdated.find( channel->getChannelID() );
 
-       int update = ( It != cache->channelLastUpdated.end() ? ( UPDATE_INTERVAL - ( (eDVBLocalTimeHandler::getInstance()->nowTime()-It->second) * 1000 ) ) : ZAP_DELAY );
+       int update = ( It != cache->channelLastUpdated.end() ? ( UPDATE_INTERVAL - ( (::time(0)-It->second) * 1000 ) ) : ZAP_DELAY );
 
        if (update < ZAP_DELAY)
                update = ZAP_DELAY;
@@ -1331,7 +1354,7 @@ void eEPGCache::channel_data::readData( const __u8 *data)
                                break;
                        default: eDebugNoNewLine("unknown");break;
                }
-               eDebug(" finished(%ld)", eDVBLocalTimeHandler::getInstance()->nowTime());
+               eDebug(" finished(%ld)", ::time(0));
                if ( reader )
                        reader->stop();
                isRunning &= ~source;
@@ -1381,7 +1404,7 @@ RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, co
        if ( It != eventDB.end() && !It->second.first.empty() ) // entrys cached ?
        {
                if (t==-1)
-                       t = eDVBLocalTimeHandler::getInstance()->nowTime();
+                       t = ::time(0);
                timeMap::iterator i = direction <= 0 ? It->second.second.lower_bound(t) :  // find > or equal
                        It->second.second.upper_bound(t); // just >
                if ( i != It->second.second.end() )
@@ -1507,10 +1530,10 @@ RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id,
 
 RESULT eEPGCache::startTimeQuery(const eServiceReference &service, time_t begin, int minutes)
 {
+       singleLock s(cache_lock);
        const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)handleGroup(service);
        if (begin == -1)
-               begin = eDVBLocalTimeHandler::getInstance()->nowTime();
-       Lock();
+               begin = ::time(0);
        eventCache::iterator It = eventDB.find(ref);
        if ( It != eventDB.end() && It->second.second.size() )
        {
@@ -1536,10 +1559,8 @@ RESULT eEPGCache::startTimeQuery(const eServiceReference &service, time_t begin,
                        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;
 }
 
@@ -1584,14 +1605,15 @@ RESULT eEPGCache::getNextTimeEntry(ePtr<eServiceEvent> &result)
        return -1;
 }
 
-void fillTuple(ePyObject tuple, char *argstring, int argcount, ePyObject service, 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);
@@ -1626,6 +1648,12 @@ void fillTuple(ePyObject tuple, char *argstring, int argcount, ePyObject service
                        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)
                {
@@ -1634,11 +1662,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(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)
        {
@@ -1683,6 +1711,9 @@ int handleEvent(eServiceEvent *ptr, ePyObject dest_list, char* argstring, int ar
 //   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
@@ -1699,7 +1730,7 @@ 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,
@@ -1729,6 +1760,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 +1778,7 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc)
        }
 
        ePyObject nowTime = strchr(argstring, 'C') ?
-               PyLong_FromLong(eDVBLocalTimeHandler::getInstance()->nowTime()) :
+               PyLong_FromLong(::time(0)) :
                ePyObject();
 
        int must_get_service_name = strchr(argstring, 'N') ? 1 : strchr(argstring, 'n') ? 2 : 0;
@@ -1798,7 +1834,7 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc)
                        }
 
                        if (minutes && stime == -1)
-                               stime = eDVBLocalTimeHandler::getInstance()->nowTime();
+                               stime = ::time(0);
 
                        eServiceReference ref(handleGroup(eServiceReference(PyString_AS_STRING(service))));
                        if (ref.type != eServiceReference::idDVB)
@@ -1840,7 +1876,7 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc)
 
                                                if (must_get_service_name == 1)
                                                {
-                                                       unsigned int pos;
+                                                       size_t pos;
                                                        // filter short name brakets
                                                        while((pos = name.find("\xc2\x86")) != std::string::npos)
                                                                name.erase(pos,2);
@@ -1859,7 +1895,7 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc)
                        }
                        if (minutes)
                        {
-                               Lock();
+                               singleLock s(cache_lock);
                                if (!startTimeQuery(ref, stime, minutes))
                                {
                                        while ( m_timemap_cursor != m_timemap_end )
@@ -1868,33 +1904,36 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc)
                                                eServiceEvent evt;
                                                evt.parseFrom(&ev, currentQueryTsidOnid);
                                                if (handleEvent(&evt, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs))
-                                               {
-                                                       Unlock();
                                                        return 0;  // error
-                                               }
                                        }
                                }
-                               else
-                                       handleEvent(0, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs);
-                               Unlock();
+                               else if (forceReturnOne && handleEvent(0, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs))
+                                       return 0;  // error
                        }
                        else
                        {
                                eServiceEvent evt;
-                               Event *ev=0;
+                               const eventData *ev_data=0;
                                if (stime)
                                {
+                                       singleLock s(cache_lock);
                                        if (type == 2)
-                                               lookupEventId(ref, event_id, ev);
+                                               lookupEventId(ref, event_id, ev_data);
                                        else
-                                               lookupEventTime(ref, stime, ev, type);
-                                       if (ev)
+                                               lookupEventTime(ref, stime, ev_data, type);
+                                       if (ev_data)
                                        {
                                                const eServiceReferenceDVB &dref = (const eServiceReferenceDVB&)ref;
-                                               evt.parseFrom(ev, (dref.getTransportStreamID().get()<<16)|dref.getOriginalNetworkID().get());
+                                               Event ev((uint8_t*)ev_data->get());
+                                               evt.parseFrom(&ev, (dref.getTransportStreamID().get()<<16)|dref.getOriginalNetworkID().get());
                                        }
                                }
-                               if (handleEvent(ev ? &evt : 0, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs))
+                               if (ev_data)
+                               {
+                                       if (handleEvent(&evt, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs))
+                                               return 0; // error
+                               }
+                               else if (forceReturnOne && handleEvent(0, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs))
                                        return 0; // error
                        }
                        if (service_changed)
@@ -1957,6 +1996,8 @@ void fillTuple2(ePyObject tuple, const char *argstring, int argcount, eventData
                                tmp = service_name;
                                inc_refcount = true;
                                break;
+                       default:  // ignore unknown
+                               eDebug("fillTuple2 unknown '%c'... insert None in Result", argstring[pos]);
                }
                if (!tmp)
                {
@@ -2084,16 +2125,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;
                                }
@@ -2251,15 +2290,16 @@ PyObject *eEPGCache::search(ePyObject arg)
                                        {
                                        // create servive event
                                                eServiceEvent ptr;
-                                               Event *ev=0;
+                                               const eventData *ev_data=0;
                                                if (needServiceEvent)
                                                {
-                                                       if (lookupEventId(ref, evid, ev))
+                                                       if (lookupEventId(ref, evid, ev_data))
                                                                eDebug("event not found !!!!!!!!!!!");
                                                        else
                                                        {
                                                                const eServiceReferenceDVB &dref = (const eServiceReferenceDVB&)ref;
-                                                               ptr.parseFrom(ev, (dref.getTransportStreamID().get()<<16)|dref.getOriginalNetworkID().get());
+                                                               Event ev((uint8_t*)ev_data->get());
+                                                               ptr.parseFrom(&ev, (dref.getTransportStreamID().get()<<16)|dref.getOriginalNetworkID().get());
                                                        }
                                                }
                                        // create service name
@@ -2281,7 +2321,7 @@ PyObject *eEPGCache::search(ePyObject arg)
 
                                                                                if (must_get_service_name == 1)
                                                                                {
-                                                                                       unsigned int pos;
+                                                                                       size_t pos;
                                                                                        // filter short name brakets
                                                                                        while((pos = name.find("\xc2\x86")) != std::string::npos)
                                                                                                name.erase(pos,2);
@@ -2308,7 +2348,7 @@ PyObject *eEPGCache::search(ePyObject arg)
                                        // create tuple
                                                ePyObject tuple = PyTuple_New(argcount);
                                        // fill tuple
-                                               fillTuple2(tuple, argstring, argcount, evit->second, ev ? &ptr : 0, 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;
@@ -2555,7 +2595,7 @@ void eEPGCache::privateSectionRead(const uniqueEPGKey &current_service, const __
        ASSERT(ptr <= 4098);
        for ( std::map< date_time, std::list<uniqueEPGKey> >::iterator it(start_times.begin()); it != start_times.end(); ++it )
        {
-               time_t now = eDVBLocalTimeHandler::getInstance()->nowTime();
+               time_t now = ::time(0);
                if ( (it->first.tm + duration_sec) < now )
                        continue;
                memcpy(event+2, it->first.data, 5);
@@ -2631,7 +2671,7 @@ void eEPGCache::channel_data::readPrivateData( const __u8 *data)
                int tmp = chid.original_network_id.get();
                tmp |= 0x80000000; // we use highest bit as private epg indicator
                chid.original_network_id = tmp;
-               cache->channelLastUpdated[chid] = eDVBLocalTimeHandler::getInstance()->nowTime();
+               cache->channelLastUpdated[chid] = ::time(0);
                m_PrevVersion = (data[5] & 0x3E) >> 1;
                startPrivateReader();
        }
@@ -2690,7 +2730,7 @@ void eEPGCache::channel_data::timeMHW2DVB( u_char day, u_char hours, u_char minu
 
        // As far as we know all mhw time data is sent in central Europe time zone.
        // So, temporarily set timezone to western europe
-       time_t dt = eDVBLocalTimeHandler::getInstance()->nowTime();
+       time_t dt = ::time(0);
 
        char *old_tz = getenv( "TZ" );
        putenv("TZ=CET-1CEST,M3.5.0/2,M10.5.0/3");
@@ -3060,7 +3100,7 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data)
                }
        }
        eDebug("[EPGC] mhw finished(%ld) %d summaries not found",
-               eDVBLocalTimeHandler::getInstance()->nowTime(),
+               ::time(0),
                m_program_ids.size());
        // Summaries have been read, titles that have summaries have been stored.
        // Now store titles that do not have summaries.
@@ -3365,7 +3405,7 @@ start_summary:
                        for (std::map<__u32, mhw_title_t>::iterator itTitle(m_titles.begin()); itTitle != m_titles.end(); itTitle++)
                                storeTitle( itTitle, "", data );
                        eDebug("[EPGC] mhw2 finished(%ld) %d summaries not found",
-                               eDVBLocalTimeHandler::getInstance()->nowTime(),
+                               ::time(0),
                                m_program_ids.size());
                }
        }