4afe813b8369717cc1136f8b6bae1b39072c0166
[enigma2.git] / lib / dvb / epgcache.cpp
1 #include <lib/dvb/epgcache.h>
2 #include <lib/dvb/dvb.h>
3
4 #undef EPG_DEBUG  
5
6 #ifdef EPG_DEBUG
7 #include <lib/service/event.h>
8 #endif
9
10 #include <time.h>
11 #include <unistd.h>  // for usleep
12 #include <sys/vfs.h> // for statfs
13 // #include <libmd5sum.h>
14 #include <lib/base/eerror.h>
15 #include <lib/dvb/pmt.h>
16 #include <lib/dvb/db.h>
17 #include <Python.h>
18
19 int eventData::CacheSize=0;
20 descriptorMap eventData::descriptors;
21 __u8 eventData::data[4108];
22 extern const uint32_t crc32_table[256];
23
24 eventData::eventData(const eit_event_struct* e, int size, int type)
25         :ByteSize(size&0xFF), type(type&0xFF)
26 {
27         if (!e)
28                 return;
29
30         __u32 descr[65];
31         __u32 *pdescr=descr;
32
33         __u8 *data = (__u8*)e;
34         int ptr=10;
35         int descriptors_length = (data[ptr++]&0x0F) << 8;
36         descriptors_length |= data[ptr++];
37         while ( descriptors_length > 0 )
38         {
39                 __u8 *descr = data+ptr;
40                 int descr_len = descr[1]+2;
41
42                 __u32 crc = 0;
43                 int cnt=0;
44                 while(cnt++ < descr_len)
45                         crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ data[ptr++]) & 0xFF];
46
47                 descriptorMap::iterator it =
48                         descriptors.find(crc);
49                 if ( it == descriptors.end() )
50                 {
51                         CacheSize+=descr_len;
52                         __u8 *d = new __u8[descr_len];
53                         memcpy(d, descr, descr_len);
54                         descriptors[crc] = descriptorPair(1, d);
55                 }
56                 else
57                         ++it->second.first;
58
59                 *pdescr++=crc;
60                 descriptors_length -= descr_len;
61         }
62         ByteSize = 12+((pdescr-descr)*4);
63         EITdata = new __u8[ByteSize];
64         CacheSize+=ByteSize;
65         memcpy(EITdata, (__u8*) e, 12);
66         memcpy(EITdata+12, descr, ByteSize-12);
67 }
68
69 const eit_event_struct* eventData::get() const
70 {
71         int pos = 12;
72         int tmp = ByteSize-12;
73         memcpy(data, EITdata, 12);
74         __u32 *p = (__u32*)(EITdata+12);
75         while(tmp>0)
76         {
77                 descriptorMap::iterator it =
78                         descriptors.find(*p++);
79                 if ( it != descriptors.end() )
80                 {
81                         int b = it->second.second[1]+2;
82                         memcpy(data+pos, it->second.second, b );
83                         pos += b;
84                 }
85                 tmp-=4;
86         }
87
88         return (const eit_event_struct*)data;
89 }
90
91 eventData::~eventData()
92 {
93         if ( ByteSize )
94         {
95                 CacheSize-=ByteSize;
96                 ByteSize-=12;
97                 __u32 *d = (__u32*)(EITdata+12);
98                 while(ByteSize)
99                 {
100                         descriptorMap::iterator it =
101                                 descriptors.find(*d++);
102                         if ( it != descriptors.end() )
103                         {
104                                 descriptorPair &p = it->second;
105                                 if (!--p.first) // no more used descriptor
106                                 {
107                                         CacheSize -= it->second.second[1];
108                                         delete [] it->second.second;    // free descriptor memory
109                                         descriptors.erase(it);  // remove entry from descriptor map
110                                 }
111                         }
112                         ByteSize-=4;
113                 }
114                 delete [] EITdata;
115         }
116 }
117
118 void eventData::load(FILE *f)
119 {
120         int size=0;
121         int id=0;
122         __u8 header[2];
123         descriptorPair p;
124         fread(&size, sizeof(int), 1, f);
125         while(size)
126         {
127                 fread(&id, sizeof(__u32), 1, f);
128                 fread(&p.first, sizeof(int), 1, f);
129                 fread(header, 2, 1, f);
130                 int bytes = header[1]+2;
131                 p.second = new __u8[bytes];
132                 p.second[0] = header[0];
133                 p.second[1] = header[1];
134                 fread(p.second+2, bytes-2, 1, f);
135                 descriptors[id]=p;
136                 --size;
137                 CacheSize+=bytes;
138         }
139 }
140
141 void eventData::save(FILE *f)
142 {
143         int size=descriptors.size();
144         descriptorMap::iterator it(descriptors.begin());
145         fwrite(&size, sizeof(int), 1, f);
146         while(size)
147         {
148                 fwrite(&it->first, sizeof(__u32), 1, f);
149                 fwrite(&it->second.first, sizeof(int), 1, f);
150                 fwrite(it->second.second, it->second.second[1]+2, 1, f);
151                 ++it;
152                 --size;
153         }
154 }
155
156 eEPGCache* eEPGCache::instance;
157 pthread_mutex_t eEPGCache::cache_lock=
158         PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
159 pthread_mutex_t eEPGCache::channel_map_lock=
160         PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
161
162 DEFINE_REF(eEPGCache)
163
164 eEPGCache::eEPGCache()
165         :messages(this,1), cleanTimer(this)//, paused(0)
166 {
167         eDebug("[EPGC] Initialized EPGCache");
168
169         CONNECT(messages.recv_msg, eEPGCache::gotMessage);
170         CONNECT(eDVBLocalTimeHandler::getInstance()->m_timeUpdated, eEPGCache::timeUpdated);
171         CONNECT(cleanTimer.timeout, eEPGCache::cleanLoop);
172
173         ePtr<eDVBResourceManager> res_mgr;
174         eDVBResourceManager::getInstance(res_mgr);
175         if (!res_mgr)
176                 eDebug("[eEPGCache] no resource manager !!!!!!!");
177         else
178                 res_mgr->connectChannelAdded(slot(*this,&eEPGCache::DVBChannelAdded), m_chanAddedConn);
179         instance=this;
180 }
181
182 void eEPGCache::timeUpdated()
183 {
184         if (!sync())
185         {
186                 eDebug("[EPGC] time updated.. start EPG Mainloop");
187                 run();
188         } else
189                 messages.send(Message(Message::timeChanged));
190 }
191
192 void eEPGCache::DVBChannelAdded(eDVBChannel *chan)
193 {
194         if ( chan )
195         {
196 //              eDebug("[eEPGCache] add channel %p", chan);
197                 channel_data *data = new channel_data(this);
198                 data->channel = chan;
199                 data->prevChannelState = -1;
200 #ifdef ENABLE_PRIVATE_EPG
201                 data->m_PrivatePid = -1;
202 #endif
203                 singleLock s(channel_map_lock);
204                 m_knownChannels.insert( std::pair<iDVBChannel*, channel_data* >(chan, data) );
205                 chan->connectStateChange(slot(*this, &eEPGCache::DVBChannelStateChanged), data->m_stateChangedConn);
206         }
207 }
208
209 void eEPGCache::DVBChannelRunning(iDVBChannel *chan)
210 {
211         singleLock s(channel_map_lock);
212         channelMapIterator it =
213                 m_knownChannels.find(chan);
214         if ( it == m_knownChannels.end() )
215                 eDebug("[eEPGCache] will start non existing channel %p !!!", chan);
216         else
217         {
218                 channel_data &data = *it->second;
219                 ePtr<eDVBResourceManager> res_mgr;
220                 if ( eDVBResourceManager::getInstance( res_mgr ) )
221                         eDebug("[eEPGCache] no res manager!!");
222                 else
223                 {
224                         ePtr<iDVBDemux> demux;
225                         if ( data.channel->getDemux(demux, 0) )
226                         {
227                                 eDebug("[eEPGCache] no demux!!");
228                                 return;
229                         }
230                         else
231                         {
232                                 RESULT res = demux->createSectionReader( this, data.m_NowNextReader );
233                                 if ( res )
234                                 {
235                                         eDebug("[eEPGCache] couldnt initialize nownext reader!!");
236                                         return;
237                                 }
238
239                                 res = demux->createSectionReader( this, data.m_ScheduleReader );
240                                 if ( res )
241                                 {
242                                         eDebug("[eEPGCache] couldnt initialize schedule reader!!");
243                                         return;
244                                 }
245
246                                 res = demux->createSectionReader( this, data.m_ScheduleOtherReader );
247                                 if ( res )
248                                 {
249                                         eDebug("[eEPGCache] couldnt initialize schedule other reader!!");
250                                         return;
251                                 }
252 #ifdef ENABLE_PRIVATE_EPG
253                                 res = demux->createSectionReader( this, data.m_PrivateReader );
254                                 if ( res )
255                                 {
256                                         eDebug("[eEPGCache] couldnt initialize private reader!!");
257                                         return;
258                                 }
259 #endif
260 #ifdef ENABLE_MHW_EPG
261                                 res = demux->createSectionReader( this, data.m_MHWReader );
262                                 if ( res )
263                                 {
264                                         eDebug("[eEPGCache] couldnt initialize mhw reader!!");
265                                         return;
266                                 }
267 #endif
268                                 messages.send(Message(Message::startChannel, chan));
269                                 // -> gotMessage -> changedService
270                         }
271                 }
272         }
273 }
274
275 void eEPGCache::DVBChannelStateChanged(iDVBChannel *chan)
276 {
277         channelMapIterator it =
278                 m_knownChannels.find(chan);
279         if ( it != m_knownChannels.end() )
280         {
281                 int state=0;
282                 chan->getState(state);
283                 if ( it->second->prevChannelState != state )
284                 {
285                         switch (state)
286                         {
287                                 case iDVBChannel::state_ok:
288                                 {
289                                         eDebug("[eEPGCache] channel %p running", chan);
290                                         DVBChannelRunning(chan);
291                                         break;
292                                 }
293                                 case iDVBChannel::state_release:
294                                 {
295                                         eDebug("[eEPGCache] remove channel %p", chan);
296                                         messages.send(Message(Message::leaveChannel, chan));
297                                         while(!it->second->canDelete())
298                                                 usleep(1000);
299                                         delete it->second;
300                                         m_knownChannels.erase(it);
301                                         // -> gotMessage -> abortEPG
302                                         break;
303                                 }
304                                 default: // ignore all other events
305                                         return;
306                         }
307                         it->second->prevChannelState = state;
308                 }
309         }
310 }
311
312 void eEPGCache::FixOverlapping(std::pair<eventMap,timeMap> &servicemap, time_t TM, int duration, const timeMap::iterator &tm_it, const uniqueEPGKey &service)
313 {
314         timeMap::iterator tmp = tm_it;
315         while ((tmp->first+tmp->second->getDuration()-300) > TM)
316         {
317                 if(tmp->first != TM && tmp->second->type != PRIVATE)
318                 {
319                         __u16 event_id = tmp->second->getEventID();
320                         servicemap.first.erase(event_id);
321 #ifdef EPG_DEBUG
322                         Event evt((uint8_t*)tmp->second->get());
323                         eServiceEvent event;
324                         event.parseFrom(&evt, service.sid<<16|service.onid);
325                         eDebug("(1)erase no more used event %04x %d\n%s %s\n%s",
326                                 service.sid, event_id,
327                                 event.getBeginTimeString().c_str(),
328                                 event.getEventName().c_str(),
329                                 event.getExtendedDescription().c_str());
330 #endif
331                         delete tmp->second;
332                         if (tmp == servicemap.second.begin())
333                         {
334                                 servicemap.second.erase(tmp);
335                                 break;
336                         }
337                         else
338                                 servicemap.second.erase(tmp--);
339                 }
340                 else
341                 {
342                         if (tmp == servicemap.second.begin())
343                                 break;
344                         --tmp;
345                 }
346         }
347
348         tmp = tm_it;
349         while(tmp->first < (TM+duration-300))
350         {
351                 if (tmp->first != TM && tmp->second->type != PRIVATE)
352                 {
353                         __u16 event_id = tmp->second->getEventID();
354                         servicemap.first.erase(event_id);
355 #ifdef EPG_DEBUG  
356                         Event evt((uint8_t*)tmp->second->get());
357                         eServiceEvent event;
358                         event.parseFrom(&evt, service.sid<<16|service.onid);
359                         eDebug("(2)erase no more used event %04x %d\n%s %s\n%s",
360                                 service.sid, event_id,
361                                 event.getBeginTimeString().c_str(),
362                                 event.getEventName().c_str(),
363                                 event.getExtendedDescription().c_str());
364 #endif
365                         delete tmp->second;
366                         servicemap.second.erase(tmp++);
367                 }
368                 else
369                         ++tmp;
370                 if (tmp == servicemap.second.end())
371                         break;
372         }
373 }
374
375 void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel)
376 {
377         eit_t *eit = (eit_t*) data;
378
379         int len=HILO(eit->section_length)-1;//+3-4;
380         int ptr=EIT_SIZE;
381         if ( ptr >= len )
382                 return;
383
384         // This fixed the EPG on the Multichoice irdeto systems
385         // the EIT packet is non-compliant.. their EIT packet stinks
386         if ( data[ptr-1] < 0x40 )
387                 --ptr;
388
389         uniqueEPGKey service( HILO(eit->service_id), HILO(eit->original_network_id), HILO(eit->transport_stream_id) );
390         eit_event_struct* eit_event = (eit_event_struct*) (data+ptr);
391         int eit_event_size;
392         int duration;
393
394         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);
395         time_t now = eDVBLocalTimeHandler::getInstance()->nowTime();
396
397         if ( TM != 3599 && TM > -1)
398                 channel->haveData |= source;
399
400         singleLock s(cache_lock);
401         // hier wird immer eine eventMap zurück gegeben.. entweder eine vorhandene..
402         // oder eine durch [] erzeugte
403         std::pair<eventMap,timeMap> &servicemap = eventDB[service];
404         eventMap::iterator prevEventIt = servicemap.first.end();
405         timeMap::iterator prevTimeIt = servicemap.second.end();
406
407         while (ptr<len)
408         {
409                 eit_event_size = HILO(eit_event->descriptors_loop_length)+EIT_LOOP_SIZE;
410
411                 duration = fromBCD(eit_event->duration_1)*3600+fromBCD(eit_event->duration_2)*60+fromBCD(eit_event->duration_3);
412                 TM = parseDVBtime(
413                         eit_event->start_time_1,
414                         eit_event->start_time_2,
415                         eit_event->start_time_3,
416                         eit_event->start_time_4,
417                         eit_event->start_time_5);
418
419                 if ( TM == 3599 )
420                         goto next;
421
422                 if ( TM != 3599 && (TM+duration < now || TM > now+14*24*60*60) )
423                         goto next;
424
425                 if ( now <= (TM+duration) || TM == 3599 /*NVOD Service*/ )  // old events should not be cached
426                 {
427                         __u16 event_id = HILO(eit_event->event_id);
428 //                      eDebug("event_id is %d sid is %04x", event_id, service.sid);
429
430                         eventData *evt = 0;
431                         int ev_erase_count = 0;
432                         int tm_erase_count = 0;
433
434                         // search in eventmap
435                         eventMap::iterator ev_it =
436                                 servicemap.first.find(event_id);
437
438                         // entry with this event_id is already exist ?
439                         if ( ev_it != servicemap.first.end() )
440                         {
441                                 if ( source > ev_it->second->type )  // update needed ?
442                                         goto next; // when not.. then skip this entry
443
444                                 // search this event in timemap
445                                 timeMap::iterator tm_it_tmp =
446                                         servicemap.second.find(ev_it->second->getStartTime());
447
448                                 if ( tm_it_tmp != servicemap.second.end() )
449                                 {
450                                         if ( tm_it_tmp->first == TM ) // just update eventdata
451                                         {
452                                                 // exempt memory
453                                                 delete ev_it->second;
454                                                 ev_it->second = tm_it_tmp->second =
455                                                         new eventData(eit_event, eit_event_size, source);
456                                                 FixOverlapping(servicemap, TM, duration, tm_it_tmp, service);
457                                                 goto next;
458                                         }
459                                         else  // event has new event begin time
460                                         {
461                                                 tm_erase_count++;
462                                                 // delete the found record from timemap
463                                                 servicemap.second.erase(tm_it_tmp);
464                                                 prevTimeIt=servicemap.second.end();
465                                         }
466                                 }
467                         }
468
469                         // search in timemap, for check of a case if new time has coincided with time of other event
470                         // or event was is not found in eventmap
471                         timeMap::iterator tm_it =
472                                 servicemap.second.find(TM);
473
474                         if ( tm_it != servicemap.second.end() )
475                         {
476                                 // event with same start time but another event_id...
477                                 if ( source > tm_it->second->type &&
478                                         ev_it == servicemap.first.end() )
479                                         goto next; // when not.. then skip this entry
480
481                                 // search this time in eventmap
482                                 eventMap::iterator ev_it_tmp =
483                                         servicemap.first.find(tm_it->second->getEventID());
484
485                                 if ( ev_it_tmp != servicemap.first.end() )
486                                 {
487                                         ev_erase_count++;
488                                         // delete the found record from eventmap
489                                         servicemap.first.erase(ev_it_tmp);
490                                         prevEventIt=servicemap.first.end();
491                                 }
492                         }
493
494                         evt = new eventData(eit_event, eit_event_size, source);
495 #ifdef EPG_DEBUG
496                         bool consistencyCheck=true;
497 #endif
498                         if (ev_erase_count > 0 && tm_erase_count > 0) // 2 different pairs have been removed
499                         {
500                                 // exempt memory
501                                 delete ev_it->second;
502                                 delete tm_it->second;
503                                 ev_it->second=evt;
504                                 tm_it->second=evt;
505                         }
506                         else if (ev_erase_count == 0 && tm_erase_count > 0)
507                         {
508                                 // exempt memory
509                                 delete ev_it->second;
510                                 tm_it=prevTimeIt=servicemap.second.insert( prevTimeIt, std::pair<const time_t, eventData*>( TM, evt ) );
511                                 ev_it->second=evt;
512                         }
513                         else if (ev_erase_count > 0 && tm_erase_count == 0)
514                         {
515                                 // exempt memory
516                                 delete tm_it->second;
517                                 ev_it=prevEventIt=servicemap.first.insert( prevEventIt, std::pair<const __u16, eventData*>( event_id, evt) );
518                                 tm_it->second=evt;
519                         }
520                         else // added new eventData
521                         {
522 #ifdef EPG_DEBUG
523                                 consistencyCheck=false;
524 #endif
525                                 ev_it=prevEventIt=servicemap.first.insert( prevEventIt, std::pair<const __u16, eventData*>( event_id, evt) );
526                                 tm_it=prevTimeIt=servicemap.second.insert( prevTimeIt, std::pair<const time_t, eventData*>( TM, evt ) );
527                         }
528
529                         FixOverlapping(servicemap, TM, duration, tm_it, service);
530
531 #ifdef EPG_DEBUG
532                         if ( consistencyCheck )
533                         {
534                                 if ( tm_it->second != evt || ev_it->second != evt )
535                                         eFatal("tm_it->second != ev_it->second");
536                                 else if ( tm_it->second->getStartTime() != tm_it->first )
537                                         eFatal("event start_time(%d) non equal timemap key(%d)",
538                                                 tm_it->second->getStartTime(), tm_it->first );
539                                 else if ( tm_it->first != TM )
540                                         eFatal("timemap key(%d) non equal TM(%d)",
541                                                 tm_it->first, TM);
542                                 else if ( ev_it->second->getEventID() != ev_it->first )
543                                         eFatal("event_id (%d) non equal event_map key(%d)",
544                                                 ev_it->second->getEventID(), ev_it->first);
545                                 else if ( ev_it->first != event_id )
546                                         eFatal("eventmap key(%d) non equal event_id(%d)",
547                                                 ev_it->first, event_id );
548                         }
549 #endif
550                 }
551 next:
552 #ifdef EPG_DEBUG
553                 if ( servicemap.first.size() != servicemap.second.size() )
554                 {
555                         FILE *f = fopen("/hdd/event_map.txt", "w+");
556                         int i=0;
557                         for (eventMap::iterator it(servicemap.first.begin())
558                                 ; it != servicemap.first.end(); ++it )
559                                 fprintf(f, "%d(key %d) -> time %d, event_id %d, data %p\n", 
560                                         i++, (int)it->first, (int)it->second->getStartTime(), (int)it->second->getEventID(), it->second );
561                         fclose(f);
562                         f = fopen("/hdd/time_map.txt", "w+");
563                         i=0;
564                         for (timeMap::iterator it(servicemap.second.begin())
565                                 ; it != servicemap.second.end(); ++it )
566                                         fprintf(f, "%d(key %d) -> time %d, event_id %d, data %p\n", 
567                                                 i++, (int)it->first, (int)it->second->getStartTime(), (int)it->second->getEventID(), it->second );
568                         fclose(f);
569
570                         eFatal("(1)map sizes not equal :( sid %04x tsid %04x onid %04x size %d size2 %d", 
571                                 service.sid, service.tsid, service.onid, 
572                                 servicemap.first.size(), servicemap.second.size() );
573                 }
574 #endif
575                 ptr += eit_event_size;
576                 eit_event=(eit_event_struct*)(((__u8*)eit_event)+eit_event_size);
577         }
578 }
579
580 void eEPGCache::flushEPG(const uniqueEPGKey & s)
581 {
582         eDebug("[EPGC] flushEPG %d", (int)(bool)s);
583         singleLock l(cache_lock);
584         if (s)  // clear only this service
585         {
586                 eventCache::iterator it = eventDB.find(s);
587                 if ( it != eventDB.end() )
588                 {
589                         eventMap &evMap = it->second.first;
590                         timeMap &tmMap = it->second.second;
591                         tmMap.clear();
592                         for (eventMap::iterator i = evMap.begin(); i != evMap.end(); ++i)
593                                 delete i->second;
594                         evMap.clear();
595                         eventDB.erase(it);
596
597                         // TODO .. search corresponding channel for removed service and remove this channel from lastupdated map
598 #ifdef ENABLE_PRIVATE_EPG
599                         contentMaps::iterator it =
600                                 content_time_tables.find(s);
601                         if ( it != content_time_tables.end() )
602                         {
603                                 it->second.clear();
604                                 content_time_tables.erase(it);
605                         }
606 #endif
607                 }
608         }
609         else // clear complete EPG Cache
610         {
611                 for (eventCache::iterator it(eventDB.begin());
612                         it != eventDB.end(); ++it)
613                 {
614                         eventMap &evMap = it->second.first;
615                         timeMap &tmMap = it->second.second;
616                         for (eventMap::iterator i = evMap.begin(); i != evMap.end(); ++i)
617                                 delete i->second;
618                         evMap.clear();
619                         tmMap.clear();
620                 }
621                 eventDB.clear();
622 #ifdef ENABLE_PRIVATE_EPG
623                 content_time_tables.clear();
624 #endif
625                 channelLastUpdated.clear();
626                 singleLock m(channel_map_lock);
627                 for (channelMapIterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it)
628                         it->second->startEPG();
629         }
630         eDebug("[EPGC] %i bytes for cache used", eventData::CacheSize);
631 }
632
633 void eEPGCache::cleanLoop()
634 {
635         singleLock s(cache_lock);
636         if (!eventDB.empty())
637         {
638                 eDebug("[EPGC] start cleanloop");
639
640                 time_t now = eDVBLocalTimeHandler::getInstance()->nowTime();
641
642                 for (eventCache::iterator DBIt = eventDB.begin(); DBIt != eventDB.end(); DBIt++)
643                 {
644                         bool updated = false;
645                         for (timeMap::iterator It = DBIt->second.second.begin(); It != DBIt->second.second.end() && It->first < now;)
646                         {
647                                 if ( now > (It->first+It->second->getDuration()) )  // outdated normal entry (nvod references to)
648                                 {
649                                         // remove entry from eventMap
650                                         eventMap::iterator b(DBIt->second.first.find(It->second->getEventID()));
651                                         if ( b != DBIt->second.first.end() )
652                                         {
653                                                 // release Heap Memory for this entry   (new ....)
654 //                                              eDebug("[EPGC] delete old event (evmap)");
655                                                 DBIt->second.first.erase(b);
656                                         }
657
658                                         // remove entry from timeMap
659 //                                      eDebug("[EPGC] release heap mem");
660                                         delete It->second;
661                                         DBIt->second.second.erase(It++);
662 //                                      eDebug("[EPGC] delete old event (timeMap)");
663                                         updated = true;
664                                 }
665                                 else
666                                         ++It;
667                         }
668 #ifdef ENABLE_PRIVATE_EPG
669                         if ( updated )
670                         {
671                                 contentMaps::iterator x =
672                                         content_time_tables.find( DBIt->first );
673                                 if ( x != content_time_tables.end() )
674                                 {
675                                         timeMap &tmMap = eventDB[DBIt->first].second;
676                                         for ( contentMap::iterator i = x->second.begin(); i != x->second.end(); )
677                                         {
678                                                 for ( contentTimeMap::iterator it(i->second.begin());
679                                                         it != i->second.end(); )
680                                                 {
681                                                         if ( tmMap.find(it->second.first) == tmMap.end() )
682                                                                 i->second.erase(it++);
683                                                         else
684                                                                 ++it;
685                                                 }
686                                                 if ( i->second.size() )
687                                                         ++i;
688                                                 else
689                                                         x->second.erase(i++);
690                                         }
691                                 }
692                         }
693 #endif
694                 }
695                 eDebug("[EPGC] stop cleanloop");
696                 eDebug("[EPGC] %i bytes for cache used", eventData::CacheSize);
697         }
698         cleanTimer.start(CLEAN_INTERVAL,true);
699 }
700
701 eEPGCache::~eEPGCache()
702 {
703         messages.send(Message::quit);
704         kill(); // waiting for thread shutdown
705         singleLock s(cache_lock);
706         for (eventCache::iterator evIt = eventDB.begin(); evIt != eventDB.end(); evIt++)
707                 for (eventMap::iterator It = evIt->second.first.begin(); It != evIt->second.first.end(); It++)
708                         delete It->second;
709 }
710
711 void eEPGCache::gotMessage( const Message &msg )
712 {
713         switch (msg.type)
714         {
715                 case Message::flush:
716                         flushEPG(msg.service);
717                         break;
718                 case Message::startChannel:
719                 {
720                         singleLock s(channel_map_lock);
721                         channelMapIterator channel =
722                                 m_knownChannels.find(msg.channel);
723                         if ( channel != m_knownChannels.end() )
724                                 channel->second->startChannel();
725                         break;
726                 }
727                 case Message::leaveChannel:
728                 {
729                         singleLock s(channel_map_lock);
730                         channelMapIterator channel =
731                                 m_knownChannels.find(msg.channel);
732                         if ( channel != m_knownChannels.end() )
733                                 channel->second->abortEPG();
734                         break;
735                 }
736                 case Message::quit:
737                         quit(0);
738                         break;
739 #ifdef ENABLE_PRIVATE_EPG
740                 case Message::got_private_pid:
741                 {
742                         for (channelMapIterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it)
743                         {
744                                 eDVBChannel *channel = (eDVBChannel*) it->first;
745                                 channel_data *data = it->second;
746                                 eDVBChannelID chid = channel->getChannelID();
747                                 if ( chid.transport_stream_id.get() == msg.service.tsid &&
748                                         chid.original_network_id.get() == msg.service.onid &&
749                                         data->m_PrivatePid == -1 )
750                                 {
751                                         data->m_PrevVersion = -1;
752                                         data->m_PrivatePid = msg.pid;
753                                         data->m_PrivateService = msg.service;
754                                         updateMap::iterator It = channelLastUpdated.find( channel->getChannelID() );
755                                         int update = ( It != channelLastUpdated.end() ? ( UPDATE_INTERVAL - ( (eDVBLocalTimeHandler::getInstance()->nowTime()-It->second) * 1000 ) ) : ZAP_DELAY );
756                                         if (update < ZAP_DELAY)
757                                                 update = ZAP_DELAY;
758                                         data->startPrivateTimer.start(update, 1);
759                                         if (update >= 60000)
760                                                 eDebug("[EPGC] next private update in %i min", update/60000);
761                                         else if (update >= 1000)
762                                                 eDebug("[EPGC] next private update in %i sec", update/1000);
763                                         break;
764                                 }
765                         }
766                         break;
767                 }
768 #endif
769                 case Message::timeChanged:
770                         cleanLoop();
771                         break;
772                 default:
773                         eDebug("unhandled EPGCache Message!!");
774                         break;
775         }
776 }
777
778 void eEPGCache::thread()
779 {
780         hasStarted();
781         nice(4);
782         load();
783         cleanLoop();
784         runLoop();
785         save();
786 }
787
788 void eEPGCache::load()
789 {
790         singleLock s(cache_lock);
791         FILE *f = fopen("/hdd/epg.dat", "r");
792         if (f)
793         {
794                 int size=0;
795                 int cnt=0;
796 #if 0
797                 unsigned char md5_saved[16];
798                 unsigned char md5[16];
799                 bool md5ok=false;
800
801                 if (!md5_file("/hdd/epg.dat", 1, md5))
802                 {
803                         FILE *f = fopen("/hdd/epg.dat.md5", "r");
804                         if (f)
805                         {
806                                 fread( md5_saved, 16, 1, f);
807                                 fclose(f);
808                                 if ( !memcmp(md5_saved, md5, 16) )
809                                         md5ok=true;
810                         }
811                 }
812                 if ( md5ok )
813 #endif
814                 {
815                         unsigned int magic=0;
816                         fread( &magic, sizeof(int), 1, f);
817                         if (magic != 0x98765432)
818                         {
819                                 eDebug("epg file has incorrect byte order.. dont read it");
820                                 fclose(f);
821                                 return;
822                         }
823                         char text1[13];
824                         fread( text1, 13, 1, f);
825                         if ( !strncmp( text1, "ENIGMA_EPG_V5", 13) )
826                         {
827                                 fread( &size, sizeof(int), 1, f);
828                                 while(size--)
829                                 {
830                                         uniqueEPGKey key;
831                                         eventMap evMap;
832                                         timeMap tmMap;
833                                         int size=0;
834                                         fread( &key, sizeof(uniqueEPGKey), 1, f);
835                                         fread( &size, sizeof(int), 1, f);
836                                         while(size--)
837                                         {
838                                                 __u8 len=0;
839                                                 __u8 type=0;
840                                                 eventData *event=0;
841                                                 fread( &type, sizeof(__u8), 1, f);
842                                                 fread( &len, sizeof(__u8), 1, f);
843                                                 event = new eventData(0, len, type);
844                                                 event->EITdata = new __u8[len];
845                                                 eventData::CacheSize+=len;
846                                                 fread( event->EITdata, len, 1, f);
847                                                 evMap[ event->getEventID() ]=event;
848                                                 tmMap[ event->getStartTime() ]=event;
849                                                 ++cnt;
850                                         }
851                                         eventDB[key]=std::pair<eventMap,timeMap>(evMap,tmMap);
852                                 }
853                                 eventData::load(f);
854                                 eDebug("%d events read from /hdd/epg.dat", cnt);
855 #ifdef ENABLE_PRIVATE_EPG
856                                 char text2[11];
857                                 fread( text2, 11, 1, f);
858                                 if ( !strncmp( text2, "PRIVATE_EPG", 11) )
859                                 {
860                                         size=0;
861                                         fread( &size, sizeof(int), 1, f);
862                                         while(size--)
863                                         {
864                                                 int size=0;
865                                                 uniqueEPGKey key;
866                                                 fread( &key, sizeof(uniqueEPGKey), 1, f);
867                                                 eventMap &evMap=eventDB[key].first;
868                                                 fread( &size, sizeof(int), 1, f);
869                                                 while(size--)
870                                                 {
871                                                         int size;
872                                                         int content_id;
873                                                         fread( &content_id, sizeof(int), 1, f);
874                                                         fread( &size, sizeof(int), 1, f);
875                                                         while(size--)
876                                                         {
877                                                                 time_t time1, time2;
878                                                                 __u16 event_id;
879                                                                 fread( &time1, sizeof(time_t), 1, f);
880                                                                 fread( &time2, sizeof(time_t), 1, f);
881                                                                 fread( &event_id, sizeof(__u16), 1, f);
882                                                                 content_time_tables[key][content_id][time1]=std::pair<time_t, __u16>(time2, event_id);
883                                                                 eventMap::iterator it =
884                                                                         evMap.find(event_id);
885                                                                 if (it != evMap.end())
886                                                                         it->second->type = PRIVATE;
887                                                         }
888                                                 }
889                                         }
890                                 }
891 #endif // ENABLE_PRIVATE_EPG
892                         }
893                         else
894                                 eDebug("[EPGC] don't read old epg database");
895                         fclose(f);
896                 }
897         }
898 }
899
900 void eEPGCache::save()
901 {
902         struct statfs s;
903         off64_t tmp;
904         if (statfs("/hdd", &s)<0)
905                 tmp=0;
906         else
907         {
908                 tmp=s.f_blocks;
909                 tmp*=s.f_bsize;
910         }
911
912         // prevent writes to builtin flash
913         if ( tmp < 1024*1024*50 ) // storage size < 50MB
914                 return;
915
916         // check for enough free space on storage
917         tmp=s.f_bfree;
918         tmp*=s.f_bsize;
919         if ( tmp < (eventData::CacheSize*12)/10 ) // 20% overhead
920                 return;
921
922         FILE *f = fopen("/hdd/epg.dat", "w");
923         int cnt=0;
924         if ( f )
925         {
926                 unsigned int magic = 0x98765432;
927                 fwrite( &magic, sizeof(int), 1, f);
928                 const char *text = "ENIGMA_EPG_V5";
929                 fwrite( text, 13, 1, f );
930                 int size = eventDB.size();
931                 fwrite( &size, sizeof(int), 1, f );
932                 for (eventCache::iterator service_it(eventDB.begin()); service_it != eventDB.end(); ++service_it)
933                 {
934                         timeMap &timemap = service_it->second.second;
935                         fwrite( &service_it->first, sizeof(uniqueEPGKey), 1, f);
936                         size = timemap.size();
937                         fwrite( &size, sizeof(int), 1, f);
938                         for (timeMap::iterator time_it(timemap.begin()); time_it != timemap.end(); ++time_it)
939                         {
940                                 __u8 len = time_it->second->ByteSize;
941                                 fwrite( &time_it->second->type, sizeof(__u8), 1, f );
942                                 fwrite( &len, sizeof(__u8), 1, f);
943                                 fwrite( time_it->second->EITdata, len, 1, f);
944                                 ++cnt;
945                         }
946                 }
947                 eDebug("%d events written to /hdd/epg.dat", cnt);
948                 eventData::save(f);
949 #ifdef ENABLE_PRIVATE_EPG
950                 const char* text3 = "PRIVATE_EPG";
951                 fwrite( text3, 11, 1, f );
952                 size = content_time_tables.size();
953                 fwrite( &size, sizeof(int), 1, f);
954                 for (contentMaps::iterator a = content_time_tables.begin(); a != content_time_tables.end(); ++a)
955                 {
956                         contentMap &content_time_table = a->second;
957                         fwrite( &a->first, sizeof(uniqueEPGKey), 1, f);
958                         int size = content_time_table.size();
959                         fwrite( &size, sizeof(int), 1, f);
960                         for (contentMap::iterator i = content_time_table.begin(); i != content_time_table.end(); ++i )
961                         {
962                                 int size = i->second.size();
963                                 fwrite( &i->first, sizeof(int), 1, f);
964                                 fwrite( &size, sizeof(int), 1, f);
965                                 for ( contentTimeMap::iterator it(i->second.begin());
966                                         it != i->second.end(); ++it )
967                                 {
968                                         fwrite( &it->first, sizeof(time_t), 1, f);
969                                         fwrite( &it->second.first, sizeof(time_t), 1, f);
970                                         fwrite( &it->second.second, sizeof(__u16), 1, f);
971                                 }
972                         }
973                 }
974 #endif
975                 fclose(f);
976 #if 0
977                 unsigned char md5[16];
978                 if (!md5_file("/hdd/epg.dat", 1, md5))
979                 {
980                         FILE *f = fopen("/hdd/epg.dat.md5", "w");
981                         if (f)
982                         {
983                                 fwrite( md5, 16, 1, f);
984                                 fclose(f);
985                         }
986                 }
987 #endif
988         }
989 }
990
991 eEPGCache::channel_data::channel_data(eEPGCache *ml)
992         :cache(ml)
993         ,abortTimer(ml), zapTimer(ml), state(0)
994         ,isRunning(0), haveData(0)
995 #ifdef ENABLE_PRIVATE_EPG
996         ,startPrivateTimer(ml)
997 #endif
998 #ifdef ENABLE_MHW_EPG
999         ,m_MHWTimeoutTimer(ml)
1000 #endif
1001 {
1002 #ifdef ENABLE_MHW_EPG
1003         CONNECT(m_MHWTimeoutTimer.timeout, eEPGCache::channel_data::MHWTimeout);
1004 #endif
1005         CONNECT(zapTimer.timeout, eEPGCache::channel_data::startEPG);
1006         CONNECT(abortTimer.timeout, eEPGCache::channel_data::abortNonAvail);
1007 #ifdef ENABLE_PRIVATE_EPG
1008         CONNECT(startPrivateTimer.timeout, eEPGCache::channel_data::startPrivateReader);
1009 #endif
1010 }
1011
1012 bool eEPGCache::channel_data::finishEPG()
1013 {
1014         if (!isRunning)  // epg ready
1015         {
1016                 eDebug("[EPGC] stop caching events(%ld)", eDVBLocalTimeHandler::getInstance()->nowTime());
1017                 zapTimer.start(UPDATE_INTERVAL, 1);
1018                 eDebug("[EPGC] next update in %i min", UPDATE_INTERVAL / 60000);
1019                 for (int i=0; i < 3; ++i)
1020                 {
1021                         seenSections[i].clear();
1022                         calcedSections[i].clear();
1023                 }
1024                 singleLock l(cache->cache_lock);
1025                 cache->channelLastUpdated[channel->getChannelID()] = eDVBLocalTimeHandler::getInstance()->nowTime();
1026 #ifdef ENABLE_MHW_EPG
1027                 cleanup();
1028 #endif
1029                 return true;
1030         }
1031         return false;
1032 }
1033
1034 void eEPGCache::channel_data::startEPG()
1035 {
1036         eDebug("[EPGC] start caching events(%ld)", eDVBLocalTimeHandler::getInstance()->nowTime());
1037         state=0;
1038         haveData=0;
1039         for (int i=0; i < 3; ++i)
1040         {
1041                 seenSections[i].clear();
1042                 calcedSections[i].clear();
1043         }
1044
1045         eDVBSectionFilterMask mask;
1046         memset(&mask, 0, sizeof(mask));
1047
1048 #ifdef ENABLE_MHW_EPG
1049         mask.pid = 0xD3;
1050         mask.data[0] = 0x91;
1051         mask.mask[0] = 0xFF;
1052         m_MHWReader->connectRead(slot(*this, &eEPGCache::channel_data::readMHWData), m_MHWConn);
1053         m_MHWReader->start(mask);
1054         isRunning |= MHW;
1055         memcpy(&m_MHWFilterMask, &mask, sizeof(eDVBSectionFilterMask));
1056 #endif
1057
1058         mask.pid = 0x12;
1059         mask.flags = eDVBSectionFilterMask::rfCRC;
1060
1061         mask.data[0] = 0x4E;
1062         mask.mask[0] = 0xFE;
1063         m_NowNextReader->connectRead(slot(*this, &eEPGCache::channel_data::readData), m_NowNextConn);
1064         m_NowNextReader->start(mask);
1065         isRunning |= NOWNEXT;
1066
1067         mask.data[0] = 0x50;
1068         mask.mask[0] = 0xF0;
1069         m_ScheduleReader->connectRead(slot(*this, &eEPGCache::channel_data::readData), m_ScheduleConn);
1070         m_ScheduleReader->start(mask);
1071         isRunning |= SCHEDULE;
1072
1073         mask.data[0] = 0x60;
1074         mask.mask[0] = 0xF0;
1075         m_ScheduleOtherReader->connectRead(slot(*this, &eEPGCache::channel_data::readData), m_ScheduleOtherConn);
1076         m_ScheduleOtherReader->start(mask);
1077         isRunning |= SCHEDULE_OTHER;
1078
1079         abortTimer.start(7000,true);
1080 }
1081
1082 void eEPGCache::channel_data::abortNonAvail()
1083 {
1084         if (!state)
1085         {
1086                 if ( !(haveData&NOWNEXT) && (isRunning&NOWNEXT) )
1087                 {
1088                         eDebug("[EPGC] abort non avail nownext reading");
1089                         isRunning &= ~NOWNEXT;
1090                         m_NowNextReader->stop();
1091                         m_NowNextConn=0;
1092                 }
1093                 if ( !(haveData&SCHEDULE) && (isRunning&SCHEDULE) )
1094                 {
1095                         eDebug("[EPGC] abort non avail schedule reading");
1096                         isRunning &= ~SCHEDULE;
1097                         m_ScheduleReader->stop();
1098                         m_ScheduleConn=0;
1099                 }
1100                 if ( !(haveData&SCHEDULE_OTHER) && (isRunning&SCHEDULE_OTHER) )
1101                 {
1102                         eDebug("[EPGC] abort non avail schedule_other reading");
1103                         isRunning &= ~SCHEDULE_OTHER;
1104                         m_ScheduleOtherReader->stop();
1105                         m_ScheduleOtherConn=0;
1106                 }
1107 #ifdef ENABLE_MHW_EPG
1108                 if ( !(haveData&MHW) && (isRunning&MHW) )
1109                 {
1110                         eDebug("[EPGC] abort non avail mhw reading");
1111                         isRunning &= ~MHW;
1112                         m_MHWReader->stop();
1113                         m_MHWConn=0;
1114                 }
1115 #endif
1116                 if ( isRunning )
1117                         abortTimer.start(90000, true);
1118                 else
1119                 {
1120                         ++state;
1121                         for (int i=0; i < 3; ++i)
1122                         {
1123                                 seenSections[i].clear();
1124                                 calcedSections[i].clear();
1125                         }
1126                 }
1127         }
1128         ++state;
1129 }
1130
1131 void eEPGCache::channel_data::startChannel()
1132 {
1133         updateMap::iterator It = cache->channelLastUpdated.find( channel->getChannelID() );
1134
1135         int update = ( It != cache->channelLastUpdated.end() ? ( UPDATE_INTERVAL - ( (eDVBLocalTimeHandler::getInstance()->nowTime()-It->second) * 1000 ) ) : ZAP_DELAY );
1136
1137         if (update < ZAP_DELAY)
1138                 update = ZAP_DELAY;
1139
1140         zapTimer.start(update, 1);
1141         if (update >= 60000)
1142                 eDebug("[EPGC] next update in %i min", update/60000);
1143         else if (update >= 1000)
1144                 eDebug("[EPGC] next update in %i sec", update/1000);
1145 }
1146
1147 void eEPGCache::channel_data::abortEPG()
1148 {
1149         for (int i=0; i < 3; ++i)
1150         {
1151                 seenSections[i].clear();
1152                 calcedSections[i].clear();
1153         }
1154         abortTimer.stop();
1155         zapTimer.stop();
1156         if (isRunning)
1157         {
1158                 eDebug("[EPGC] abort caching events !!");
1159                 if (isRunning & SCHEDULE)
1160                 {
1161                         isRunning &= ~SCHEDULE;
1162                         m_ScheduleReader->stop();
1163                         m_ScheduleConn=0;
1164                 }
1165                 if (isRunning & NOWNEXT)
1166                 {
1167                         isRunning &= ~NOWNEXT;
1168                         m_NowNextReader->stop();
1169                         m_NowNextConn=0;
1170                 }
1171                 if (isRunning & SCHEDULE_OTHER)
1172                 {
1173                         isRunning &= ~SCHEDULE_OTHER;
1174                         m_ScheduleOtherReader->stop();
1175                         m_ScheduleOtherConn=0;
1176                 }
1177 #ifdef ENABLE_MHW_EPG
1178                 if (isRunning & MHW)
1179                 {
1180                         isRunning &= ~MHW;
1181                         m_MHWReader->stop();
1182                         m_MHWConn=0;
1183                 }
1184 #endif
1185         }
1186 #ifdef ENABLE_PRIVATE_EPG
1187         if (m_PrivateReader)
1188                 m_PrivateReader->stop();
1189         if (m_PrivateConn)
1190                 m_PrivateConn=0;
1191 #endif
1192 }
1193
1194 void eEPGCache::channel_data::readData( const __u8 *data)
1195 {
1196         if (!data)
1197                 eDebug("get Null pointer from section reader !!");
1198         else
1199         {
1200                 int source;
1201                 int map;
1202                 iDVBSectionReader *reader=NULL;
1203                 switch(data[0])
1204                 {
1205                         case 0x4E ... 0x4F:
1206                                 reader=m_NowNextReader;
1207                                 source=NOWNEXT;
1208                                 map=0;
1209                                 break;
1210                         case 0x50 ... 0x5F:
1211                                 reader=m_ScheduleReader;
1212                                 source=SCHEDULE;
1213                                 map=1;
1214                                 break;
1215                         case 0x60 ... 0x6F:
1216                                 reader=m_ScheduleOtherReader;
1217                                 source=SCHEDULE_OTHER;
1218                                 map=2;
1219                                 break;
1220                         default:
1221                                 eDebug("[EPGC] unknown table_id !!!");
1222                                 return;
1223                 }
1224                 tidMap &seenSections = this->seenSections[map];
1225                 tidMap &calcedSections = this->calcedSections[map];
1226                 if ( state == 1 && calcedSections == seenSections || state > 1 )
1227                 {
1228                         eDebugNoNewLine("[EPGC] ");
1229                         switch (source)
1230                         {
1231                                 case NOWNEXT:
1232                                         m_NowNextConn=0;
1233                                         eDebugNoNewLine("nownext");
1234                                         break;
1235                                 case SCHEDULE:
1236                                         m_ScheduleConn=0;
1237                                         eDebugNoNewLine("schedule");
1238                                         break;
1239                                 case SCHEDULE_OTHER:
1240                                         m_ScheduleOtherConn=0;
1241                                         eDebugNoNewLine("schedule other");
1242                                         break;
1243                                 default: eDebugNoNewLine("unknown");break;
1244                         }
1245                         eDebug(" finished(%ld)", eDVBLocalTimeHandler::getInstance()->nowTime());
1246                         if ( reader )
1247                                 reader->stop();
1248                         isRunning &= ~source;
1249                         if (!isRunning)
1250                                 finishEPG();
1251                 }
1252                 else
1253                 {
1254                         eit_t *eit = (eit_t*) data;
1255                         __u32 sectionNo = data[0] << 24;
1256                         sectionNo |= data[3] << 16;
1257                         sectionNo |= data[4] << 8;
1258                         sectionNo |= eit->section_number;
1259
1260                         tidMap::iterator it =
1261                                 seenSections.find(sectionNo);
1262
1263                         if ( it == seenSections.end() )
1264                         {
1265                                 seenSections.insert(sectionNo);
1266                                 calcedSections.insert(sectionNo);
1267                                 __u32 tmpval = sectionNo & 0xFFFFFF00;
1268                                 __u8 incr = source == NOWNEXT ? 1 : 8;
1269                                 for ( int i = 0; i <= eit->last_section_number; i+=incr )
1270                                 {
1271                                         if ( i == eit->section_number )
1272                                         {
1273                                                 for (int x=i; x <= eit->segment_last_section_number; ++x)
1274                                                         calcedSections.insert(tmpval|(x&0xFF));
1275                                         }
1276                                         else
1277                                                 calcedSections.insert(tmpval|(i&0xFF));
1278                                 }
1279                                 cache->sectionRead(data, source, this);
1280                         }
1281                 }
1282         }
1283 }
1284
1285 RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, const eventData *&result, int direction)
1286 // if t == -1 we search the current event...
1287 {
1288         singleLock s(cache_lock);
1289         uniqueEPGKey key(service);
1290
1291         // check if EPG for this service is ready...
1292         eventCache::iterator It = eventDB.find( key );
1293         if ( It != eventDB.end() && !It->second.first.empty() ) // entrys cached ?
1294         {
1295                 if (t==-1)
1296                         t = eDVBLocalTimeHandler::getInstance()->nowTime();
1297                 timeMap::iterator i = direction <= 0 ? It->second.second.lower_bound(t) :  // find > or equal
1298                         It->second.second.upper_bound(t); // just >
1299                 if ( i != It->second.second.end() )
1300                 {
1301                         if ( direction < 0 || (direction == 0 && i->second->getStartTime() > t) )
1302                         {
1303                                 timeMap::iterator x = i;
1304                                 --x;
1305                                 if ( x != It->second.second.end() )
1306                                 {
1307                                         time_t start_time = x->second->getStartTime();
1308                                         if (direction >= 0)
1309                                         {
1310                                                 if (t < start_time)
1311                                                         return -1;
1312                                                 if (t > (start_time+x->second->getDuration()))
1313                                                         return -1;
1314                                         }
1315                                         i = x;
1316                                 }
1317                                 else
1318                                         return -1;
1319                         }
1320                         result = i->second;
1321                         return 0;
1322                 }
1323         }
1324         return -1;
1325 }
1326
1327 RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, const eit_event_struct *&result, int direction)
1328 {
1329         singleLock s(cache_lock);
1330         const eventData *data=0;
1331         RESULT ret = lookupEventTime(service, t, data, direction);
1332         if ( !ret && data )
1333                 result = data->get();
1334         return ret;
1335 }
1336
1337 RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, Event *& result, int direction)
1338 {
1339         singleLock s(cache_lock);
1340         const eventData *data=0;
1341         RESULT ret = lookupEventTime(service, t, data, direction);
1342         if ( !ret && data )
1343                 result = new Event((uint8_t*)data->get());
1344         return ret;
1345 }
1346
1347 RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, ePtr<eServiceEvent> &result, int direction)
1348 {
1349         singleLock s(cache_lock);
1350         const eventData *data=0;
1351         RESULT ret = lookupEventTime(service, t, data, direction);
1352         if ( !ret && data )
1353         {
1354                 Event ev((uint8_t*)data->get());
1355                 result = new eServiceEvent();
1356                 const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)service;
1357                 ret = result->parseFrom(&ev, (ref.getTransportStreamID().get()<<16)|ref.getOriginalNetworkID().get());
1358         }
1359         return ret;
1360 }
1361
1362 RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, const eventData *&result )
1363 {
1364         singleLock s(cache_lock);
1365         uniqueEPGKey key( service );
1366
1367         eventCache::iterator It = eventDB.find( key );
1368         if ( It != eventDB.end() && !It->second.first.empty() ) // entrys cached?
1369         {
1370                 eventMap::iterator i( It->second.first.find( event_id ));
1371                 if ( i != It->second.first.end() )
1372                 {
1373                         result = i->second;
1374                         return 0;
1375                 }
1376                 else
1377                 {
1378                         result = 0;
1379                         eDebug("event %04x not found in epgcache", event_id);
1380                 }
1381         }
1382         return -1;
1383 }
1384
1385 RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, const eit_event_struct *&result)
1386 {
1387         singleLock s(cache_lock);
1388         const eventData *data=0;
1389         RESULT ret = lookupEventId(service, event_id, data);
1390         if ( !ret && data )
1391                 result = data->get();
1392         return ret;
1393 }
1394
1395 RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, Event *& result)
1396 {
1397         singleLock s(cache_lock);
1398         const eventData *data=0;
1399         RESULT ret = lookupEventId(service, event_id, data);
1400         if ( !ret && data )
1401                 result = new Event((uint8_t*)data->get());
1402         return ret;
1403 }
1404
1405 RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, ePtr<eServiceEvent> &result)
1406 {
1407         singleLock s(cache_lock);
1408         const eventData *data=0;
1409         RESULT ret = lookupEventId(service, event_id, data);
1410         if ( !ret && data )
1411         {
1412                 Event ev((uint8_t*)data->get());
1413                 result = new eServiceEvent();
1414                 const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)service;
1415                 ret = result->parseFrom(&ev, (ref.getTransportStreamID().get()<<16)|ref.getOriginalNetworkID().get());
1416         }
1417         return ret;
1418 }
1419
1420 RESULT eEPGCache::startTimeQuery(const eServiceReference &service, time_t begin, int minutes)
1421 {
1422         eventCache::iterator It = eventDB.find( service );
1423         if ( It != eventDB.end() && It->second.second.size() )
1424         {
1425                 m_timemap_end = minutes != -1 ? It->second.second.upper_bound(begin+minutes*60) : It->second.second.end();
1426                 if ( begin != -1 )
1427                 {
1428                         m_timemap_cursor = It->second.second.lower_bound(begin);
1429                         if ( m_timemap_cursor != It->second.second.end() )
1430                         {
1431                                 if ( m_timemap_cursor->second->getStartTime() != begin )
1432                                 {
1433                                         timeMap::iterator x = m_timemap_cursor;
1434                                         --x;
1435                                         if ( x != It->second.second.end() )
1436                                         {
1437                                                 time_t start_time = x->second->getStartTime();
1438                                                 if ( begin > start_time && begin < (start_time+x->second->getDuration()))
1439                                                         m_timemap_cursor = x;
1440                                         }
1441                                 }
1442                         }
1443                 }
1444                 else
1445                         m_timemap_cursor = It->second.second.begin();
1446                 const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)service;
1447                 currentQueryTsidOnid = (ref.getTransportStreamID().get()<<16) | ref.getOriginalNetworkID().get();
1448                 return 0;
1449         }
1450         return -1;
1451 }
1452
1453 RESULT eEPGCache::getNextTimeEntry(const eventData *& result)
1454 {
1455         if ( m_timemap_cursor != m_timemap_end )
1456         {
1457                 result = m_timemap_cursor++->second;
1458                 return 0;
1459         }
1460         return -1;
1461 }
1462
1463 RESULT eEPGCache::getNextTimeEntry(const eit_event_struct *&result)
1464 {
1465         if ( m_timemap_cursor != m_timemap_end )
1466         {
1467                 result = m_timemap_cursor++->second->get();
1468                 return 0;
1469         }
1470         return -1;
1471 }
1472
1473 RESULT eEPGCache::getNextTimeEntry(Event *&result)
1474 {
1475         if ( m_timemap_cursor != m_timemap_end )
1476         {
1477                 result = new Event((uint8_t*)m_timemap_cursor++->second->get());
1478                 return 0;
1479         }
1480         return -1;
1481 }
1482
1483 RESULT eEPGCache::getNextTimeEntry(ePtr<eServiceEvent> &result)
1484 {
1485         if ( m_timemap_cursor != m_timemap_end )
1486         {
1487                 Event ev((uint8_t*)m_timemap_cursor++->second->get());
1488                 result = new eServiceEvent();
1489                 return result->parseFrom(&ev, currentQueryTsidOnid);
1490         }
1491         return -1;
1492 }
1493
1494 void fillTuple(PyObject *tuple, char *argstring, int argcount, PyObject *service, ePtr<eServiceEvent> &ptr, PyObject *nowTime, PyObject *service_name )
1495 {
1496         PyObject *tmp=NULL;
1497         int pos=0;
1498         while(pos < argcount)
1499         {
1500                 bool inc_refcount=false;
1501                 switch(argstring[pos])
1502                 {
1503                         case '0': // PyLong 0
1504                                 tmp = PyLong_FromLong(0);
1505                                 break;
1506                         case 'I': // Event Id
1507                                 tmp = ptr ? PyLong_FromLong(ptr->getEventId()) : NULL;
1508                                 break;
1509                         case 'B': // Event Begin Time
1510                                 tmp = ptr ? PyLong_FromLong(ptr->getBeginTime()) : NULL;
1511                                 break;
1512                         case 'D': // Event Duration
1513                                 tmp = ptr ? PyLong_FromLong(ptr->getDuration()) : NULL;
1514                                 break;
1515                         case 'T': // Event Title
1516                                 tmp = ptr ? PyString_FromString(ptr->getEventName().c_str()) : NULL;
1517                                 break;
1518                         case 'S': // Event Short Description
1519                                 tmp = ptr ? PyString_FromString(ptr->getShortDescription().c_str()) : NULL;
1520                                 break;
1521                         case 'E': // Event Extended Description
1522                                 tmp = ptr ? PyString_FromString(ptr->getExtendedDescription().c_str()) : NULL;
1523                                 break;
1524                         case 'C': // Current Time
1525                                 tmp = nowTime;
1526                                 inc_refcount = true;
1527                                 break;
1528                         case 'R': // service reference string
1529                                 tmp = service;
1530                                 inc_refcount = true;
1531                                 break;
1532                         case 'N': // service name
1533                                 tmp = service_name;
1534                                 inc_refcount = true;
1535                 }
1536                 if (!tmp)
1537                 {
1538                         tmp = Py_None;
1539                         inc_refcount = true;
1540                 }
1541                 if (inc_refcount)
1542                         Py_INCREF(tmp);
1543                 PyTuple_SET_ITEM(tuple, pos++, tmp);
1544         }
1545 }
1546
1547 PyObject *handleEvent(ePtr<eServiceEvent> &ptr, PyObject *dest_list, char* argstring, int argcount, PyObject *service, PyObject *nowTime, PyObject *service_name, PyObject *convertFunc, PyObject *convertFuncArgs)
1548 {
1549         if (convertFunc)
1550         {
1551                 fillTuple(convertFuncArgs, argstring, argcount, service, ptr, nowTime, service_name);
1552                 PyObject *result = PyObject_CallObject(convertFunc, convertFuncArgs);
1553                 if (result == NULL)
1554                 {
1555                         if (service_name)
1556                                 Py_DECREF(service_name);
1557                         if (nowTime)
1558                                 Py_DECREF(nowTime);
1559                         Py_DECREF(convertFuncArgs);
1560                         Py_DECREF(dest_list);
1561                         return result;
1562                 }
1563                 PyList_Append(dest_list, result);
1564                 Py_DECREF(result);
1565         }
1566         else
1567         {
1568                 PyObject *tuple = PyTuple_New(argcount);
1569                 fillTuple(tuple, argstring, argcount, service, ptr, nowTime, service_name);
1570                 PyList_Append(dest_list, tuple);
1571                 Py_DECREF(tuple);
1572         }
1573         return 0;
1574 }
1575
1576 // here we get a python list
1577 // the first entry in the list is a python string to specify the format of the returned tuples (in a list)
1578 //   0 = PyLong(0)
1579 //   I = Event Id
1580 //   B = Event Begin Time
1581 //   D = Event Duration
1582 //   T = Event Title
1583 //   S = Event Short Description
1584 //   E = Event Extended Description
1585 //   C = Current Time
1586 //   R = Service Reference
1587 //   N = Service Name
1588 // then for each service follows a tuple
1589 //   first tuple entry is the servicereference (as string... use the ref.toString() function)
1590 //   the second is the type of query
1591 //     2 = event_id
1592 //    -1 = event before given start_time
1593 //     0 = event intersects given start_time
1594 //    +1 = event after given start_time
1595 //   the third
1596 //      when type is eventid it is the event_id
1597 //      when type is time then it is the start_time ( 0 for now_time )
1598 //   the fourth is the end_time .. ( optional .. for query all events in time range)
1599
1600 PyObject *eEPGCache::lookupEvent(PyObject *list, PyObject *convertFunc)
1601 {
1602         PyObject *convertFuncArgs=NULL;
1603         int argcount=0;
1604         char *argstring=NULL;
1605         if (!PyList_Check(list))
1606         {
1607                 PyErr_SetString(PyExc_StandardError,
1608                         "type error");
1609                 eDebug("no list");
1610                 return NULL;
1611         }
1612         int listIt=0;
1613         int listSize=PyList_Size(list);
1614         if (!listSize)
1615         {
1616                 PyErr_SetString(PyExc_StandardError,
1617                         "not params given");
1618                 eDebug("not params given");
1619                 return NULL;
1620         }
1621         else 
1622         {
1623                 PyObject *argv=PyList_GET_ITEM(list, 0); // borrowed reference!
1624                 if (PyString_Check(argv))
1625                 {
1626                         argstring = PyString_AS_STRING(argv);
1627                         ++listIt;
1628                 }
1629                 else
1630                         argstring = "I"; // just event id as default
1631                 argcount = strlen(argstring);
1632 //              eDebug("have %d args('%s')", argcount, argstring);
1633         }
1634         if (convertFunc)
1635         {
1636                 if (!PyCallable_Check(convertFunc))
1637                 {
1638                         PyErr_SetString(PyExc_StandardError,
1639                                 "convertFunc must be callable");
1640                         eDebug("convertFunc is not callable");
1641                         return NULL;
1642                 }
1643                 convertFuncArgs = PyTuple_New(argcount);
1644         }
1645
1646         PyObject *nowTime = strchr(argstring, 'C') ?
1647                 PyLong_FromLong(eDVBLocalTimeHandler::getInstance()->nowTime()) :
1648                 NULL;
1649
1650         bool must_get_service_name = strchr(argstring, 'N') ? true : false;
1651
1652         // create dest list
1653         PyObject *dest_list=PyList_New(0);
1654         while(listSize > listIt)
1655         {
1656                 PyObject *item=PyList_GET_ITEM(list, listIt++); // borrowed reference!
1657                 if (PyTuple_Check(item))
1658                 {
1659                         bool service_changed=false;
1660                         int type=0;
1661                         long event_id=-1;
1662                         time_t stime=-1;
1663                         int minutes=0;
1664                         int tupleSize=PyTuple_Size(item);
1665                         int tupleIt=0;
1666                         PyObject *service=NULL;
1667                         while(tupleSize > tupleIt)  // parse query args
1668                         {
1669                                 PyObject *entry=PyTuple_GET_ITEM(item, tupleIt); // borrowed reference!
1670                                 switch(tupleIt++)
1671                                 {
1672                                         case 0:
1673                                         {
1674                                                 if (!PyString_Check(entry))
1675                                                 {
1676                                                         eDebug("tuple entry 0 is no a string");
1677                                                         goto skip_entry;
1678                                                 }
1679                                                 service = entry;
1680                                                 break;
1681                                         }
1682                                         case 1:
1683                                                 type=PyInt_AsLong(entry);
1684                                                 if (type < -1 || type > 2)
1685                                                 {
1686                                                         eDebug("unknown type %d", type);
1687                                                         goto skip_entry;
1688                                                 }
1689                                                 break;
1690                                         case 2:
1691                                                 event_id=stime=PyInt_AsLong(entry);
1692                                                 break;
1693                                         case 3:
1694                                                 minutes=PyInt_AsLong(entry);
1695                                                 break;
1696                                         default:
1697                                                 eDebug("unneeded extra argument");
1698                                                 break;
1699                                 }
1700                         }
1701                         eServiceReference ref(PyString_AS_STRING(service));
1702                         if (ref.type != eServiceReference::idDVB)
1703                         {
1704                                 eDebug("service reference for epg query is not valid");
1705                                 continue;
1706                         }
1707
1708                         // redirect subservice querys to parent service
1709                         eServiceReferenceDVB &dvb_ref = (eServiceReferenceDVB&)ref;
1710                         if (dvb_ref.getParentTransportStreamID().get()) // linkage subservice
1711                         {
1712                                 eServiceCenterPtr service_center;
1713                                 if (!eServiceCenter::getPrivInstance(service_center))
1714                                 {
1715                                         dvb_ref.setTransportStreamID( dvb_ref.getParentTransportStreamID() );
1716                                         dvb_ref.setServiceID( dvb_ref.getParentServiceID() );
1717                                         dvb_ref.setParentTransportStreamID(eTransportStreamID(0));
1718                                         dvb_ref.setParentServiceID(eServiceID(0));
1719                                         dvb_ref.name="";
1720                                         service = PyString_FromString(dvb_ref.toString().c_str());
1721                                         service_changed = true;
1722                                 }
1723                         }
1724
1725                         PyObject *service_name=NULL;
1726                         if (must_get_service_name)
1727                         {
1728                                 ePtr<iStaticServiceInformation> sptr;
1729                                 eServiceCenterPtr service_center;
1730                                 eServiceCenter::getPrivInstance(service_center);
1731                                 if (service_center)
1732                                 {
1733                                         service_center->info(ref, sptr);
1734                                         if (sptr)
1735                                         {
1736                                                 std::string name;
1737                                                 sptr->getName(ref, name);
1738                                                 if (name.length())
1739                                                         service_name = PyString_FromString(name.c_str());
1740                                         }
1741                                 }
1742                                 if (!service_name)
1743                                         service_name = PyString_FromString("<n/a>");
1744                         }
1745                         if (minutes)
1746                         {
1747                                 Lock();
1748                                 if (!startTimeQuery(ref, stime, minutes))
1749                                 {
1750                                         ePtr<eServiceEvent> ptr;
1751                                         while (!getNextTimeEntry(ptr))
1752                                         {
1753                                                 PyObject *ret = handleEvent(ptr, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs);
1754                                                 if (ret)
1755                                                         return ret;
1756                                         }
1757                                 }
1758                                 Unlock();
1759                         }
1760                         else
1761                         {
1762                                 ePtr<eServiceEvent> ptr;
1763                                 if (stime)
1764                                 {
1765                                         if (type == 2)
1766                                                 lookupEventId(ref, event_id, ptr);
1767                                         else
1768                                                 lookupEventTime(ref, stime, ptr, type);
1769                                 }
1770                                 PyObject *ret = handleEvent(ptr, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs);
1771                                 if (ret)
1772                                         return ret;
1773                         }
1774                         if (service_changed)
1775                                 Py_DECREF(service);
1776                         if (service_name)
1777                                 Py_DECREF(service_name);
1778                 }
1779 skip_entry:
1780                 ;
1781         }
1782         if (convertFuncArgs)
1783                 Py_DECREF(convertFuncArgs);
1784         if (nowTime)
1785                 Py_DECREF(nowTime);
1786         return dest_list;
1787 }
1788
1789 void fillTuple2(PyObject *tuple, const char *argstring, int argcount, eventData *evData, ePtr<eServiceEvent> &ptr, PyObject *service_name, PyObject *service_reference)
1790 {
1791         PyObject *tmp=NULL;
1792         int pos=0;
1793         while(pos < argcount)
1794         {
1795                 bool inc_refcount=false;
1796                 switch(argstring[pos])
1797                 {
1798                         case '0': // PyLong 0
1799                                 tmp = PyLong_FromLong(0);
1800                                 break;
1801                         case 'I': // Event Id
1802                                 tmp = PyLong_FromLong(evData->getEventID());
1803                                 break;
1804                         case 'B': // Event Begin Time
1805                                 if (ptr)
1806                                         tmp = ptr ? PyLong_FromLong(ptr->getBeginTime()) : NULL;
1807                                 else
1808                                         tmp = PyLong_FromLong(evData->getStartTime());
1809                                 break;
1810                         case 'D': // Event Duration
1811                                 if (ptr)
1812                                         tmp = ptr ? PyLong_FromLong(ptr->getDuration()) : NULL;
1813                                 else
1814                                         tmp = PyLong_FromLong(evData->getDuration());
1815                                 break;
1816                         case 'T': // Event Title
1817                                 tmp = ptr ? PyString_FromString(ptr->getEventName().c_str()) : NULL;
1818                                 break;
1819                         case 'S': // Event Short Description
1820                                 tmp = ptr ? PyString_FromString(ptr->getShortDescription().c_str()) : NULL;
1821                                 break;
1822                         case 'E': // Event Extended Description
1823                                 tmp = ptr ? PyString_FromString(ptr->getExtendedDescription().c_str()) : NULL;
1824                                 break;
1825                         case 'R': // service reference string
1826                                 tmp = service_reference;
1827                                 inc_refcount = true;
1828                                 break;
1829                         case 'N': // service name
1830                                 tmp = service_name;
1831                                 inc_refcount = true;
1832                                 break;
1833                 }
1834                 if (!tmp)
1835                 {
1836                         tmp = Py_None;
1837                         inc_refcount = true;
1838                 }
1839                 if (inc_refcount)
1840                         Py_INCREF(tmp);
1841                 PyTuple_SET_ITEM(tuple, pos++, tmp);
1842         }
1843 }
1844
1845 // here we get a python tuple
1846 // the first entry in the tuple is a python string to specify the format of the returned tuples (in a list)
1847 //   I = Event Id
1848 //   B = Event Begin Time
1849 //   D = Event Duration
1850 //   T = Event Title
1851 //   S = Event Short Description
1852 //   E = Event Extended Description
1853 //   R = Service Reference
1854 //   N = Service Name
1855 //  the second tuple entry is the MAX matches value
1856 //  the third tuple entry is the type of query
1857 //     0 = search for similar broadcastings (SIMILAR_BROADCASTINGS_SEARCH)
1858 //     1 = search events with exactly title name (EXAKT_TITLE_SEARCH)
1859 //     2 = search events with text in title name (PARTIAL_TITLE_SEARCH)
1860 //  when type is 0 (SIMILAR_BROADCASTINGS_SEARCH)
1861 //   the fourth is the servicereference string
1862 //   the fifth is the eventid
1863 //  when type is 1 or 2 (EXAKT_TITLE_SEARCH or PARTIAL_TITLE_SEARCH)
1864 //   the fourth is the search text
1865 //   the fifth is
1866 //     0 = case sensitive (CASE_CHECK)
1867 //     1 = case insensitive (NO_CASECHECK)
1868
1869 PyObject *eEPGCache::search(PyObject *arg)
1870 {
1871         PyObject *ret = 0;
1872         int descridx = -1;
1873         __u32 descr[512];
1874         int eventid = -1;
1875         const char *argstring=0;
1876         char *refstr=0;
1877         int argcount=0;
1878         int querytype=-1;
1879         bool needServiceEvent=false;
1880         int maxmatches=0;
1881
1882         if (PyTuple_Check(arg))
1883         {
1884                 int tuplesize=PyTuple_Size(arg);
1885                 if (tuplesize > 0)
1886                 {
1887                         PyObject *obj = PyTuple_GET_ITEM(arg,0);
1888                         if (PyString_Check(obj))
1889                         {
1890                                 argcount = PyString_GET_SIZE(obj);
1891                                 argstring = PyString_AS_STRING(obj);
1892                                 for (int i=0; i < argcount; ++i)
1893                                         switch(argstring[i])
1894                                         {
1895                                         case 'S':
1896                                         case 'E':
1897                                         case 'T':
1898                                                 needServiceEvent=true;
1899                                         default:
1900                                                 break;
1901                                         }
1902                         }
1903                         else
1904                         {
1905                                 PyErr_SetString(PyExc_StandardError,
1906                                         "type error");
1907                                 eDebug("tuple arg 0 is not a string");
1908                                 return NULL;
1909                         }
1910                 }
1911                 if (tuplesize > 1)
1912                         maxmatches = PyLong_AsLong(PyTuple_GET_ITEM(arg, 1));
1913                 if (tuplesize > 2)
1914                 {
1915                         querytype = PyLong_AsLong(PyTuple_GET_ITEM(arg, 2));
1916                         if (tuplesize > 4 && querytype == 0)
1917                         {
1918                                 PyObject *obj = PyTuple_GET_ITEM(arg, 3);
1919                                 if (PyString_Check(obj))
1920                                 {
1921                                         refstr = PyString_AS_STRING(obj);
1922                                         eServiceReferenceDVB ref(refstr);
1923                                         if (ref.valid())
1924                                         {
1925                                                 eventid = PyLong_AsLong(PyTuple_GET_ITEM(arg, 4));
1926                                                 singleLock s(cache_lock);
1927                                                 const eventData *evData = 0;
1928                                                 lookupEventId(ref, eventid, evData);
1929                                                 if (evData)
1930                                                 {
1931                                                         __u8 *data = evData->EITdata;
1932                                                         int tmp = evData->ByteSize-12;
1933                                                         __u32 *p = (__u32*)(data+12);
1934                                                                 // search short and extended event descriptors
1935                                                         while(tmp>0)
1936                                                         {
1937                                                                 __u32 crc = *p++;
1938                                                                 descriptorMap::iterator it =
1939                                                                         eventData::descriptors.find(crc);
1940                                                                 if (it != eventData::descriptors.end())
1941                                                                 {
1942                                                                         __u8 *descr_data = it->second.second;
1943                                                                         switch(descr_data[0])
1944                                                                         {
1945                                                                         case 0x4D ... 0x4E:
1946                                                                                 descr[++descridx]=crc;
1947                                                                         default:
1948                                                                                 break;
1949                                                                         }
1950                                                                 }
1951                                                                 tmp-=4;
1952                                                         }
1953                                                 }
1954                                                 if (descridx<0)
1955                                                         eDebug("event not found");
1956                                         }
1957                                         else
1958                                         {
1959                                                 PyErr_SetString(PyExc_StandardError,
1960                                                         "type error");
1961                                                 eDebug("tuple arg 4 is not a valid service reference string");
1962                                                 return NULL;
1963                                         }
1964                                 }
1965                                 else
1966                                 {
1967                                         PyErr_SetString(PyExc_StandardError,
1968                                         "type error");
1969                                         eDebug("tuple arg 4 is not a string");
1970                                         return NULL;
1971                                 }
1972                         }
1973                         else if (tuplesize > 4 && (querytype == 1 || querytype == 2) )
1974                         {
1975                                 PyObject *obj = PyTuple_GET_ITEM(arg, 3);
1976                                 if (PyString_Check(obj))
1977                                 {
1978                                         int casetype = PyLong_AsLong(PyTuple_GET_ITEM(arg, 4));
1979                                         const char *str = PyString_AS_STRING(obj);
1980                                         int textlen = PyString_GET_SIZE(obj);
1981                                         if (querytype == 1)
1982                                                 eDebug("lookup for events with '%s' as title(%s)", str, casetype?"ignore case":"case sensitive");
1983                                         else
1984                                                 eDebug("lookup for events with '%s' in title(%s)", str, casetype?"ignore case":"case sensitive");
1985                                         singleLock s(cache_lock);
1986                                         for (descriptorMap::iterator it(eventData::descriptors.begin());
1987                                                 it != eventData::descriptors.end() && descridx < 511; ++it)
1988                                         {
1989                                                 __u8 *data = it->second.second;
1990                                                 if ( data[0] == 0x4D ) // short event descriptor
1991                                                 {
1992                                                         int title_len = data[5];
1993                                                         if ( querytype == 1 )
1994                                                         {
1995                                                                 if (title_len > textlen)
1996                                                                         continue;
1997                                                                 else if (title_len < textlen)
1998                                                                         continue;
1999                                                                 if ( casetype )
2000                                                                 {
2001                                                                         if ( !strncasecmp((const char*)data+6, str, title_len) )
2002                                                                         {
2003 //                                                                              std::string s((const char*)data+6, title_len);
2004 //                                                                              eDebug("match1 %s %s", str, s.c_str() );
2005                                                                                 descr[++descridx] = it->first;
2006                                                                         }
2007                                                                 }
2008                                                                 else if ( !strncmp((const char*)data+6, str, title_len) )
2009                                                                 {
2010 //                                                                      std::string s((const char*)data+6, title_len);
2011 //                                                                      eDebug("match2 %s %s", str, s.c_str() );
2012                                                                         descr[++descridx] = it->first;
2013                                                                 }
2014                                                         }
2015                                                         else
2016                                                         {
2017                                                                 int idx=0;
2018                                                                 while((title_len-idx) >= textlen)
2019                                                                 {
2020                                                                         if (casetype)
2021                                                                         {
2022                                                                                 if (!strncasecmp((const char*)data+6+idx, str, textlen) )
2023                                                                                 {
2024                                                                                         descr[++descridx] = it->first;
2025 //                                                                                      std::string s((const char*)data+6, title_len);
2026 //                                                                                      eDebug("match 3 %s %s", str, s.c_str() );
2027                                                                                         break;
2028                                                                                 }
2029                                                                                 else if (!strncmp((const char*)data+6+idx, str, textlen) )
2030                                                                                 {
2031                                                                                         descr[++descridx] = it->first;
2032 //                                                                                      std::string s((const char*)data+6, title_len);
2033 //                                                                                      eDebug("match 4 %s %s", str, s.c_str() );
2034                                                                                         break;
2035                                                                                 }
2036                                                                         }
2037                                                                         ++idx;
2038                                                                 }
2039                                                         }
2040                                                 }
2041                                         }
2042                                 }
2043                                 else
2044                                 {
2045                                         PyErr_SetString(PyExc_StandardError,
2046                                                 "type error");
2047                                         eDebug("tuple arg 4 is not a string");
2048                                         return NULL;
2049                                 }
2050                         }
2051                         else
2052                         {
2053                                 PyErr_SetString(PyExc_StandardError,
2054                                         "type error");
2055                                 eDebug("tuple arg 3(%d) is not a known querytype(0, 1, 2)", querytype);
2056                                 return NULL;
2057                         }
2058                 }
2059                 else
2060                 {
2061                         PyErr_SetString(PyExc_StandardError,
2062                                 "type error");
2063                         eDebug("not enough args in tuple");
2064                         return NULL;
2065                 }
2066         }
2067         else
2068         {
2069                 PyErr_SetString(PyExc_StandardError,
2070                         "type error");
2071                 eDebug("arg 0 is not a tuple");
2072                 return NULL;
2073         }
2074
2075         if (descridx > -1)
2076         {
2077                 int maxcount=maxmatches;
2078                 eServiceReferenceDVB ref(refstr?refstr:"");
2079                 // ref is only valid in SIMILAR_BROADCASTING_SEARCH
2080                 // in this case we start searching with the base service
2081                 bool first = ref.valid() ? true : false;
2082                 singleLock s(cache_lock);
2083                 eventCache::iterator cit(ref.valid() ? eventDB.find(ref) : eventDB.begin());
2084                 while(cit != eventDB.end() && maxcount)
2085                 {
2086                         if ( ref.valid() && !first && cit->first == ref )
2087                         {
2088                                 // do not scan base service twice ( only in SIMILAR BROADCASTING SEARCH )
2089                                 ++cit;
2090                                 continue;
2091                         }
2092                         PyObject *service_name=0;
2093                         PyObject *service_reference=0;
2094                         timeMap &evmap = cit->second.second;
2095                         // check all events
2096                         for (timeMap::iterator evit(evmap.begin()); evit != evmap.end() && maxcount; ++evit)
2097                         {
2098                                 if (evit->second->getEventID() == eventid)
2099                                         continue;
2100                                 __u8 *data = evit->second->EITdata;
2101                                 int tmp = evit->second->ByteSize-12;
2102                                 __u32 *p = (__u32*)(data+12);
2103                                 // check if any of our descriptor used by this event
2104                                 int cnt=-1;
2105                                 while(tmp>0)
2106                                 {
2107                                         __u32 crc32 = *p++;
2108                                         for ( int i=0; i <= descridx; ++i)
2109                                         {
2110                                                 if (descr[i] == crc32)  // found...
2111                                                         ++cnt;
2112                                         }
2113                                         tmp-=4;
2114                                 }
2115                                 if ( (querytype == 0 && cnt == descridx) ||
2116                                          ((querytype == 1 || querytype == 2) && cnt != -1) )
2117                                 {
2118                                         const uniqueEPGKey &service = cit->first;
2119                                         eServiceReference ref =
2120                                                 eDVBDB::getInstance()->searchReference(service.tsid, service.onid, service.sid);
2121                                         if (ref.valid())
2122                                         {
2123                                         // create servive event
2124                                                 ePtr<eServiceEvent> ptr;
2125                                                 if (needServiceEvent)
2126                                                 {
2127                                                         lookupEventId(ref, evit->first, ptr);
2128                                                         if (!ptr)
2129                                                                 eDebug("event not found !!!!!!!!!!!");
2130                                                 }
2131                                         // create service name
2132                                                 if (!service_name && strchr(argstring,'N'))
2133                                                 {
2134                                                         ePtr<iStaticServiceInformation> sptr;
2135                                                         eServiceCenterPtr service_center;
2136                                                         eServiceCenter::getPrivInstance(service_center);
2137                                                         if (service_center)
2138                                                         {
2139                                                                 service_center->info(ref, sptr);
2140                                                                 if (sptr)
2141                                                                 {
2142                                                                         std::string name;
2143                                                                         sptr->getName(ref, name);
2144                                                                         if (name.length())
2145                                                                                 service_name = PyString_FromString(name.c_str());
2146                                                                 }
2147                                                         }
2148                                                         if (!service_name)
2149                                                                 service_name = PyString_FromString("<n/a>");
2150                                                 }
2151                                         // create servicereference string
2152                                                 if (!service_reference && strchr(argstring,'R'))
2153                                                         service_reference = PyString_FromString(ref.toString().c_str());
2154                                         // create list
2155                                                 if (!ret)
2156                                                         ret = PyList_New(0);
2157                                         // create tuple
2158                                                 PyObject *tuple = PyTuple_New(argcount);
2159                                         // fill tuple
2160                                                 fillTuple2(tuple, argstring, argcount, evit->second, ptr, service_name, service_reference);
2161                                                 PyList_Append(ret, tuple);
2162                                                 Py_DECREF(tuple);
2163                                                 --maxcount;
2164                                         }
2165                                 }
2166                         }
2167                         if (service_name)
2168                                 Py_DECREF(service_name);
2169                         if (service_reference)
2170                                 Py_DECREF(service_reference);
2171                         if (first)
2172                         {
2173                                 // now start at first service in epgcache database ( only in SIMILAR BROADCASTING SEARCH )
2174                                 first=false;
2175                                 cit=eventDB.begin();
2176                         }
2177                         else
2178                                 ++cit;
2179                 }
2180         }
2181
2182         if (!ret)
2183         {
2184                 Py_INCREF(Py_None);
2185                 ret=Py_None;
2186         }
2187
2188         return ret;
2189 }
2190
2191 #ifdef ENABLE_PRIVATE_EPG
2192 #include <dvbsi++/descriptor_tag.h>
2193 #include <dvbsi++/unknown_descriptor.h>
2194 #include <dvbsi++/private_data_specifier_descriptor.h>
2195
2196 void eEPGCache::PMTready(eDVBServicePMTHandler *pmthandler)
2197 {
2198         ePtr<eTable<ProgramMapSection> > ptr;
2199         if (!pmthandler->getPMT(ptr) && ptr)
2200         {
2201                 std::vector<ProgramMapSection*>::const_iterator i;
2202                 for (i = ptr->getSections().begin(); i != ptr->getSections().end(); ++i)
2203                 {
2204                         const ProgramMapSection &pmt = **i;
2205
2206                         ElementaryStreamInfoConstIterator es;
2207                         for (es = pmt.getEsInfo()->begin(); es != pmt.getEsInfo()->end(); ++es)
2208                         {
2209                                 int tmp=0;
2210                                 switch ((*es)->getType())
2211                                 {
2212                                 case 0x05: // private
2213                                         for (DescriptorConstIterator desc = (*es)->getDescriptors()->begin();
2214                                                 desc != (*es)->getDescriptors()->end(); ++desc)
2215                                         {
2216                                                 switch ((*desc)->getTag())
2217                                                 {
2218                                                         case PRIVATE_DATA_SPECIFIER_DESCRIPTOR:
2219                                                                 if (((PrivateDataSpecifierDescriptor*)(*desc))->getPrivateDataSpecifier() == 190)
2220                                                                         tmp |= 1;
2221                                                                 break;
2222                                                         case 0x90:
2223                                                         {
2224                                                                 UnknownDescriptor *descr = (UnknownDescriptor*)*desc;
2225                                                                 int descr_len = descr->getLength();
2226                                                                 if (descr_len == 4)
2227                                                                 {
2228                                                                         uint8_t data[descr_len+2];
2229                                                                         descr->writeToBuffer(data);
2230                                                                         if ( !data[2] && !data[3] && data[4] == 0xFF && data[5] == 0xFF )
2231                                                                                 tmp |= 2;
2232                                                                 }
2233                                                                 break;
2234                                                         }
2235                                                         default:
2236                                                                 break;
2237                                                 }
2238                                         }
2239                                 default:
2240                                         break;
2241                                 }
2242                                 if (tmp==3)
2243                                 {
2244                                         eServiceReferenceDVB ref;
2245                                         if (!pmthandler->getServiceReference(ref))
2246                                         {
2247                                                 int pid = (*es)->getPid();
2248                                                 messages.send(Message(Message::got_private_pid, ref, pid));
2249                                                 return;
2250                                         }
2251                                 }
2252                         }
2253                 }
2254         }
2255         else
2256                 eDebug("PMTready but no pmt!!");
2257 }
2258
2259 struct date_time
2260 {
2261         __u8 data[5];
2262         time_t tm;
2263         date_time( const date_time &a )
2264         {
2265                 memcpy(data, a.data, 5);
2266                 tm = a.tm;
2267         }
2268         date_time( const __u8 data[5])
2269         {
2270                 memcpy(this->data, data, 5);
2271                 tm = parseDVBtime(data[0], data[1], data[2], data[3], data[4]);
2272         }
2273         date_time()
2274         {
2275         }
2276         const __u8& operator[](int pos) const
2277         {
2278                 return data[pos];
2279         }
2280 };
2281
2282 struct less_datetime
2283 {
2284         bool operator()( const date_time &a, const date_time &b ) const
2285         {
2286                 return abs(a.tm-b.tm) < 360 ? false : a.tm < b.tm;
2287         }
2288 };
2289
2290 void eEPGCache::privateSectionRead(const uniqueEPGKey &current_service, const __u8 *data)
2291 {
2292         contentMap &content_time_table = content_time_tables[current_service];
2293         singleLock s(cache_lock);
2294         std::map< date_time, std::list<uniqueEPGKey>, less_datetime > start_times;
2295         eventMap &evMap = eventDB[current_service].first;
2296         timeMap &tmMap = eventDB[current_service].second;
2297         int ptr=8;
2298         int content_id = data[ptr++] << 24;
2299         content_id |= data[ptr++] << 16;
2300         content_id |= data[ptr++] << 8;
2301         content_id |= data[ptr++];
2302
2303         contentTimeMap &time_event_map =
2304                 content_time_table[content_id];
2305         for ( contentTimeMap::iterator it( time_event_map.begin() );
2306                 it != time_event_map.end(); ++it )
2307         {
2308                 eventMap::iterator evIt( evMap.find(it->second.second) );
2309                 if ( evIt != evMap.end() )
2310                 {
2311                         delete evIt->second;
2312                         evMap.erase(evIt);
2313                 }
2314                 tmMap.erase(it->second.first);
2315         }
2316         time_event_map.clear();
2317
2318         __u8 duration[3];
2319         memcpy(duration, data+ptr, 3);
2320         ptr+=3;
2321         int duration_sec =
2322                 fromBCD(duration[0])*3600+fromBCD(duration[1])*60+fromBCD(duration[2]);
2323
2324         const __u8 *descriptors[65];
2325         const __u8 **pdescr = descriptors;
2326
2327         int descriptors_length = (data[ptr++]&0x0F) << 8;
2328         descriptors_length |= data[ptr++];
2329         while ( descriptors_length > 0 )
2330         {
2331                 int descr_type = data[ptr];
2332                 int descr_len = data[ptr+1];
2333                 descriptors_length -= (descr_len+2);
2334                 if ( descr_type == 0xf2 )
2335                 {
2336                         ptr+=2;
2337                         int tsid = data[ptr++] << 8;
2338                         tsid |= data[ptr++];
2339                         int onid = data[ptr++] << 8;
2340                         onid |= data[ptr++];
2341                         int sid = data[ptr++] << 8;
2342                         sid |= data[ptr++];
2343
2344 // WORKAROUND for wrong transmitted epg data
2345                         if ( onid == 0x85 && tsid == 0x11 && sid == 0xd3 )  // premiere sends wrong tsid here
2346                                 tsid = 0x1;
2347                         else if ( onid == 0x85 && tsid == 0x3 && sid == 0xf5 ) // premiere sends wrong sid here
2348                                 sid = 0xdc;
2349 ////////////////////////////////////////////
2350                                 
2351                         uniqueEPGKey service( sid, onid, tsid );
2352                         descr_len -= 6;
2353                         while( descr_len > 0 )
2354                         {
2355                                 __u8 datetime[5];
2356                                 datetime[0] = data[ptr++];
2357                                 datetime[1] = data[ptr++];
2358                                 int tmp_len = data[ptr++];
2359                                 descr_len -= 3;
2360                                 while( tmp_len > 0 )
2361                                 {
2362                                         memcpy(datetime+2, data+ptr, 3);
2363                                         ptr+=3;
2364                                         descr_len -= 3;
2365                                         tmp_len -= 3;
2366                                         start_times[datetime].push_back(service);
2367                                 }
2368                         }
2369                 }
2370                 else
2371                 {
2372                         *pdescr++=data+ptr;
2373                         ptr += 2;
2374                         ptr += descr_len;
2375                 }
2376         }
2377         __u8 event[4098];
2378         eit_event_struct *ev_struct = (eit_event_struct*) event;
2379         ev_struct->running_status = 0;
2380         ev_struct->free_CA_mode = 1;
2381         memcpy(event+7, duration, 3);
2382         ptr = 12;
2383         const __u8 **d=descriptors;
2384         while ( d < pdescr )
2385         {
2386                 memcpy(event+ptr, *d, ((*d)[1])+2);
2387                 ptr+=(*d++)[1];
2388                 ptr+=2;
2389         }
2390         for ( std::map< date_time, std::list<uniqueEPGKey> >::iterator it(start_times.begin()); it != start_times.end(); ++it )
2391         {
2392                 time_t now = eDVBLocalTimeHandler::getInstance()->nowTime();
2393                 if ( (it->first.tm + duration_sec) < now )
2394                         continue;
2395                 memcpy(event+2, it->first.data, 5);
2396                 int bptr = ptr;
2397                 int cnt=0;
2398                 for (std::list<uniqueEPGKey>::iterator i(it->second.begin()); i != it->second.end(); ++i)
2399                 {
2400                         event[bptr++] = 0x4A;
2401                         __u8 *len = event+(bptr++);
2402                         event[bptr++] = (i->tsid & 0xFF00) >> 8;
2403                         event[bptr++] = (i->tsid & 0xFF);
2404                         event[bptr++] = (i->onid & 0xFF00) >> 8;
2405                         event[bptr++] = (i->onid & 0xFF);
2406                         event[bptr++] = (i->sid & 0xFF00) >> 8;
2407                         event[bptr++] = (i->sid & 0xFF);
2408                         event[bptr++] = 0xB0;
2409                         bptr += sprintf((char*)(event+bptr), "Option %d", ++cnt);
2410                         *len = ((event+bptr) - len)-1;
2411                 }
2412                 int llen = bptr - 12;
2413                 ev_struct->descriptors_loop_length_hi = (llen & 0xF00) >> 8;
2414                 ev_struct->descriptors_loop_length_lo = (llen & 0xFF);
2415
2416                 time_t stime = it->first.tm;
2417                 while( tmMap.find(stime) != tmMap.end() )
2418                         ++stime;
2419                 event[6] += (stime - it->first.tm);
2420                 __u16 event_id = 0;
2421                 while( evMap.find(event_id) != evMap.end() )
2422                         ++event_id;
2423                 event[0] = (event_id & 0xFF00) >> 8;
2424                 event[1] = (event_id & 0xFF);
2425                 time_event_map[it->first.tm]=std::pair<time_t, __u16>(stime, event_id);
2426                 eventData *d = new eventData( ev_struct, bptr, PRIVATE );
2427                 evMap[event_id] = d;
2428                 tmMap[stime] = d;
2429         }
2430 }
2431
2432 void eEPGCache::channel_data::startPrivateReader()
2433 {
2434         eDVBSectionFilterMask mask;
2435         memset(&mask, 0, sizeof(mask));
2436         mask.pid = m_PrivatePid;
2437         mask.flags = eDVBSectionFilterMask::rfCRC;
2438         mask.data[0] = 0xA0;
2439         mask.mask[0] = 0xFF;
2440         eDebug("start privatefilter for pid %04x and version %d", m_PrivatePid, m_PrevVersion);
2441         if (m_PrevVersion != -1)
2442         {
2443                 mask.data[3] = m_PrevVersion << 1;
2444                 mask.mask[3] = 0x3E;
2445                 mask.mode[3] = 0x3E;
2446         }
2447         seenPrivateSections.clear();
2448         if (!m_PrivateConn)
2449                 m_PrivateReader->connectRead(slot(*this, &eEPGCache::channel_data::readPrivateData), m_PrivateConn);
2450         m_PrivateReader->start(mask);
2451 }
2452
2453 void eEPGCache::channel_data::readPrivateData( const __u8 *data)
2454 {
2455         if (!data)
2456                 eDebug("get Null pointer from section reader !!");
2457         else
2458         {
2459                 if ( seenPrivateSections.find( data[6] ) == seenPrivateSections.end() )
2460                 {
2461                         cache->privateSectionRead(m_PrivateService, data);
2462                         seenPrivateSections.insert(data[6]);
2463                 }
2464                 if ( seenPrivateSections.size() == (unsigned int)(data[7] + 1) )
2465                 {
2466                         eDebug("[EPGC] private finished");
2467                         m_PrevVersion = (data[5] & 0x3E) >> 1;
2468                         startPrivateReader();
2469                 }
2470         }
2471 }
2472
2473 #endif // ENABLE_PRIVATE_EPG
2474
2475 #ifdef ENABLE_MHW_EPG
2476 void eEPGCache::channel_data::cleanup()
2477 {
2478         m_channels.clear();
2479         m_themes.clear();
2480         m_titles.clear();
2481         m_program_ids.clear();
2482 }
2483
2484 __u8 *eEPGCache::channel_data::delimitName( __u8 *in, __u8 *out, int len_in )
2485 {
2486         // Names in mhw structs are not strings as they are not '\0' terminated.
2487         // This function converts the mhw name into a string.
2488         // Constraint: "length of out" = "length of in" + 1.
2489         int i;
2490         for ( i=0; i < len_in; i++ )
2491                 out[i] = in[i];
2492
2493         i = len_in - 1;
2494         while ( ( i >=0 ) && ( out[i] == 0x20 ) )
2495                 i--;
2496
2497         out[i+1] = 0;
2498         return out;
2499 }
2500
2501 void eEPGCache::channel_data::timeMHW2DVB( u_char hours, u_char minutes, u_char *return_time)
2502 // For time of day
2503 {
2504         return_time[0] = toBCD( hours );
2505         return_time[1] = toBCD( minutes );
2506         return_time[2] = 0;
2507 }
2508
2509 void eEPGCache::channel_data::timeMHW2DVB( int minutes, u_char *return_time)
2510 {
2511         timeMHW2DVB( int(minutes/60), minutes%60, return_time );
2512 }
2513
2514 void eEPGCache::channel_data::timeMHW2DVB( u_char day, u_char hours, u_char minutes, u_char *return_time)
2515 // For date plus time of day
2516 {
2517         // Remove offset in mhw time.
2518         __u8 local_hours = hours;
2519         if ( hours >= 16 )
2520                 local_hours -= 4;
2521         else if ( hours >= 8 )
2522                 local_hours -= 2;
2523
2524         // As far as we know all mhw time data is sent in central Europe time zone.
2525         // So, temporarily set timezone to western europe
2526         time_t dt = eDVBLocalTimeHandler::getInstance()->nowTime();
2527
2528         char *old_tz = getenv( "TZ" );
2529         putenv("TZ=CET-1CEST,M3.5.0/2,M10.5.0/3");
2530         tzset();
2531
2532         tm *localnow = localtime( &dt );
2533
2534         if (day == 7)
2535                 day = 0;
2536         if ( day + 1 < localnow->tm_wday )              // day + 1 to prevent old events to show for next week.
2537                 day += 7;
2538         if (local_hours <= 5)
2539                 day++;
2540
2541         dt += 3600*24*(day - localnow->tm_wday);        // Shift dt to the recording date (local time zone).
2542         dt += 3600*(local_hours - localnow->tm_hour);  // Shift dt to the recording hour.
2543
2544         tm *recdate = gmtime( &dt );   // This will also take care of DST.
2545
2546         if ( old_tz == NULL )
2547                 unsetenv( "TZ" );
2548         else
2549                 putenv( old_tz );
2550         tzset();
2551
2552         // Calculate MJD according to annex in ETSI EN 300 468
2553         int l=0;
2554         if ( recdate->tm_mon <= 1 )     // Jan or Feb
2555                 l=1;
2556         int mjd = 14956 + recdate->tm_mday + int( (recdate->tm_year - l) * 365.25) +
2557                 int( (recdate->tm_mon + 2 + l * 12) * 30.6001);
2558
2559         return_time[0] = (mjd & 0xFF00)>>8;
2560         return_time[1] = mjd & 0xFF;
2561
2562         timeMHW2DVB( recdate->tm_hour, minutes, return_time+2 );
2563 }
2564
2565 void eEPGCache::channel_data::storeTitle(std::map<__u32, mhw_title_t>::iterator itTitle, std::string sumText, const __u8 *data)
2566 // data is borrowed from calling proc to save memory space.
2567 {
2568         // For each title a separate EIT packet will be sent to eEPGCache::sectionRead()
2569         __u8 name[24];
2570
2571         eit_t *packet = (eit_t *) data;
2572         packet->table_id = 0x50;
2573         packet->section_syntax_indicator = 1;
2574         packet->service_id_hi = m_channels[ itTitle->second.channel_id - 1 ].channel_id_hi;
2575         packet->service_id_lo = m_channels[ itTitle->second.channel_id - 1 ].channel_id_lo;
2576         packet->version_number = 0;     // eEPGCache::sectionRead() will dig this for the moment
2577         packet->current_next_indicator = 0;
2578         packet->section_number = 0;     // eEPGCache::sectionRead() will dig this for the moment
2579         packet->last_section_number = 0;        // eEPGCache::sectionRead() will dig this for the moment
2580         packet->transport_stream_id_hi = m_channels[ itTitle->second.channel_id - 1 ].transport_stream_id_hi;
2581         packet->transport_stream_id_lo = m_channels[ itTitle->second.channel_id - 1 ].transport_stream_id_lo;
2582         packet->original_network_id_hi = m_channels[ itTitle->second.channel_id - 1 ].network_id_hi;
2583         packet->original_network_id_lo = m_channels[ itTitle->second.channel_id - 1 ].network_id_lo;
2584         packet->segment_last_section_number = 0; // eEPGCache::sectionRead() will dig this for the moment
2585         packet->segment_last_table_id = 0x50;
2586
2587         std::string prog_title = (char *) delimitName( itTitle->second.title, name, 23 );
2588         int prog_title_length = prog_title.length();
2589
2590         int packet_length = EIT_SIZE + EIT_LOOP_SIZE + EIT_SHORT_EVENT_DESCRIPTOR_SIZE +
2591                 prog_title_length + 1;
2592
2593         eit_event_t *event_data = (eit_event_t *) (data + EIT_SIZE);
2594         event_data->event_id_hi = (( itTitle->first ) >> 8 ) & 0xFF;
2595         event_data->event_id_lo = ( itTitle->first ) & 0xFF;
2596
2597         timeMHW2DVB( itTitle->second.day, itTitle->second.hours, itTitle->second.minutes,
2598                 (u_char *) event_data + 2 );
2599         timeMHW2DVB( HILO(itTitle->second.duration), (u_char *) event_data+7 );
2600
2601         event_data->running_status = 0;
2602         event_data->free_CA_mode = 0;
2603         int descr_ll = EIT_SHORT_EVENT_DESCRIPTOR_SIZE + 1 + prog_title_length;
2604
2605         eit_short_event_descriptor_struct *short_event_descriptor =
2606                 (eit_short_event_descriptor_struct *) ( (u_char *) event_data + EIT_LOOP_SIZE);
2607         short_event_descriptor->descriptor_tag = EIT_SHORT_EVENT_DESCRIPTOR;
2608         short_event_descriptor->descriptor_length = EIT_SHORT_EVENT_DESCRIPTOR_SIZE +
2609                 prog_title_length - 1;
2610         short_event_descriptor->language_code_1 = 'e';
2611         short_event_descriptor->language_code_2 = 'n';
2612         short_event_descriptor->language_code_3 = 'g';
2613         short_event_descriptor->event_name_length = prog_title_length;
2614         delimitName( itTitle->second.title, name, 23 );
2615         u_char *event_name = (u_char *) short_event_descriptor + EIT_SHORT_EVENT_DESCRIPTOR_SIZE;
2616         memcpy(event_name, name, prog_title_length);
2617
2618         // Set text length
2619         event_name[prog_title_length] = 0;
2620
2621         if ( sumText.length() > 0 )
2622         // There is summary info
2623         {
2624                 unsigned int sum_length = sumText.length();
2625                 if ( sum_length + short_event_descriptor->descriptor_length <= 0xff )
2626                 // Store summary in short event descriptor
2627                 {
2628                         // Increase all relevant lengths
2629                         event_name[prog_title_length] = sum_length;
2630                         short_event_descriptor->descriptor_length += sum_length;
2631                         packet_length += sum_length;
2632                         descr_ll += sum_length;
2633                         sumText.copy( (char *) event_name+prog_title_length+1, sum_length );
2634                 }
2635                 else
2636                 // Store summary in extended event descriptors
2637                 {
2638                         int remaining_sum_length = sumText.length();
2639                         int nbr_descr = int(remaining_sum_length/247) + 1;
2640                         for ( int i=0; i < nbr_descr; i++)
2641                         // Loop once per extended event descriptor
2642                         {
2643                                 eit_extended_descriptor_struct *ext_event_descriptor = (eit_extended_descriptor_struct *) (data + packet_length);
2644                                 sum_length = remaining_sum_length > 247 ? 247 : remaining_sum_length;
2645                                 remaining_sum_length -= sum_length;
2646                                 packet_length += 8 + sum_length;
2647                                 descr_ll += 8 + sum_length;
2648
2649                                 ext_event_descriptor->descriptor_tag = EIT_EXTENDED_EVENT_DESCRIPOR;
2650                                 ext_event_descriptor->descriptor_length = sum_length + 6;
2651                                 ext_event_descriptor->descriptor_number = i;
2652                                 ext_event_descriptor->last_descriptor_number = nbr_descr - 1;
2653                                 ext_event_descriptor->iso_639_2_language_code_1 = 'e';
2654                                 ext_event_descriptor->iso_639_2_language_code_2 = 'n';
2655                                 ext_event_descriptor->iso_639_2_language_code_3 = 'g';
2656                                 u_char *the_text = (u_char *) ext_event_descriptor + 8;
2657                                 the_text[-2] = 0;
2658                                 the_text[-1] = sum_length;
2659                                 sumText.copy( (char *) the_text, sum_length, sumText.length() - sum_length - remaining_sum_length );
2660                         }
2661                 }
2662         }
2663         // Add content descriptor
2664         u_char *descriptor = (u_char *) data + packet_length;
2665         packet_length += 4;
2666         descr_ll += 4;
2667
2668         int content_id = 0;
2669         std::string content_descr = (char *) delimitName( m_themes[itTitle->second.theme_id].name, name, 15 );
2670         if ( content_descr.find( "FILM" ) != std::string::npos )
2671                 content_id = 0x10;
2672         else if ( content_descr.find( "SPORT" ) != std::string::npos )
2673                 content_id = 0x40;
2674
2675         descriptor[0] = 0x54;
2676         descriptor[1] = 2;
2677         descriptor[2] = content_id;
2678         descriptor[3] = 0;
2679
2680         event_data->descriptors_loop_length_hi = (descr_ll & 0xf00)>>8;
2681         event_data->descriptors_loop_length_lo = (descr_ll & 0xff);
2682
2683         packet->section_length_hi =  ((packet_length - 3)&0xf00)>>8;
2684         packet->section_length_lo =  (packet_length - 3)&0xff;
2685
2686         // Feed the data to eEPGCache::sectionRead()
2687         cache->sectionRead( data, MHW, this );
2688 }
2689
2690 void eEPGCache::channel_data::startTimeout(int msec)
2691 {
2692         m_MHWTimeoutTimer.start(msec,true);
2693         m_MHWTimeoutet=false;
2694 }
2695
2696 void eEPGCache::channel_data::startMHWReader(__u16 pid, __u8 tid)
2697 {
2698         m_MHWFilterMask.pid = pid;
2699         m_MHWFilterMask.data[0] = tid;
2700         m_MHWReader->start(m_MHWFilterMask);
2701 //      eDebug("start 0x%02x 0x%02x", pid, tid);
2702 }
2703
2704 void eEPGCache::channel_data::readMHWData(const __u8 *data)
2705 {
2706         if ( state > 1 || // aborted
2707                 // have si data.. so we dont read mhw data
2708                 (haveData & (SCHEDULE|SCHEDULE_OTHER)) ) 
2709         {
2710                 eDebug("[EPGC] mhw aborted %d", state);
2711         }
2712         else if (m_MHWFilterMask.pid == 0xD3 && m_MHWFilterMask.data[0] == 0x91)
2713         // Channels table
2714         {
2715                 int len = ((data[1]&0xf)<<8) + data[2] - 1;
2716                 int record_size = sizeof( mhw_channel_name_t );
2717                 int nbr_records = int (len/record_size);
2718
2719                 for ( int i = 0; i < nbr_records; i++ )
2720                 {
2721                         mhw_channel_name_t *channel = (mhw_channel_name_t*) &data[4 + i*record_size];
2722                         m_channels.push_back( *channel );
2723                 }
2724                 haveData |= MHW;
2725
2726                 eDebug("channels finished %d found", m_channels.size());
2727
2728                 // Channels table has been read, start reading the themes table.
2729                 startMHWReader(0xD3, 0x92);
2730                 return;
2731         }
2732         else if (m_MHWFilterMask.pid == 0xD3 && m_MHWFilterMask.data[0] == 0x92)
2733         // Themes table
2734         {
2735                 int len = ((data[1]&0xf)<<8) + data[2] - 16;
2736                 int record_size = sizeof( mhw_theme_name_t );
2737                 int nbr_records = int (len/record_size);
2738                 int idx_ptr = 0;
2739                 __u8 next_idx = (__u8) *(data + 3 + idx_ptr);
2740                 __u8 idx = 0;
2741                 __u8 sub_idx = 0;
2742                 for ( int i = 0; i < nbr_records; i++ )
2743                 {
2744                         mhw_theme_name_t *theme = (mhw_theme_name_t*) &data[19 + i*record_size];
2745                         if ( i >= next_idx )
2746                         {
2747                                 idx = (idx_ptr<<4);
2748                                 idx_ptr++;
2749                                 next_idx = (__u8) *(data + 3 + idx_ptr);
2750                                 sub_idx = 0;
2751                         }
2752                         else
2753                                 sub_idx++;
2754
2755                         m_themes[idx+sub_idx] = *theme;
2756                 }
2757                 eDebug("themes finished %d found", m_themes.size());
2758                 // Themes table has been read, start reading the titles table.
2759                 startMHWReader(0xD2, 0x90);
2760                 startTimeout(4000);
2761                 return;
2762         }
2763         else if (m_MHWFilterMask.pid == 0xD2 && m_MHWFilterMask.data[0] == 0x90)
2764         // Titles table
2765         {
2766                 mhw_title_t *title = (mhw_title_t*) data;
2767
2768                 if ( title->channel_id == 0xFF )        // Separator
2769                         return; // Continue reading of the current table.
2770                 else
2771                 {
2772                         // Create unique key per title
2773                         __u32 title_id = ((title->channel_id)<<16)|((title->day)<<13)|((title->hours)<<8)|
2774                                 (title->minutes);
2775                         __u32 program_id = ((title->program_id_hi)<<24)|((title->program_id_mh)<<16)|
2776                                 ((title->program_id_ml)<<8)|(title->program_id_lo);
2777
2778                         if ( m_titles.find( title_id ) == m_titles.end() )
2779                         {
2780                                 startTimeout(4000);
2781                                 m_titles[ title_id ] = *title;
2782                                 if ( (title->summary_available) && (m_program_ids.find(program_id) == m_program_ids.end()) )
2783                                         // program_ids will be used to gather summaries.
2784                                         m_program_ids[ program_id ] = title_id;
2785                                 return; // Continue reading of the current table.
2786                         }
2787                         else if (!checkTimeout())
2788                                 return;
2789                 }
2790                 if ( !m_program_ids.empty())
2791                 {
2792                         // Titles table has been read, there are summaries to read.
2793                         // Start reading summaries, store corresponding titles on the fly.
2794                         startMHWReader(0xD3, 0x90);
2795                         eDebug("titles finished %d titles, %d with summary",
2796                                 m_titles.size(),
2797                                 m_program_ids.size());
2798                         startTimeout(4000);
2799                         return;
2800                 }
2801         }
2802         else if (m_MHWFilterMask.pid == 0xD3 && m_MHWFilterMask.data[0] == 0x90)
2803         // Summaries table
2804         {
2805                 mhw_summary_t *summary = (mhw_summary_t*) data;
2806
2807                 // Create unique key per record
2808                 __u32 program_id = ((summary->program_id_hi)<<24)|((summary->program_id_mh)<<16)|
2809                         ((summary->program_id_ml)<<8)|(summary->program_id_lo);
2810                 int len = ((data[1]&0xf)<<8) + data[2];
2811
2812                 // ugly workaround to convert const __u8* to char*
2813                 char *tmp=0;
2814                 memcpy(&tmp, &data, sizeof(void*));
2815                 tmp[len+3] = 0; // Terminate as a string.
2816
2817                 std::map<__u32, __u32>::iterator itProgid( m_program_ids.find( program_id ) );
2818                 if ( itProgid == m_program_ids.end() )
2819                 { /*    This part is to prevent to looping forever if some summaries are not received yet.
2820                         There is a timeout of 4 sec. after the last successfully read summary. */
2821                         if (!m_program_ids.empty() && !checkTimeout())
2822                                 return; // Continue reading of the current table.
2823                 }
2824                 else
2825                 {
2826                         std::string the_text = (char *) (data + 11 + summary->nb_replays * 7);
2827
2828                         unsigned int pos=0;
2829                         while((pos = the_text.find("\r\n")) != std::string::npos)
2830                                 the_text.replace(pos, 2, " ");
2831
2832                         // Find corresponding title, store title and summary in epgcache.
2833                         std::map<__u32, mhw_title_t>::iterator itTitle( m_titles.find( itProgid->second ) );
2834                         if ( itTitle != m_titles.end() )
2835                         {
2836                                 startTimeout(4000);
2837                                 storeTitle( itTitle, the_text, data );
2838                                 m_titles.erase( itTitle );
2839                         }
2840                         m_program_ids.erase( itProgid );
2841                         if ( !m_program_ids.empty() )
2842                                 return; // Continue reading of the current table.
2843                 }
2844         }
2845         // Summaries have been read, titles that have summaries have been stored.
2846         // Now store titles that do not have summaries.
2847         for (std::map<__u32, mhw_title_t>::iterator itTitle(m_titles.begin()); itTitle != m_titles.end(); itTitle++)
2848                 storeTitle( itTitle, "", data );
2849         eDebug("[EPGC] mhw finished(%ld) %d summaries left",
2850                 eDVBLocalTimeHandler::getInstance()->nowTime(),
2851                 m_program_ids.size());
2852         isRunning &= ~MHW;
2853         m_MHWConn=0;
2854         if ( m_MHWReader )
2855                 m_MHWReader->stop();
2856         if (haveData)
2857                 finishEPG();
2858 }
2859
2860 #endif