Update EPG Cache(thanks to open source community)
[vuplus_dvbapp] / lib / dvb / epgcache.cpp
1 #include <lib/dvb/epgcache.h>
2 #include <lib/dvb/dvb.h>
3 #include <lib/dvb/lowlevel/eit.h>
4
5 #undef EPG_DEBUG
6
7 #ifdef EPG_DEBUG
8 #include <lib/service/event.h>
9 #endif
10
11 #include <deque>
12 #include <string>
13 #include <time.h>
14 #include <unistd.h>  // for usleep
15 #include <sys/vfs.h> // for statfs
16 #include <lib/base/eerror.h>
17 #include <lib/base/encoding.h>
18 #include <lib/base/estring.h>
19 #include <lib/dvb/pmt.h>
20 #include <lib/dvb/db.h>
21 #include <lib/python/python.h>
22 #include <dvbsi++/descriptor_tag.h>
23
24 /* Interval between "garbage collect" cycles */
25 #define CLEAN_INTERVAL 60000    //  1 min
26 /* Restart EPG data capture */
27 #define UPDATE_INTERVAL 3600000  // 60 min
28 /* Time to wait after tuning in before EPG data capturing starts */
29 #define ZAP_DELAY 2000          // 2 sec
30
31 struct DescriptorPair
32 {
33         int reference_count;
34         uint8_t* data;
35
36         DescriptorPair() {}
37         DescriptorPair(int c, uint8_t* d): reference_count(c), data(d) {}
38 };
39
40 typedef std::tr1::unordered_map<uint32_t, DescriptorPair> DescriptorMap;
41
42 struct eventData
43 {
44         uint8_t rawEITdata[10];
45         uint8_t n_crc;
46         uint8_t type;
47         uint32_t *crc_list;
48         static DescriptorMap descriptors;
49         static uint8_t data[];
50         static unsigned int CacheSize;
51         static bool isCacheCorrupt;
52         eventData(const eit_event_struct* e = NULL, int size = 0, int type = 0, int tsidonid = 0);
53         ~eventData();
54         static void load(FILE *);
55         static void save(FILE *);
56         static void cacheCorrupt(const char* context);
57         const eit_event_struct* get() const;
58         int getEventID() const
59         {
60                 return (rawEITdata[0] << 8) | rawEITdata[1];
61         }
62         time_t getStartTime() const
63         {
64                 return parseDVBtime(&rawEITdata[2]);
65         }
66         int getDuration() const
67         {
68                 return fromBCD(rawEITdata[7])*3600+fromBCD(rawEITdata[8])*60+fromBCD(rawEITdata[9]);
69         }
70 };
71
72 unsigned int eventData::CacheSize = 0;
73 bool eventData::isCacheCorrupt = 0;
74 DescriptorMap eventData::descriptors;
75 uint8_t eventData::data[2 * 4096 + 12];
76 extern const uint32_t crc32_table[256];
77
78 const eServiceReference &handleGroup(const eServiceReference &ref)
79 {
80         if (ref.flags & eServiceReference::isGroup)
81         {
82                 ePtr<eDVBResourceManager> res;
83                 if (!eDVBResourceManager::getInstance(res))
84                 {
85                         ePtr<iDVBChannelList> db;
86                         if (!res->getChannelList(db))
87                         {
88                                 eBouquet *bouquet = NULL;
89                                 if (!db->getBouquet(ref, bouquet))
90                                 {
91                                         std::list<eServiceReference>::iterator it(bouquet->m_services.begin());
92                                         if (it != bouquet->m_services.end())
93                                                 return *it;
94                                 }
95                         }
96                 }
97         }
98         return ref;
99 }
100
101 static uint32_t calculate_crc_hash(const uint8_t *data, int size)
102 {
103         uint32_t crc = 0;
104         for (int i = 0; i < size; ++i)
105                 crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ data[i]) & 0xFF];
106         return crc;
107 }
108
109 eventData::eventData(const eit_event_struct* e, int size, int _type, int tsidonid)
110         :n_crc(0), type(_type & 0xFF), crc_list(NULL)
111 {
112         if (!e)
113                 return; /* Used when loading from file */
114
115         uint32_t descr[65];
116         uint32_t *pdescr=descr;
117
118         uint8_t *data = (uint8_t*)e;
119         int ptr=12;
120         size -= 12;
121
122         while(size > 1)
123         {
124                 uint8_t *descr = data + ptr;
125                 int descr_len = descr[1];
126                 descr_len += 2;
127                 if (size >= descr_len)
128                 {
129                         switch (descr[0])
130                         {
131                                 case EXTENDED_EVENT_DESCRIPTOR:
132                                 case LINKAGE_DESCRIPTOR:
133                                 case COMPONENT_DESCRIPTOR:
134                                 case CONTENT_DESCRIPTOR:
135                                 case PARENTAL_RATING_DESCRIPTOR:
136                                 case PDC_DESCRIPTOR:
137                                 {
138                                         uint32_t crc = calculate_crc_hash(descr, descr_len);
139                                         DescriptorMap::iterator it = descriptors.find(crc);
140                                         if ( it == descriptors.end() )
141                                         {
142                                                 CacheSize+=descr_len;
143                                                 uint8_t *d = new uint8_t[descr_len];
144                                                 memcpy(d, descr, descr_len);
145                                                 descriptors[crc] = DescriptorPair(1, d);
146                                         }
147                                         else
148                                                 ++it->second.reference_count;
149                                         *pdescr++ = crc;
150                                         break;
151                                 }
152                                 case SHORT_EVENT_DESCRIPTOR:
153                                 {
154                                         //parse the data out from the short event descriptor
155                                         //get the country code, which will be used for converting to UTF8
156                                         std::string cc( (const char*)&descr[2], 3);
157                                         std::transform(cc.begin(), cc.end(), cc.begin(), tolower);
158                                         int table = encodingHandler.getCountryCodeDefaultMapping(cc);
159
160                                         int eventNameLen = descr[5];
161                                         int eventTextLen = descr[6 + eventNameLen];
162
163                                         //convert our strings to UTF8
164                                         std::string eventNameUTF8 = convertDVBUTF8((const unsigned char*)&descr[6], eventNameLen, table, tsidonid);
165                                         std::string textUTF8 = convertDVBUTF8((const unsigned char*)&descr[7 + eventNameLen], eventTextLen, table, tsidonid);
166                                         unsigned int eventNameUTF8len = eventNameUTF8.length();
167                                         unsigned int textUTF8len = textUTF8.length();
168
169                                         //Rebuild the short event descriptor with UTF-8 strings
170
171                                         //Save the title first
172                                         if( eventNameUTF8len > 0 ) //only store the data if there is something to store
173                                         {
174                                                 /*this will actually cause us to save some memory
175                                                  previously some descriptors didnt match because there text was different and titles the same.
176                                                  Now that we store them seperatly we can save some space on title data some rough calculation show anywhere from 20 - 40% savings
177                                                 */
178                                                 eventNameUTF8len = truncateUTF8(eventNameUTF8, 255 - 6);
179                                                 int title_len = 6 + eventNameUTF8len;
180                                                 uint8_t *title_data = new uint8_t[title_len + 2];
181                                                 title_data[0] = SHORT_EVENT_DESCRIPTOR;
182                                                 title_data[1] = title_len;
183                                                 title_data[2] = descr[2];
184                                                 title_data[3] = descr[3];
185                                                 title_data[4] = descr[4];
186                                                 title_data[5] = eventNameUTF8len + 1;
187                                                 title_data[6] = 0x15; //identify event name as UTF-8
188                                                 memcpy(&title_data[7], eventNameUTF8.data(), eventNameUTF8len);
189                                                 title_data[7 + eventNameUTF8len] = 0;
190
191                                                 //Calculate the CRC, based on our new data
192                                                 title_len += 2; //add 2 the length to include the 2 bytes in the header
193                                                 uint32_t title_crc = calculate_crc_hash(title_data, title_len);
194
195                                                 DescriptorMap::iterator it = descriptors.find(title_crc);
196                                                 if ( it == descriptors.end() )
197                                                 {
198                                                         CacheSize += title_len;
199                                                         descriptors[title_crc] = DescriptorPair(1, title_data);
200                                                 }
201                                                 else
202                                                 {
203                                                         ++it->second.reference_count;
204                                                         delete [] title_data;
205                                                 }
206                                                 *pdescr++ = title_crc;
207                                         }
208
209                                         //save the text
210                                         if( textUTF8len > 0 ) //only store the data if there is something to store
211                                         {
212                                                 textUTF8len = truncateUTF8(textUTF8, 255 - 6);
213                                                 int text_len = 6 + textUTF8len;
214                                                 uint8_t *text_data = new uint8_t[text_len + 2];
215                                                 text_data[0] = SHORT_EVENT_DESCRIPTOR;
216                                                 text_data[1] = text_len;
217                                                 text_data[2] = descr[2];
218                                                 text_data[3] = descr[3];
219                                                 text_data[4] = descr[4];
220                                                 text_data[5] = 0;
221                                                 text_data[6] = textUTF8len + 1; //identify text as UTF-8
222                                                 text_data[7] = 0x15; //identify text as UTF-8
223                                                 memcpy(&text_data[8], textUTF8.data(), textUTF8len);
224
225                                                 text_len += 2; //add 2 the length to include the 2 bytes in the header
226                                                 uint32_t text_crc = calculate_crc_hash(text_data, text_len);
227
228                                                 DescriptorMap::iterator it = descriptors.find(text_crc);
229                                                 if ( it == descriptors.end() )
230                                                 {
231                                                         CacheSize += text_len;
232                                                         descriptors[text_crc] = DescriptorPair(1, text_data);
233                                                 }
234                                                 else
235                                                 {
236                                                         ++it->second.reference_count;
237                                                         delete [] text_data;
238                                                 }
239                                                 *pdescr++ = text_crc;
240                                         }
241                                         break;
242                                 }
243                                 default: // do not cache all other descriptors
244                                         break;
245                         }
246                         ptr += descr_len;
247                         size -= descr_len;
248                 }
249                 else
250                         break;
251         }
252         memcpy(rawEITdata, (uint8_t*)e, 10);
253         ASSERT(pdescr <= &descr[65]);
254         n_crc = pdescr - descr;
255         if (n_crc)
256         {
257                 crc_list = new uint32_t[n_crc];
258                 memcpy(crc_list, descr, n_crc * sizeof(uint32_t));
259         }
260         CacheSize += sizeof(*this) + n_crc * sizeof(uint32_t);
261 }
262
263 const eit_event_struct* eventData::get() const
264 {
265         unsigned int pos = 12;
266         memcpy(data, rawEITdata, 10);
267         unsigned int descriptors_length = 0;
268         for (uint8_t i = 0; i < n_crc; ++i)
269         {
270                 DescriptorMap::iterator it = descriptors.find(crc_list[i]);
271                 if (it != descriptors.end())
272                 {
273                         unsigned int b = it->second.data[1] + 2;
274                         if (pos + b < sizeof(data))
275                         {
276                                 memcpy(data + pos, it->second.data, b);
277                                 pos += b;
278                                 descriptors_length += b;
279                         }
280                 }
281                 else
282                         cacheCorrupt("eventData::get");
283         }
284         data[10] = (descriptors_length >> 8) & 0x0F;
285         data[11] = descriptors_length & 0xFF;
286         return (eit_event_struct*)data;
287 }
288
289 eventData::~eventData()
290 {
291         for ( uint8_t i = 0; i < n_crc; ++i )
292         {
293                 DescriptorMap::iterator it = descriptors.find(crc_list[i]);
294                 if ( it != descriptors.end() )
295                 {
296                         DescriptorPair &p = it->second;
297                         if (!--p.reference_count) // no more used descriptor
298                         {
299                                 CacheSize -= it->second.data[1];
300                                 delete [] it->second.data;      // free descriptor memory
301                                 descriptors.erase(it);  // remove entry from descriptor map
302                         }
303                 }
304                 else
305                 {
306                         cacheCorrupt("eventData::~eventData");
307                 }
308         }
309         delete [] crc_list;
310         CacheSize -= sizeof(*this) + n_crc * sizeof(uint32_t);
311 }
312
313 void eventData::load(FILE *f)
314 {
315         int size = 0;
316         int id=0;
317         DescriptorPair p;
318         uint8_t header[2];
319         fread(&size, sizeof(int), 1, f);
320         descriptors.rehash(size);
321         while(size)
322         {
323                 fread(&id, sizeof(uint32_t), 1, f);
324                 fread(&p.reference_count, sizeof(int), 1, f);
325                 fread(header, 2, 1, f);
326                 int bytes = header[1]+2;
327                 p.data = new uint8_t[bytes];
328                 p.data[0] = header[0];
329                 p.data[1] = header[1];
330                 fread(p.data+2, bytes-2, 1, f);
331                 descriptors[id] = p;
332                 --size;
333         }
334 }
335
336 void eventData::save(FILE *f)
337 {
338         if (isCacheCorrupt)
339                 return;
340         int size=descriptors.size();
341         DescriptorMap::iterator it(descriptors.begin());
342         fwrite(&size, sizeof(int), 1, f);
343         while(size)
344         {
345                 fwrite(&it->first, sizeof(uint32_t), 1, f);
346                 fwrite(&it->second.reference_count, sizeof(int), 1, f);
347                 fwrite(it->second.data, it->second.data[1]+2, 1, f);
348                 ++it;
349                 --size;
350         }
351 }
352
353 void eventData::cacheCorrupt(const char* context)
354 {
355
356         eDebug("[eventData] EPG Cache is corrupt (%s), you should restart Enigma!", context);
357         if (!isCacheCorrupt)
358         {
359                 isCacheCorrupt = true;
360                 if (!eEPGCache::instance->m_filename.empty())
361                         unlink(eEPGCache::instance->m_filename.c_str()); // Remove corrupt EPG data
362         }
363 }
364
365 eEPGCache* eEPGCache::instance;
366 static pthread_mutex_t cache_lock =
367         PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
368 static pthread_mutex_t channel_map_lock =
369         PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
370
371 DEFINE_REF(eEPGCache)
372
373 eEPGCache::eEPGCache()
374         :messages(this,1), cleanTimer(eTimer::create(this)), m_running(false)
375 {
376         eDebug("[eEPGCache] Initialized EPGCache (wait for setCacheFile call now)");
377
378         enabledSources = 0;
379         historySeconds = 0;
380
381         CONNECT(messages.recv_msg, eEPGCache::gotMessage);
382         CONNECT(eDVBLocalTimeHandler::getInstance()->m_timeUpdated, eEPGCache::timeUpdated);
383         CONNECT(cleanTimer->timeout, eEPGCache::cleanLoop);
384
385         ePtr<eDVBResourceManager> res_mgr;
386         eDVBResourceManager::getInstance(res_mgr);
387         if (!res_mgr)
388                 eDebug("[eEPGCache] no resource manager !!!!!!!");
389         else
390                 res_mgr->connectChannelAdded(slot(*this,&eEPGCache::DVBChannelAdded), m_chanAddedConn);
391
392         instance=this;
393 }
394
395 void eEPGCache::setCacheFile(const char *path)
396 {
397         bool inited = !m_filename.empty();
398         m_filename = path;
399         if (!inited)
400         {
401                 eDebug("[eEPGCache] setCacheFile read/write epg data from/to '%s'", m_filename.c_str());
402                 if (eDVBLocalTimeHandler::getInstance()->ready())
403                         timeUpdated();
404         }
405 }
406
407 void eEPGCache::timeUpdated()
408 {
409         if (!m_filename.empty())
410         {
411                 if (!m_running)
412                 {
413                         eDebug("[eEPGCache] time updated.. start EPG Mainloop");
414                         run();
415                         m_running = true;
416                         singleLock s(channel_map_lock);
417                         for (ChannelMap::const_iterator it = m_knownChannels.begin(); it != m_knownChannels.end(); ++it)
418                         {
419                                 if (it->second->state == -1) {
420                                         it->second->state=0;
421                                         messages.send(Message(Message::startChannel, it->first));
422                                 }
423                         }
424                 } else
425                         messages.send(Message(Message::timeChanged));
426         }
427         else
428                 eDebug("[eEPGCache] time updated.. but cache file not set yet.. dont start epg!!");
429 }
430
431 void eEPGCache::DVBChannelAdded(eDVBChannel *chan)
432 {
433         if ( chan )
434         {
435 //              eDebug("[eEPGCache] add channel %p", chan);
436                 channel_data *data = new channel_data(this);
437                 data->channel = chan;
438                 data->prevChannelState = -1;
439 #ifdef ENABLE_PRIVATE_EPG
440                 data->m_PrivatePid = -1;
441 #endif
442 #ifdef ENABLE_MHW_EPG
443                 data->m_mhw2_channel_pid = 0x231; // defaults for astra 19.2 D+
444                 data->m_mhw2_title_pid = 0x234; // defaults for astra 19.2 D+
445                 data->m_mhw2_summary_pid = 0x236; // defaults for astra 19.2 D+
446 #endif
447                 singleLock s(channel_map_lock);
448                 m_knownChannels.insert( std::pair<iDVBChannel*, channel_data* >(chan, data) );
449                 chan->connectStateChange(slot(*this, &eEPGCache::DVBChannelStateChanged), data->m_stateChangedConn);
450         }
451 }
452
453 void eEPGCache::DVBChannelRunning(iDVBChannel *chan)
454 {
455         ChannelMap::const_iterator it = m_knownChannels.find(chan);
456         if ( it == m_knownChannels.end() )
457                 eDebug("[eEPGCache] will start non existing channel %p !!!", chan);
458         else
459         {
460                 channel_data &data = *it->second;
461                 ePtr<eDVBResourceManager> res_mgr;
462                 if ( eDVBResourceManager::getInstance( res_mgr ) )
463                         eDebug("[eEPGCache] no res manager!!");
464                 else
465                 {
466                         ePtr<iDVBDemux> demux;
467                         if ( data.channel->getDemux(demux, 0) )
468                         {
469                                 eDebug("[eEPGCache] no demux!!");
470                                 return;
471                         }
472                         else
473                         {
474                                 RESULT res = demux->createSectionReader( this, data.m_NowNextReader );
475                                 if ( res )
476                                 {
477                                         eDebug("[eEPGCache] couldnt initialize nownext reader!!");
478                                         return;
479                                 }
480
481                                 res = demux->createSectionReader( this, data.m_ScheduleReader );
482                                 if ( res )
483                                 {
484                                         eDebug("[eEPGCache] couldnt initialize schedule reader!!");
485                                         return;
486                                 }
487
488                                 res = demux->createSectionReader( this, data.m_ScheduleOtherReader );
489                                 if ( res )
490                                 {
491                                         eDebug("[eEPGCache] couldnt initialize schedule other reader!!");
492                                         return;
493                                 }
494
495 #ifdef ENABLE_VIRGIN
496                                 res = demux->createSectionReader( this, data.m_VirginNowNextReader );
497                                 if ( res )
498                                 {
499                                         eDebug("[eEPGCache] couldnt initialize virgin nownext reader!!");
500                                         return;
501                                 }
502
503                                 res = demux->createSectionReader( this, data.m_VirginScheduleReader );
504                                 if ( res )
505                                 {
506                                         eDebug("[eEPGCache] couldnt initialize virgin schedule reader!!");
507                                         return;
508                                 }
509 #endif
510 #ifdef ENABLE_NETMED
511                                 res = demux->createSectionReader( this, data.m_NetmedScheduleReader );
512                                 if ( res )
513                                 {
514                                         eDebug("[eEPGCache] couldnt initialize netmed schedule reader!!");
515                                         return;
516                                 }
517
518                                 res = demux->createSectionReader( this, data.m_NetmedScheduleOtherReader );
519                                 if ( res )
520                                 {
521                                         eDebug("[eEPGCache] couldnt initialize netmed schedule other reader!!");
522                                         return;
523                                 }
524 #endif
525                                 res = demux->createSectionReader( this, data.m_ViasatReader );
526                                 if ( res )
527                                 {
528                                         eDebug("[eEPGCache] couldnt initialize viasat reader!!");
529                                         return;
530                                 }
531 #ifdef ENABLE_PRIVATE_EPG
532                                 res = demux->createSectionReader( this, data.m_PrivateReader );
533                                 if ( res )
534                                 {
535                                         eDebug("[eEPGCache] couldnt initialize private reader!!");
536                                         return;
537                                 }
538 #endif
539 #ifdef ENABLE_MHW_EPG
540                                 res = demux->createSectionReader( this, data.m_MHWReader );
541                                 if ( res )
542                                 {
543                                         eDebug("[eEPGCache] couldnt initialize mhw reader!!");
544                                         return;
545                                 }
546                                 res = demux->createSectionReader( this, data.m_MHWReader2 );
547                                 if ( res )
548                                 {
549                                         eDebug("[eEPGCache] couldnt initialize mhw reader!!");
550                                         return;
551                                 }
552 #endif
553 #if ENABLE_FREESAT
554                                 res = demux->createSectionReader( this, data.m_FreeSatScheduleOtherReader );
555                                 if ( res )
556                                 {
557                                         eDebug("[eEPGCache] couldnt initialize FreeSat reader!!");
558                                         return;
559                                 }
560                                 res = demux->createSectionReader( this, data.m_FreeSatScheduleOtherReader2 );
561                                 if ( res )
562                                 {
563                                         eDebug("[eEPGCache] couldnt initialize FreeSat reader 2!!");
564                                         return;
565                                 }
566 #endif
567                                 if (m_running)
568                                 {
569                                         data.state = 0;
570                                         messages.send(Message(Message::startChannel, chan));
571                                         // -> gotMessage -> changedService
572                                 }
573                                 else
574                                         data.state=-1;
575                         }
576                 }
577         }
578 }
579
580 void eEPGCache::DVBChannelStateChanged(iDVBChannel *chan)
581 {
582         ChannelMap::iterator it = m_knownChannels.find(chan);
583         if ( it != m_knownChannels.end() )
584         {
585                 int state=0;
586                 chan->getState(state);
587                 if ( it->second->prevChannelState != state )
588                 {
589                         switch (state)
590                         {
591                                 case iDVBChannel::state_ok:
592                                 {
593                                         eDebug("[eEPGCache] channel %p running", chan);
594                                         DVBChannelRunning(chan);
595                                         break;
596                                 }
597                                 case iDVBChannel::state_release:
598                                 {
599                                         eDebug("[eEPGCache] remove channel %p", chan);
600                                         if (it->second->state >= 0)
601                                                 messages.send(Message(Message::leaveChannel, chan));
602                                         channel_data* cd = it->second;
603                                         pthread_mutex_lock(&cd->channel_active);
604                                         {
605                                                 singleLock s(channel_map_lock);
606                                                 m_knownChannels.erase(it);
607                                         }
608                                         pthread_mutex_unlock(&cd->channel_active);
609                                         delete cd;
610                                         // -> gotMessage -> abortEPG
611                                         return;
612                                 }
613                                 default: // ignore all other events
614                                         return;
615                         }
616                         if (it->second)
617                                 it->second->prevChannelState = state;
618                 }
619         }
620 }
621
622 bool eEPGCache::FixOverlapping(EventCacheItem &servicemap, time_t TM, int duration, const timeMap::iterator &tm_it, const uniqueEPGKey &service)
623 {
624         bool ret = false;
625         timeMap::iterator tmp = tm_it;
626         while ((tmp->first + tmp->second->getDuration() - 300) > TM)
627         {
628                 if(tmp->first != TM
629 #ifdef ENABLE_PRIVATE_EPG
630                         && tmp->second->type != PRIVATE
631 #endif
632 #ifdef ENABLE_MHW_EPG
633                         && tmp->second->type != MHW
634 #endif
635                         )
636                 {
637                         uint16_t event_id = tmp->second->getEventID();
638                         servicemap.byEvent.erase(event_id);
639 #ifdef EPG_DEBUG
640                         Event evt((uint8_t*)tmp->second->get());
641                         eServiceEvent event;
642                         event.parseFrom(&evt, service.sid<<16|service.onid);
643                         eDebug("[eEPGCache] (1)erase no more used event %04x %d\n%s %s\n%s",
644                                 service.sid, event_id,
645                                 event.getBeginTimeString().c_str(),
646                                 event.getEventName().c_str(),
647                                 event.getExtendedDescription().c_str());
648 #endif
649                         delete tmp->second;
650                         if (tmp == servicemap.byTime.begin())
651                         {
652                                 servicemap.byTime.erase(tmp);
653                                 break;
654                         }
655                         else
656                                 servicemap.byTime.erase(tmp--);
657                         ret = true;
658                 }
659                 else
660                 {
661                         if (tmp == servicemap.byTime.begin())
662                                 break;
663                         --tmp;
664                 }
665         }
666
667         tmp = tm_it;
668         while(tmp->first < (TM+duration-300))
669         {
670                 if (tmp->first != TM && tmp->second->type != PRIVATE)
671                 {
672                         uint16_t event_id = tmp->second->getEventID();
673                         servicemap.byEvent.erase(event_id);
674 #ifdef EPG_DEBUG
675                         Event evt((uint8_t*)tmp->second->get());
676                         eServiceEvent event;
677                         event.parseFrom(&evt, service.sid<<16|service.onid);
678                         eDebug("[eEPGCache] (2)erase no more used event %04x %d\n%s %s\n%s",
679                                 service.sid, event_id,
680                                 event.getBeginTimeString().c_str(),
681                                 event.getEventName().c_str(),
682                                 event.getExtendedDescription().c_str());
683 #endif
684                         delete tmp->second;
685                         servicemap.byTime.erase(tmp++);
686                         ret = true;
687                 }
688                 else
689                         ++tmp;
690                 if (tmp == servicemap.byTime.end())
691                         break;
692         }
693         return ret;
694 }
695
696 void eEPGCache::sectionRead(const uint8_t *data, int source, channel_data *channel)
697 {
698         const eit_t *eit = (const eit_t*) data;
699
700         int len = eit->getSectionLength()-1;//+3-4;
701         int ptr = EIT_SIZE;
702         if ( ptr >= len )
703                 return;
704
705 #if 0
706                 /*
707                  * disable for now, as this hack breaks EIT parsing for
708                  * services with a low segment_last_table_id
709                  *
710                  * Multichoice should be the exception, not the rule...
711                  */
712
713         // This fixed the EPG on the Multichoice irdeto systems
714         // the EIT packet is non-compliant.. their EIT packet stinks
715         if ( data[ptr-1] < 0x40 )
716                 --ptr;
717 #endif
718
719         int onid = eit->getOriginalNetworkId();
720         int tsid = eit->getTransportStreamId();
721
722         // Cablecom HACK .. tsid / onid in eit data are incorrect.. so we use
723         // it from running channel (just for current transport stream eit data)
724         /*
725          * Make an exception for BEV (onid 0x100, 0x101), which doesn't use
726          * SCHEDULE_OTHER. As a result SCHEDULE will contain data for different tsid's,
727          * so we should not replace it with the current tsid.
728          */
729         bool use_transponder_chid = onid != 0x101 && onid != 0x100 && (source == SCHEDULE || (source == NOWNEXT && data[0] == 0x4E));
730
731         if (use_transponder_chid && channel)
732         {
733                 eDVBChannelID chid = channel->channel->getChannelID();
734
735                 onid = chid.original_network_id.get();
736                 tsid = chid.transport_stream_id.get();
737         }
738
739         uniqueEPGKey service( eit->getServiceID(), onid, tsid);
740
741         eit_event_struct* eit_event = (eit_event_struct*) (data+ptr);
742         int eit_event_size;
743         int duration;
744
745         time_t TM = parseDVBtime((const uint8_t*)eit_event + 2);
746         time_t now = ::time(0);
747
748         if ( TM != 3599 && TM > -1 && channel)
749                 channel->haveData |= source;
750
751         singleLock s(cache_lock);
752         // hier wird immer eine eventMap zurck gegeben.. entweder eine vorhandene..
753         // oder eine durch [] erzeugte
754         EventCacheItem &servicemap = eventDB[service];
755         eventMap::iterator prevEventIt = servicemap.byEvent.end();
756         timeMap::iterator prevTimeIt = servicemap.byTime.end();
757
758         while (ptr<len)
759         {
760                 uint16_t event_hash;
761                 eit_event_size = eit_event->getDescriptorsLoopLength()+EIT_LOOP_SIZE;
762
763                 duration = fromBCD(eit_event->duration_1)*3600+fromBCD(eit_event->duration_2)*60+fromBCD(eit_event->duration_3);
764                 TM = parseDVBtime((const uint8_t*)eit_event + 2, &event_hash);
765
766                 if ( (TM != 3599) &&            // NVOD Service
767                      (now <= (TM+duration)) &&  // skip old events
768                      (TM < (now+28*24*60*60)) &&        // no more than 4 weeks in future
769                      ( (onid != 1714) || (duration != (24*3600-1)) )    // PlatformaHD invalid event
770                    )
771                 {
772                         uint16_t event_id = eit_event->getEventId();
773                         eventData *evt = 0;
774                         int ev_erase_count = 0;
775                         int tm_erase_count = 0;
776
777                         if (event_id == 0) {
778                                 // hack for some polsat services on 13.0E..... but this also replaces other valid event_ids with value 0..
779                                 // but we dont care about it...
780                                 event_id = event_hash;
781                                 eit_event->event_id_hi = event_hash >> 8;
782                                 eit_event->event_id_lo = event_hash & 0xFF;
783                         }
784
785                         // search in eventmap
786                         eventMap::iterator ev_it =
787                                 servicemap.byEvent.find(event_id);
788
789                         //eDebug("[eEPGCache] event_id : %d, sid : %04x", event_id, service.sid);
790
791                         // entry with this event_id is already exist ?
792                         if ( ev_it != servicemap.byEvent.end() )
793                         {
794                                 if ( source > ev_it->second->type )  // update needed ?
795                                         goto next; // when not.. then skip this entry
796
797                                 // search this event in timemap
798                                 timeMap::iterator tm_it_tmp =
799                                         servicemap.byTime.find(ev_it->second->getStartTime());
800
801                                 if ( tm_it_tmp != servicemap.byTime.end() )
802                                 {
803                                         if ( tm_it_tmp->first == TM ) // just update eventdata
804                                         {
805                                                 // exempt memory
806                                                 eventData *tmp = ev_it->second;
807                                                 ev_it->second = tm_it_tmp->second = new eventData(eit_event, eit_event_size, source, (tsid<<16)|onid);
808                                                 if (FixOverlapping(servicemap, TM, duration, tm_it_tmp, service))
809                                                 {
810                                                         prevEventIt = servicemap.byEvent.end();
811                                                         prevTimeIt = servicemap.byTime.end();
812                                                 }
813                                                 delete tmp;
814                                                 goto next;
815                                         }
816                                         else  // event has new event begin time
817                                         {
818                                                 tm_erase_count++;
819                                                 // delete the found record from timemap
820                                                 servicemap.byTime.erase(tm_it_tmp);
821                                                 prevTimeIt = servicemap.byTime.end();
822                                         }
823                                 }
824                         }
825
826                         // search in timemap, for check of a case if new time has coincided with time of other event
827                         // or event was is not found in eventmap
828                         timeMap::iterator tm_it =
829                                 servicemap.byTime.find(TM);
830
831                         if ( tm_it != servicemap.byTime.end() )
832                         {
833                                 // event with same start time but another event_id...
834                                 if ( source > tm_it->second->type &&
835                                         ev_it == servicemap.byEvent.end() )
836                                         goto next; // when not.. then skip this entry
837
838                                 // search this time in eventmap
839                                 eventMap::iterator ev_it_tmp = servicemap.byEvent.find(tm_it->second->getEventID());
840
841                                 if ( ev_it_tmp != servicemap.byEvent.end() )
842                                 {
843                                         ev_erase_count++;
844                                         // delete the found record from eventmap
845                                         servicemap.byEvent.erase(ev_it_tmp);
846                                         prevEventIt = servicemap.byEvent.end();
847                                 }
848                         }
849                         evt = new eventData(eit_event, eit_event_size, source, (tsid<<16)|onid);
850 #ifdef EPG_DEBUG
851                         bool consistencyCheck=true;
852 #endif
853                         if (ev_erase_count > 0 && tm_erase_count > 0) // 2 different pairs have been removed
854                         {
855                                 // exempt memory
856                                 delete ev_it->second;
857                                 delete tm_it->second;
858                                 ev_it->second=evt;
859                                 tm_it->second=evt;
860                         }
861                         else if (ev_erase_count == 0 && tm_erase_count > 0)
862                         {
863                                 // exempt memory
864                                 delete ev_it->second;
865                                 tm_it = prevTimeIt = servicemap.byTime.insert( prevTimeIt, std::pair<const time_t, eventData*>( TM, evt ) );
866                                 ev_it->second = evt;
867                         }
868                         else if (ev_erase_count > 0 && tm_erase_count == 0)
869                         {
870                                 // exempt memory
871                                 delete tm_it->second;
872                                 ev_it = prevEventIt = servicemap.byEvent.insert( prevEventIt, std::pair<const uint16_t, eventData*>( event_id, evt) );
873                                 tm_it->second = evt;
874                         }
875                         else // added new eventData
876                         {
877 #ifdef EPG_DEBUG
878                                 consistencyCheck=false;
879 #endif
880                                 ev_it = prevEventIt = servicemap.byEvent.insert( prevEventIt, std::pair<const uint16_t, eventData*>( event_id, evt) );
881                                 tm_it = prevTimeIt = servicemap.byTime.insert( prevTimeIt, std::pair<const time_t, eventData*>( TM, evt ) );
882                         }
883
884 #ifdef EPG_DEBUG
885                         if ( consistencyCheck )
886                         {
887                                 if ( tm_it->second != evt || ev_it->second != evt )
888                                         eFatal("[eEPGCache] tm_it->second != ev_it->second");
889                                 else if ( tm_it->second->getStartTime() != tm_it->first )
890                                         eFatal("[eEPGCache] event start_time(%d) non equal timemap key(%d)",
891                                                 (int)tm_it->second->getStartTime(), (int)tm_it->first );
892                                 else if ( tm_it->first != TM )
893                                         eFatal("[eEPGCache] timemap key(%d) non equal TM(%d)",
894                                                 (int)tm_it->first, (int)TM);
895                                 else if ( ev_it->second->getEventID() != ev_it->first )
896                                         eFatal("[eEPGCache] event_id (%d) non equal event_map key(%d)",
897                                                 (int)ev_it->second->getEventID(), (int)ev_it->first);
898                                 else if ( ev_it->first != event_id )
899                                         eFatal("[eEPGCache] eventmap key(%d) non equal event_id(%d)",
900                                                 (int)ev_it->first, (int)event_id );
901                         }
902 #endif
903                         if (FixOverlapping(servicemap, TM, duration, tm_it, service))
904                         {
905                                 prevEventIt = servicemap.byEvent.end();
906                                 prevTimeIt = servicemap.byTime.end();
907                         }
908                 }
909 next:
910 #ifdef EPG_DEBUG
911                 if ( servicemap.byEvent.size() != servicemap.byTime.size() )
912                 {
913                         FILE *f = fopen("/hdd/event_map.txt", "w+");
914                         int i=0;
915                         for (eventMap::iterator it(servicemap.byEvent.begin())
916                                 ; it != servicemap.byEvent.end(); ++it )
917                                 fprintf(f, "%d(key %d) -> time %d, event_id %d, data %p\n", 
918                                         i++, (int)it->first, (int)it->second->getStartTime(), (int)it->second->getEventID(), it->second );
919                         fclose(f);
920                         f = fopen("/hdd/time_map.txt", "w+");
921                         i=0;
922                         for (timeMap::iterator it(servicemap.byTime.begin())
923                                 ; it != servicemap.byTime.end(); ++it )
924                                         fprintf(f, "%d(key %d) -> time %d, event_id %d, data %p\n", 
925                                                 i++, (int)it->first, (int)it->second->getStartTime(), (int)it->second->getEventID(), it->second );
926                         fclose(f);
927
928                         eFatal("[eEPGCache] (1)map sizes not equal :( sid %04x tsid %04x onid %04x size %d size2 %d",
929                                 service.sid, service.tsid, service.onid,
930                                 servicemap.byEvent.size(), servicemap.byTime.size() );
931                 }
932 #endif
933                 ptr += eit_event_size;
934                 eit_event = (eit_event_struct*)(((uint8_t*)eit_event) + eit_event_size);
935         }
936 }
937
938 void eEPGCache::flushEPG(const uniqueEPGKey & s)
939 {
940         eDebug("[eEPGCache] flushEPG %d", (int)(bool)s);
941         singleLock l(cache_lock);
942         if (s)  // clear only this service
943         {
944                 eventCache::iterator it = eventDB.find(s);
945                 if ( it != eventDB.end() )
946                 {
947                         eventMap &evMap = it->second.byEvent;
948                         timeMap &tmMap = it->second.byTime;
949                         tmMap.clear();
950                         for (eventMap::iterator i = evMap.begin(); i != evMap.end(); ++i)
951                                 delete i->second;
952                         evMap.clear();
953                         eventDB.erase(it);
954
955                         // TODO .. search corresponding channel for removed service and remove this channel from lastupdated map
956 #ifdef ENABLE_PRIVATE_EPG
957                         contentMaps::iterator it =
958                                 content_time_tables.find(s);
959                         if ( it != content_time_tables.end() )
960                         {
961                                 it->second.clear();
962                                 content_time_tables.erase(it);
963                         }
964 #endif
965                 }
966         }
967         else // clear complete EPG Cache
968         {
969                 for (eventCache::iterator it(eventDB.begin());
970                         it != eventDB.end(); ++it)
971                 {
972                         eventMap &evMap = it->second.byEvent;
973                         timeMap &tmMap = it->second.byTime;
974                         for (eventMap::iterator i = evMap.begin(); i != evMap.end(); ++i)
975                                 delete i->second;
976                         evMap.clear();
977                         tmMap.clear();
978                 }
979                 eventDB.clear();
980 #ifdef ENABLE_PRIVATE_EPG
981                 content_time_tables.clear();
982 #endif
983                 channelLastUpdated.clear();
984                 singleLock m(channel_map_lock);
985                 for (ChannelMap::const_iterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it)
986                         it->second->startEPG();
987         }
988 }
989
990 void eEPGCache::cleanLoop()
991 {
992         { /* scope for cache lock */
993                 time_t now = ::time(0) - historySeconds;
994                 singleLock s(cache_lock);
995
996                 for (eventCache::iterator DBIt = eventDB.begin(); DBIt != eventDB.end(); DBIt++)
997                 {
998                         bool updated = false;
999                         for (timeMap::iterator It = DBIt->second.byTime.begin(); It != DBIt->second.byTime.end() && It->first < now;)
1000                         {
1001                                 if ( now > (It->first+It->second->getDuration()) )  // outdated normal entry (nvod references to)
1002                                 {
1003                                         // remove entry from eventMap
1004                                         eventMap::iterator b(DBIt->second.byEvent.find(It->second->getEventID()));
1005                                         if ( b != DBIt->second.byEvent.end() )
1006                                         {
1007                                                 // release Heap Memory for this entry   (new ....)
1008                                                 //eDebug("[eEPGCache] delete old event (evmap)");
1009                                                 DBIt->second.byEvent.erase(b);
1010                                         }
1011
1012                                         // remove entry from timeMap
1013                                         //eDebug("[eEPGCache] release heap mem");
1014                                         delete It->second;
1015                                         DBIt->second.byTime.erase(It++);
1016                                         //eDebug("[eEPGCache] delete old event (timeMap)");
1017                                         updated = true;
1018                                 }
1019                                 else
1020                                         ++It;
1021                         }
1022 #ifdef ENABLE_PRIVATE_EPG
1023                         if ( updated )
1024                         {
1025                                 contentMaps::iterator x =
1026                                         content_time_tables.find( DBIt->first );
1027                                 if ( x != content_time_tables.end() )
1028                                 {
1029                                         timeMap &tmMap = DBIt->second.byTime;
1030                                         for ( contentMap::iterator i = x->second.begin(); i != x->second.end(); )
1031                                         {
1032                                                 for ( contentTimeMap::iterator it(i->second.begin());
1033                                                         it != i->second.end(); )
1034                                                 {
1035                                                         if ( tmMap.find(it->second.first) == tmMap.end() )
1036                                                                 i->second.erase(it++);
1037                                                         else
1038                                                                 ++it;
1039                                                 }
1040                                                 if ( i->second.size() )
1041                                                         ++i;
1042                                                 else
1043                                                         x->second.erase(i++);
1044                                         }
1045                                 }
1046                         }
1047 #endif
1048                 }
1049         } /* release lock */
1050         cleanTimer->start(CLEAN_INTERVAL,true);
1051 }
1052
1053 eEPGCache::~eEPGCache()
1054 {
1055         m_running = false;
1056         messages.send(Message::quit);
1057         kill(); // waiting for thread shutdown
1058         singleLock s(cache_lock);
1059         for (eventCache::iterator evIt = eventDB.begin(); evIt != eventDB.end(); evIt++)
1060                 for (eventMap::iterator It = evIt->second.byEvent.begin(); It != evIt->second.byEvent.end(); It++)
1061                         delete It->second;
1062 }
1063
1064 void eEPGCache::gotMessage( const Message &msg )
1065 {
1066         switch (msg.type)
1067         {
1068                 case Message::flush:
1069                         flushEPG(msg.service);
1070                         break;
1071                 case Message::startChannel:
1072                 {
1073                         singleLock s(channel_map_lock);
1074                         ChannelMap::const_iterator channel = m_knownChannels.find(msg.channel);
1075                         if ( channel != m_knownChannels.end() )
1076                                 channel->second->startChannel();
1077                         break;
1078                 }
1079                 case Message::leaveChannel:
1080                 {
1081                         singleLock s(channel_map_lock);
1082                         ChannelMap::const_iterator channel = m_knownChannels.find(msg.channel);
1083                         if ( channel != m_knownChannels.end() )
1084                                 channel->second->abortEPG();
1085                         break;
1086                 }
1087                 case Message::quit:
1088                         quit(0);
1089                         break;
1090 #ifdef ENABLE_PRIVATE_EPG
1091                 case Message::got_private_pid:
1092                 {
1093                         singleLock s(channel_map_lock);
1094                         for (ChannelMap::const_iterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it)
1095                         {
1096                                 eDVBChannel *channel = (eDVBChannel*) it->first;
1097                                 channel_data *data = it->second;
1098                                 eDVBChannelID chid = channel->getChannelID();
1099                                 if ( chid.transport_stream_id.get() == msg.service.tsid &&
1100                                         chid.original_network_id.get() == msg.service.onid &&
1101                                         data->m_PrivatePid == -1 )
1102                                 {
1103                                         data->m_PrevVersion = -1;
1104                                         data->m_PrivatePid = msg.pid;
1105                                         data->m_PrivateService = msg.service;
1106                                         int onid = chid.original_network_id.get();
1107                                         onid |= 0x80000000;  // we use highest bit as private epg indicator
1108                                         chid.original_network_id = onid;
1109                                         updateMap::iterator It = channelLastUpdated.find( chid );
1110                                         int update = ( It != channelLastUpdated.end() ? ( UPDATE_INTERVAL - ( (::time(0)-It->second) * 1000 ) ) : ZAP_DELAY );
1111                                         if (update < ZAP_DELAY)
1112                                                 update = ZAP_DELAY;
1113                                         data->startPrivateTimer->start(update, 1);
1114                                         if (update >= 60000)
1115                                                 eDebug("[eEPGCache] next private update in %i min", update/60000);
1116                                         else if (update >= 1000)
1117                                                 eDebug("[eEPGCache] next private update in %i sec", update/1000);
1118                                         break;
1119                                 }
1120                         }
1121                         break;
1122                 }
1123 #endif
1124 #ifdef ENABLE_MHW_EPG
1125                 case Message::got_mhw2_channel_pid:
1126                 {
1127                         singleLock s(channel_map_lock);
1128                         for (ChannelMap::const_iterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it)
1129                         {
1130                                 eDVBChannel *channel = (eDVBChannel*) it->first;
1131                                 channel_data *data = it->second;
1132                                 eDVBChannelID chid = channel->getChannelID();
1133                                 if ( chid.transport_stream_id.get() == msg.service.tsid &&
1134                                         chid.original_network_id.get() == msg.service.onid )
1135                                 {
1136                                         data->m_mhw2_channel_pid = msg.pid;
1137                                         eDebug("[eEPGCache] got mhw2 channel pid %04x", msg.pid);
1138                                         break;
1139                                 }
1140                         }
1141                         break;
1142                 }
1143                 case Message::got_mhw2_title_pid:
1144                 {
1145                         singleLock s(channel_map_lock);
1146                         for (ChannelMap::const_iterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it)
1147                         {
1148                                 eDVBChannel *channel = (eDVBChannel*) it->first;
1149                                 channel_data *data = it->second;
1150                                 eDVBChannelID chid = channel->getChannelID();
1151                                 if ( chid.transport_stream_id.get() == msg.service.tsid &&
1152                                         chid.original_network_id.get() == msg.service.onid )
1153                                 {
1154                                         data->m_mhw2_title_pid = msg.pid;
1155                                         eDebug("[eEPGCache] got mhw2 title pid %04x", msg.pid);
1156                                         break;
1157                                 }
1158                         }
1159                         break;
1160                 }
1161                 case Message::got_mhw2_summary_pid:
1162                 {
1163                         singleLock s(channel_map_lock);
1164                         for (ChannelMap::const_iterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it)
1165                         {
1166                                 eDVBChannel *channel = (eDVBChannel*) it->first;
1167                                 channel_data *data = it->second;
1168                                 eDVBChannelID chid = channel->getChannelID();
1169                                 if ( chid.transport_stream_id.get() == msg.service.tsid &&
1170                                         chid.original_network_id.get() == msg.service.onid )
1171                                 {
1172                                         data->m_mhw2_summary_pid = msg.pid;
1173                                         eDebug("[eEPGCache] got mhw2 summary pid %04x", msg.pid);
1174                                         break;
1175                                 }
1176                         }
1177                         break;
1178                 }
1179 #endif
1180                 case Message::timeChanged:
1181                         cleanLoop();
1182                         break;
1183                 default:
1184                         eDebug("[eEPGCache] unhandled EPGCache Message!!");
1185                         break;
1186         }
1187 }
1188
1189 void eEPGCache::thread()
1190 {
1191         hasStarted();
1192         nice(4);
1193         load();
1194         cleanLoop();
1195         runLoop();
1196         save();
1197 }
1198
1199 static const char* EPGDAT_IN_FLASH = "/epg.dat";
1200
1201 void eEPGCache::load()
1202 {
1203         if (m_filename.empty())
1204                 m_filename = "/hdd/epg.dat";
1205         const char* EPGDAT = m_filename.c_str();
1206         std::string filenamex = m_filename + ".loading";
1207         const char* EPGDATX = filenamex.c_str();
1208         FILE *f = fopen(EPGDAT, "rb");
1209         int renameResult;
1210         if (f == NULL)
1211         {
1212                 /* No EPG on harddisk, so try internal flash */
1213                 eDebug("[eEPGCache] %s not found, try %s", EPGDAT, EPGDAT_IN_FLASH);
1214                 EPGDAT = EPGDAT_IN_FLASH;
1215                 f = fopen(EPGDAT, "rb");
1216                 if (f == NULL)
1217                         return;
1218                 renameResult = -1;
1219         }
1220         else
1221         {
1222                 unlink(EPGDATX);
1223                 renameResult = rename(EPGDAT, EPGDATX);
1224                 if (renameResult) eDebug("[eEPGCache] failed to rename %s", EPGDAT);
1225         }
1226         {
1227                 int size=0;
1228                 int cnt=0;
1229                 unsigned int magic=0;
1230                 unlink(EPGDAT_IN_FLASH);/* Don't keep it around when in flash */
1231                 fread( &magic, sizeof(int), 1, f);
1232                 if (magic != 0x98765432)
1233                 {
1234                         eDebug("[eEPGCache] epg file has incorrect byte order.. dont read it");
1235                         fclose(f);
1236                         return;
1237                 }
1238                 char text1[13];
1239                 fread( text1, 13, 1, f);
1240                 if ( !memcmp( text1, "ENIGMA_EPG_V7", 13) )
1241                 {
1242                         singleLock s(cache_lock);
1243                         fread( &size, sizeof(int), 1, f);
1244                         eventDB.rehash(size); /* Reserve buckets in advance */
1245                         while(size--)
1246                         {
1247                                 uniqueEPGKey key;
1248                                 int size=0;
1249                                 fread( &key, sizeof(uniqueEPGKey), 1, f);
1250                                 fread( &size, sizeof(int), 1, f);
1251                                 EventCacheItem& item = eventDB[key]; /* Constructs new entry */
1252                                 while(size--)
1253                                 {
1254                                         uint8_t len=0;
1255                                         uint8_t type=0;
1256                                         eventData *event=0;
1257                                         fread( &type, sizeof(uint8_t), 1, f);
1258                                         fread( &len, sizeof(uint8_t), 1, f);
1259                                         event = new eventData(0, len, type);
1260                                         event->n_crc = (len-10) / sizeof(uint32_t);
1261                                         fread( event->rawEITdata, 10, 1, f);
1262                                         if (event->n_crc)
1263                                         {
1264                                                 event->crc_list = new uint32_t[event->n_crc];
1265                                                 fread( event->crc_list, sizeof(uint32_t), event->n_crc, f);
1266                                         }
1267                                         eventData::CacheSize += sizeof(eventData) + event->n_crc * sizeof(uint32_t);
1268                                         item.byEvent[event->getEventID()] = event;
1269                                         item.byTime[event->getStartTime()] = event;
1270                                         ++cnt;
1271                                 }
1272                         }
1273                         eventData::load(f);
1274                         eDebug("[eEPGCache] %d events read from %s", cnt, EPGDAT);
1275 #ifdef ENABLE_PRIVATE_EPG
1276                         char text2[11];
1277                         fread( text2, 11, 1, f);
1278                         if ( !memcmp( text2, "PRIVATE_EPG", 11) )
1279                         {
1280                                 size=0;
1281                                 fread( &size, sizeof(int), 1, f);
1282                                 eventDB.rehash(size); /* Reserve buckets in advance */
1283                                 while(size--)
1284                                 {
1285                                         int size=0;
1286                                         uniqueEPGKey key;
1287                                         fread( &key, sizeof(uniqueEPGKey), 1, f);
1288                                         eventMap &evMap = eventDB[key].byEvent;
1289                                         fread( &size, sizeof(int), 1, f);
1290                                         while(size--)
1291                                         {
1292                                                 int size;
1293                                                 int content_id;
1294                                                 fread( &content_id, sizeof(int), 1, f);
1295                                                 fread( &size, sizeof(int), 1, f);
1296                                                 while(size--)
1297                                                 {
1298                                                         time_t time1, time2;
1299                                                         uint16_t event_id;
1300                                                         fread( &time1, sizeof(time_t), 1, f);
1301                                                         fread( &time2, sizeof(time_t), 1, f);
1302                                                         fread( &event_id, sizeof(uint16_t), 1, f);
1303                                                         content_time_tables[key][content_id][time1]=std::pair<time_t, uint16_t>(time2, event_id);
1304                                                         eventMap::iterator it =
1305                                                                 evMap.find(event_id);
1306                                                         if (it != evMap.end())
1307                                                                 it->second->type = PRIVATE;
1308                                                 }
1309                                         }
1310                                 }
1311                         }
1312 #endif // ENABLE_PRIVATE_EPG
1313                 }
1314                 else
1315                         eDebug("[eEPGCache] don't read old epg database");
1316                 posix_fadvise(fileno(f), 0, 0, POSIX_FADV_DONTNEED);
1317                 fclose(f);
1318                 // We got this far, so the EPG file is okay.
1319                 if (renameResult == 0)
1320                 {
1321                         renameResult = rename(EPGDATX, EPGDAT);
1322                         if (renameResult) eDebug("[eEPGCache] failed to rename epg.dat back");
1323                 }
1324         }
1325 }
1326
1327 void eEPGCache::save()
1328 {
1329         const char* EPGDAT = m_filename.c_str();
1330         if (eventData::isCacheCorrupt)
1331                 return;
1332         // only save epg.dat if it's worth the trouble...
1333         if (eventData::CacheSize < 10240)
1334                 return;
1335
1336         /* create empty file */
1337         FILE *f = fopen(EPGDAT, "wb");
1338         if (!f)
1339         {
1340                 eDebug("[eEPGCache] couldn't save epg data to '%s'(%m)", EPGDAT);
1341                 EPGDAT = EPGDAT_IN_FLASH;
1342                 f = fopen(EPGDAT, "wb");
1343                 if (!f)
1344                         return;
1345         }
1346
1347         char *buf = realpath(EPGDAT, NULL);
1348         if (!buf)
1349         {
1350                 eDebug("[eEPGCache] realpath to '%s' failed in save (%m)", EPGDAT);
1351                 fclose(f);
1352                 return;
1353         }
1354
1355         eDebug("[eEPGCache] store epg to realpath '%s'", buf);
1356
1357         struct statfs s;
1358         off64_t tmp;
1359         if (statfs(buf, &s) < 0) {
1360                 eDebug("[eEPGCache] statfs '%s' failed in save (%m)", buf);
1361                 fclose(f);
1362                 free(buf);
1363                 return;
1364         }
1365
1366         free(buf);
1367
1368         // check for enough free space on storage
1369         tmp=s.f_bfree;
1370         tmp*=s.f_bsize;
1371         if ( tmp < (eventData::CacheSize*12)/10 ) // 20% overhead
1372         {
1373                 eDebug("[eEPGCache] not enough free space at '%s' %lld bytes available but %u needed", buf, tmp, (eventData::CacheSize*12)/10);
1374                 fclose(f);
1375                 return;
1376         }
1377
1378         int cnt=0;
1379         unsigned int magic = 0x98765432;
1380         fwrite( &magic, sizeof(int), 1, f);
1381         const char *text = "UNFINISHED_V7";
1382         fwrite( text, 13, 1, f );
1383         int size = eventDB.size();
1384         fwrite( &size, sizeof(int), 1, f );
1385         for (eventCache::iterator service_it(eventDB.begin()); service_it != eventDB.end(); ++service_it)
1386         {
1387                 timeMap &timemap = service_it->second.byTime;
1388                 fwrite( &service_it->first, sizeof(uniqueEPGKey), 1, f);
1389                 size = timemap.size();
1390                 fwrite( &size, sizeof(int), 1, f);
1391                 for (timeMap::iterator time_it(timemap.begin()); time_it != timemap.end(); ++time_it)
1392                 {
1393                         uint8_t len = time_it->second->n_crc * sizeof(uint32_t) + 10;
1394                         fwrite( &time_it->second->type, sizeof(uint8_t), 1, f );
1395                         fwrite( &len, sizeof(uint8_t), 1, f);
1396                         fwrite( time_it->second->rawEITdata, 10, 1, f);
1397                         fwrite( time_it->second->crc_list, sizeof(uint32_t), time_it->second->n_crc, f);
1398                         ++cnt;
1399                 }
1400         }
1401         eDebug("[eEPGCache] %d events written to %s", cnt, EPGDAT);
1402         eventData::save(f);
1403 #ifdef ENABLE_PRIVATE_EPG
1404         const char* text3 = "PRIVATE_EPG";
1405         fwrite( text3, 11, 1, f );
1406         size = content_time_tables.size();
1407         fwrite( &size, sizeof(int), 1, f);
1408         for (contentMaps::iterator a = content_time_tables.begin(); a != content_time_tables.end(); ++a)
1409         {
1410                 contentMap &content_time_table = a->second;
1411                 fwrite( &a->first, sizeof(uniqueEPGKey), 1, f);
1412                 int size = content_time_table.size();
1413                 fwrite( &size, sizeof(int), 1, f);
1414                 for (contentMap::iterator i = content_time_table.begin(); i != content_time_table.end(); ++i )
1415                 {
1416                         int size = i->second.size();
1417                         fwrite( &i->first, sizeof(int), 1, f);
1418                         fwrite( &size, sizeof(int), 1, f);
1419                         for ( contentTimeMap::iterator it(i->second.begin());
1420                                 it != i->second.end(); ++it )
1421                         {
1422                                 fwrite( &it->first, sizeof(time_t), 1, f);
1423                                 fwrite( &it->second.first, sizeof(time_t), 1, f);
1424                                 fwrite( &it->second.second, sizeof(uint16_t), 1, f);
1425                         }
1426                 }
1427         }
1428 #endif
1429         // write version string after binary data
1430         // has been written to disk.
1431         fsync(fileno(f));
1432         fseek(f, sizeof(int), SEEK_SET);
1433         fwrite("ENIGMA_EPG_V7", 13, 1, f);
1434         fclose(f);
1435 }
1436
1437 eEPGCache::channel_data::channel_data(eEPGCache *ml)
1438         :cache(ml)
1439         ,abortTimer(eTimer::create(ml)), zapTimer(eTimer::create(ml)), state(-2)
1440         ,isRunning(0), haveData(0)
1441 #ifdef ENABLE_PRIVATE_EPG
1442         ,startPrivateTimer(eTimer::create(ml))
1443 #endif
1444 #ifdef ENABLE_MHW_EPG
1445         ,m_MHWTimeoutTimer(eTimer::create(ml))
1446 #endif
1447 {
1448 #ifdef ENABLE_MHW_EPG
1449         CONNECT(m_MHWTimeoutTimer->timeout, eEPGCache::channel_data::MHWTimeout);
1450 #endif
1451         CONNECT(zapTimer->timeout, eEPGCache::channel_data::startEPG);
1452         CONNECT(abortTimer->timeout, eEPGCache::channel_data::abortNonAvail);
1453 #ifdef ENABLE_PRIVATE_EPG
1454         CONNECT(startPrivateTimer->timeout, eEPGCache::channel_data::startPrivateReader);
1455 #endif
1456         pthread_mutex_init(&channel_active, 0);
1457 }
1458
1459 void eEPGCache::channel_data::finishEPG()
1460 {
1461         if (!isRunning)  // epg ready
1462         {
1463                 eDebug("[eEPGCache] stop caching events(%ld)", ::time(0));
1464                 zapTimer->start(UPDATE_INTERVAL, 1);
1465                 eDebug("[eEPGCache] next update in %i min", UPDATE_INTERVAL / 60000);
1466                 for (unsigned int i=0; i < sizeof(seenSections)/sizeof(tidMap); ++i)
1467                 {
1468                         seenSections[i].clear();
1469                         calcedSections[i].clear();
1470                 }
1471 #ifdef ENABLE_MHW_EPG
1472                 cleanupMHW();
1473 #endif
1474 #ifdef ENABLE_FREESAT
1475                 cleanupFreeSat();
1476 #endif
1477                 singleLock l(cache_lock);
1478                 cache->channelLastUpdated[channel->getChannelID()] = ::time(0);
1479         }
1480 }
1481
1482 void eEPGCache::channel_data::startEPG()
1483 {
1484         eDebug("[eEPGCache] start caching events(%ld)", ::time(0));
1485         state=0;
1486         haveData=0;
1487         for (unsigned int i=0; i < sizeof(seenSections)/sizeof(tidMap); ++i)
1488         {
1489                 seenSections[i].clear();
1490                 calcedSections[i].clear();
1491         }
1492 #ifdef ENABLE_MHW_EPG
1493                 cleanupMHW();
1494 #endif
1495 #ifdef ENABLE_FREESAT
1496                 cleanupFreeSat();
1497 #endif
1498
1499         eDVBSectionFilterMask mask;
1500         memset(&mask, 0, sizeof(mask));
1501
1502 #ifdef ENABLE_MHW_EPG
1503         if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::MHW)
1504         {
1505                 mask.pid = 0xD3;
1506                 mask.data[0] = 0x91;
1507                 mask.mask[0] = 0xFF;
1508                 m_MHWReader->connectRead(slot(*this, &eEPGCache::channel_data::readMHWData), m_MHWConn);
1509                 m_MHWReader->start(mask);
1510                 isRunning |= MHW;
1511                 memcpy(&m_MHWFilterMask, &mask, sizeof(eDVBSectionFilterMask));
1512
1513                 mask.pid = m_mhw2_channel_pid;
1514                 mask.data[0] = 0xC8;
1515                 mask.mask[0] = 0xFF;
1516                 mask.data[1] = 0;
1517                 mask.mask[1] = 0xFF;
1518                 m_MHWReader2->connectRead(slot(*this, &eEPGCache::channel_data::readMHWData2), m_MHWConn2);
1519                 m_MHWReader2->start(mask);
1520                 isRunning |= MHW;
1521                 memcpy(&m_MHWFilterMask2, &mask, sizeof(eDVBSectionFilterMask));
1522                 mask.data[1] = 0;
1523                 mask.mask[1] = 0;
1524                 m_MHWTimeoutet=false;
1525         }
1526 #endif
1527 #ifdef ENABLE_FREESAT
1528         if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::FREESAT_SCHEDULE_OTHER)
1529         {
1530                 mask.pid = 3842;
1531                 mask.flags = eDVBSectionFilterMask::rfCRC;
1532                 mask.data[0] = 0x60;
1533                 mask.mask[0] = 0xFE;
1534                 m_FreeSatScheduleOtherReader->connectRead(slot(*this, &eEPGCache::channel_data::readFreeSatScheduleOtherData), m_FreeSatScheduleOtherConn);
1535                 m_FreeSatScheduleOtherReader->start(mask);
1536
1537                 /*
1538                  * faster pid, available on ITV HD transponder.
1539                  * We rely on the fact that we have either of the two,
1540                  * never both. (both readers share the same data callback
1541                  * and status maps)
1542                  */
1543                 mask.pid = 3003;
1544                 m_FreeSatScheduleOtherReader2->connectRead(slot(*this, &eEPGCache::channel_data::readFreeSatScheduleOtherData), m_FreeSatScheduleOtherConn2);
1545                 m_FreeSatScheduleOtherReader2->start(mask);
1546                 isRunning |= FREESAT_SCHEDULE_OTHER;
1547         }
1548 #endif
1549         mask.pid = 0x12;
1550         mask.flags = eDVBSectionFilterMask::rfCRC;
1551
1552         if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::NOWNEXT)
1553         {
1554                 mask.data[0] = 0x4E;
1555                 mask.mask[0] = 0xFE;
1556                 m_NowNextReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::NOWNEXT), m_NowNextConn);
1557                 m_NowNextReader->start(mask);
1558                 isRunning |= NOWNEXT;
1559         }
1560
1561         if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::SCHEDULE)
1562         {
1563                 mask.data[0] = 0x50;
1564                 mask.mask[0] = 0xF0;
1565                 m_ScheduleReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::SCHEDULE), m_ScheduleConn);
1566                 m_ScheduleReader->start(mask);
1567                 isRunning |= SCHEDULE;
1568         }
1569
1570         if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::SCHEDULE_OTHER)
1571         {
1572                 mask.data[0] = 0x60;
1573                 mask.mask[0] = 0xF0;
1574                 m_ScheduleOtherReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::SCHEDULE_OTHER), m_ScheduleOtherConn);
1575                 m_ScheduleOtherReader->start(mask);
1576                 isRunning |= SCHEDULE_OTHER;
1577         }
1578
1579 #ifdef ENABLE_VIRGIN
1580         if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::VIRGIN_NOWNEXT)
1581         {
1582                 mask.pid = 0x2bc;
1583                 mask.data[0] = 0x4E;
1584                 mask.mask[0] = 0xFE;
1585                 m_VirginNowNextReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::VIRGIN_NOWNEXT), m_VirginNowNextConn);
1586                 m_VirginNowNextReader->start(mask);
1587                 isRunning |= VIRGIN_NOWNEXT;
1588         }
1589
1590         if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::VIRGIN_SCHEDULE)
1591         {
1592                 mask.pid = 0x2bc;
1593                 mask.data[0] = 0x50;
1594                 mask.mask[0] = 0xFE;
1595                 m_VirginScheduleReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::VIRGIN_SCHEDULE), m_VirginScheduleConn);
1596                 m_VirginScheduleReader->start(mask);
1597                 isRunning |= VIRGIN_SCHEDULE;
1598         }
1599 #endif
1600 #ifdef ENABLE_NETMED
1601         if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::NETMED_SCHEDULE)
1602         {
1603                 mask.pid = 0x1388;
1604                 mask.data[0] = 0x50;
1605                 mask.mask[0] = 0xF0;
1606                 m_NetmedScheduleReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::NETMED_SCHEDULE), m_NetmedScheduleConn);
1607                 m_NetmedScheduleReader->start(mask);
1608                 isRunning |= NETMED_SCHEDULE;
1609         }
1610
1611         if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::NETMED_SCHEDULE_OTHER)
1612         {
1613                 mask.pid = 0x1388;
1614                 mask.data[0] = 0x60;
1615                 mask.mask[0] = 0xF0;
1616                 m_NetmedScheduleOtherReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::NETMED_SCHEDULE_OTHER), m_NetmedScheduleOtherConn);
1617                 m_NetmedScheduleOtherReader->start(mask);
1618                 isRunning |= NETMED_SCHEDULE_OTHER;
1619         }
1620 #endif
1621         if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::VIASAT)
1622         {
1623                 mask.pid = 0x39;
1624
1625                 mask.data[0] = 0x40;
1626                 mask.mask[0] = 0x40;
1627                 m_ViasatReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::VIASAT), m_ViasatConn);
1628                 m_ViasatReader->start(mask);
1629                 isRunning |= VIASAT;
1630         }
1631
1632         abortTimer->start(7000,true);
1633 }
1634
1635 void eEPGCache::channel_data::abortNonAvail()
1636 {
1637         if (!state)
1638         {
1639                 if ( !(haveData&NOWNEXT) && (isRunning&NOWNEXT) )
1640                 {
1641                         eDebug("[eEPGCache] abort non avail nownext reading");
1642                         isRunning &= ~NOWNEXT;
1643                         m_NowNextReader->stop();
1644                         m_NowNextConn=0;
1645                 }
1646                 if ( !(haveData&SCHEDULE) && (isRunning&SCHEDULE) )
1647                 {
1648                         eDebug("[eEPGCache] abort non avail schedule reading");
1649                         isRunning &= ~SCHEDULE;
1650                         m_ScheduleReader->stop();
1651                         m_ScheduleConn=0;
1652                 }
1653                 if ( !(haveData&SCHEDULE_OTHER) && (isRunning&SCHEDULE_OTHER) )
1654                 {
1655                         eDebug("[eEPGCache] abort non avail schedule other reading");
1656                         isRunning &= ~SCHEDULE_OTHER;
1657                         m_ScheduleOtherReader->stop();
1658                         m_ScheduleOtherConn=0;
1659                 }
1660 #ifdef ENABLE_VIRGIN
1661                 if ( !(haveData&VIRGIN_NOWNEXT) && (isRunning&VIRGIN_NOWNEXT) )
1662                 {
1663                         eDebug("[eEPGCache] abort non avail virgin nownext reading");
1664                         isRunning &= ~VIRGIN_NOWNEXT;
1665                         m_VirginNowNextReader->stop();
1666                         m_VirginNowNextConn=0;
1667                 }
1668                 if ( !(haveData&VIRGIN_SCHEDULE) && (isRunning&VIRGIN_SCHEDULE) )
1669                 {
1670                         eDebug("[eEPGCache] abort non avail virgin schedule reading");
1671                         isRunning &= ~VIRGIN_SCHEDULE;
1672                         m_VirginScheduleReader->stop();
1673                         m_VirginScheduleConn=0;
1674                 }
1675 #endif
1676 #ifdef ENABLE_NETMED
1677                 if ( !(haveData&NETMED_SCHEDULE) && (isRunning&NETMED_SCHEDULE) )
1678                 {
1679                         eDebug("[eEPGCache] abort non avail netmed schedule reading");
1680                         isRunning &= ~NETMED_SCHEDULE;
1681                         m_NetmedScheduleReader->stop();
1682                         m_NetmedScheduleConn=0;
1683                 }
1684                 if ( !(haveData&NETMED_SCHEDULE_OTHER) && (isRunning&NETMED_SCHEDULE_OTHER) )
1685                 {
1686                         eDebug("[eEPGCache] abort non avail netmed schedule other reading");
1687                         isRunning &= ~NETMED_SCHEDULE_OTHER;
1688                         m_NetmedScheduleOtherReader->stop();
1689                         m_NetmedScheduleOtherConn=0;
1690                 }
1691 #endif
1692 #ifdef ENABLE_FREESAT
1693                 if ( !(haveData&FREESAT_SCHEDULE_OTHER) && (isRunning&FREESAT_SCHEDULE_OTHER) )
1694                 {
1695                         eDebug("[eEPGCache] abort non avail FreeSat schedule_other reading");
1696                         isRunning &= ~FREESAT_SCHEDULE_OTHER;
1697                         m_FreeSatScheduleOtherReader->stop();
1698                         m_FreeSatScheduleOtherReader2->stop();
1699                         m_FreeSatScheduleOtherConn=0;
1700                         m_FreeSatScheduleOtherConn2=0;
1701                         cleanupFreeSat();
1702                 }
1703 #endif
1704                 if ( !(haveData&VIASAT) && (isRunning&VIASAT) )
1705                 {
1706                         eDebug("[eEPGCache] abort non avail viasat reading");
1707                         isRunning &= ~VIASAT;
1708                         m_ViasatReader->stop();
1709                         m_ViasatConn=0;
1710                 }
1711 #ifdef ENABLE_MHW_EPG
1712                 if ( !(haveData&MHW) && (isRunning&MHW) )
1713                 {
1714                         eDebug("[eEPGCache] abort non avail mhw reading");
1715                         isRunning &= ~MHW;
1716                         m_MHWReader->stop();
1717                         m_MHWConn=0;
1718                         m_MHWReader2->stop();
1719                         m_MHWConn2=0;
1720                 }
1721 #endif
1722                 if ( isRunning & VIASAT )
1723                         abortTimer->start(300000, true);
1724                 else if ( isRunning )
1725                         abortTimer->start(90000, true);
1726                 else
1727                 {
1728                         ++state;
1729                         for (unsigned int i=0; i < sizeof(seenSections)/sizeof(tidMap); ++i)
1730                         {
1731                                 seenSections[i].clear();
1732                                 calcedSections[i].clear();
1733                         }
1734 #ifdef ENABLE_MHW_EPG
1735                         cleanupMHW();
1736 #endif
1737 #ifdef ENABLE_FREESAT
1738                         cleanupFreeSat();
1739 #endif
1740                 }
1741         }
1742         ++state;
1743 }
1744
1745 void eEPGCache::channel_data::startChannel()
1746 {
1747         pthread_mutex_lock(&channel_active);
1748         updateMap::iterator It = cache->channelLastUpdated.find( channel->getChannelID() );
1749
1750         int update = ( It != cache->channelLastUpdated.end() ? ( UPDATE_INTERVAL - ( (::time(0)-It->second) * 1000 ) ) : ZAP_DELAY );
1751
1752         if (update < ZAP_DELAY)
1753                 update = ZAP_DELAY;
1754
1755         zapTimer->start(update, 1);
1756         if (update >= 60000)
1757                 eDebug("[eEPGCache] next update in %i min", update/60000);
1758         else if (update >= 1000)
1759                 eDebug("[eEPGCache] next update in %i sec", update/1000);
1760 }
1761
1762 void eEPGCache::channel_data::abortEPG()
1763 {
1764         for (unsigned int i=0; i < sizeof(seenSections)/sizeof(tidMap); ++i)
1765         {
1766                 seenSections[i].clear();
1767                 calcedSections[i].clear();
1768         }
1769 #ifdef ENABLE_MHW_EPG
1770         cleanupMHW();
1771 #endif
1772 #ifdef ENABLE_FREESAT
1773         cleanupFreeSat();
1774 #endif
1775         abortTimer->stop();
1776         zapTimer->stop();
1777         if (isRunning)
1778         {
1779                 eDebug("[eEPGCache] abort caching events !!");
1780                 if (isRunning & SCHEDULE)
1781                 {
1782                         isRunning &= ~SCHEDULE;
1783                         m_ScheduleReader->stop();
1784                         m_ScheduleConn=0;
1785                 }
1786                 if (isRunning & NOWNEXT)
1787                 {
1788                         isRunning &= ~NOWNEXT;
1789                         m_NowNextReader->stop();
1790                         m_NowNextConn=0;
1791                 }
1792                 if (isRunning & SCHEDULE_OTHER)
1793                 {
1794                         isRunning &= ~SCHEDULE_OTHER;
1795                         m_ScheduleOtherReader->stop();
1796                         m_ScheduleOtherConn=0;
1797                 }
1798 #ifdef ENABLE_VIRGIN
1799                 if (isRunning & VIRGIN_NOWNEXT)
1800                 {
1801                         isRunning &= ~VIRGIN_NOWNEXT;
1802                         m_VirginNowNextReader->stop();
1803                         m_VirginNowNextConn=0;
1804                 }
1805                 if (isRunning & VIRGIN_SCHEDULE)
1806                 {
1807                         isRunning &= ~VIRGIN_SCHEDULE;
1808                         m_VirginScheduleReader->stop();
1809                         m_VirginScheduleConn=0;
1810                 }
1811 #endif
1812 #ifdef ENABLE_NETMED
1813                 if (isRunning & NETMED_SCHEDULE)
1814                 {
1815                         isRunning &= ~NETMED_SCHEDULE;
1816                         m_NetmedScheduleReader->stop();
1817                         m_NetmedScheduleConn=0;
1818                 }
1819                 if (isRunning & NETMED_SCHEDULE_OTHER)
1820                 {
1821                         isRunning &= ~NETMED_SCHEDULE_OTHER;
1822                         m_NetmedScheduleOtherReader->stop();
1823                         m_NetmedScheduleOtherConn=0;
1824                 }
1825 #endif
1826 #ifdef ENABLE_FREESAT
1827                 if (isRunning & FREESAT_SCHEDULE_OTHER)
1828                 {
1829                         isRunning &= ~FREESAT_SCHEDULE_OTHER;
1830                         m_FreeSatScheduleOtherReader->stop();
1831                         m_FreeSatScheduleOtherReader2->stop();
1832                         m_FreeSatScheduleOtherConn=0;
1833                         m_FreeSatScheduleOtherConn2=0;
1834                 }
1835 #endif
1836                 if (isRunning & VIASAT)
1837                 {
1838                         isRunning &= ~VIASAT;
1839                         m_ViasatReader->stop();
1840                         m_ViasatConn=0;
1841                 }
1842 #ifdef ENABLE_MHW_EPG
1843                 if (isRunning & MHW)
1844                 {
1845                         isRunning &= ~MHW;
1846                         m_MHWReader->stop();
1847                         m_MHWConn=0;
1848                         m_MHWReader2->stop();
1849                         m_MHWConn2=0;
1850                 }
1851 #endif
1852         }
1853 #ifdef ENABLE_PRIVATE_EPG
1854         if (m_PrivateReader)
1855                 m_PrivateReader->stop();
1856         if (m_PrivateConn)
1857                 m_PrivateConn=0;
1858 #endif
1859         pthread_mutex_unlock(&channel_active);
1860 }
1861
1862 void eEPGCache::channel_data::readData( const uint8_t *data, int source)
1863 {
1864         int map;
1865         iDVBSectionReader *reader = NULL;
1866         switch (source)
1867         {
1868                 case NOWNEXT:
1869                         reader = m_NowNextReader;
1870                         map = 0;
1871                         break;
1872                 case SCHEDULE:
1873                         reader = m_ScheduleReader;
1874                         map = 1;
1875                         break;
1876                 case SCHEDULE_OTHER:
1877                         reader = m_ScheduleOtherReader;
1878                         map = 2;
1879                         break;
1880                 case VIASAT:
1881                         reader = m_ViasatReader;
1882                         map = 3;
1883                         break;
1884 #ifdef ENABLE_NETMED
1885                 case NETMED_SCHEDULE:
1886                         reader = m_NetmedScheduleReader;
1887                         map = 1;
1888                         break;
1889                 case NETMED_SCHEDULE_OTHER:
1890                         reader = m_NetmedScheduleOtherReader;
1891                         map = 2;
1892                         break;
1893 #endif
1894 #ifdef ENABLE_VIRGIN
1895                 case VIRGIN_NOWNEXT:
1896                         reader = m_VirginNowNextReader;
1897                         map = 0;
1898                         break;
1899                 case VIRGIN_SCHEDULE:
1900                         reader = m_VirginScheduleReader;
1901                         map = 1;
1902                         break;
1903 #endif
1904                 default:
1905                         eDebug("[eEPGCache] unknown source");
1906                         return;
1907         }
1908         tidMap &seenSections = this->seenSections[map];
1909         tidMap &calcedSections = this->calcedSections[map];
1910         if ( (state == 1 && calcedSections == seenSections) || state > 1 )
1911         {
1912                 eDebugNoNewLine("[eEPGCache] ");
1913                 switch (source)
1914                 {
1915                         case NOWNEXT:
1916                                 m_NowNextConn=0;
1917                                 eDebugNoNewLine("nownext");
1918                                 break;
1919                         case SCHEDULE:
1920                                 m_ScheduleConn=0;
1921                                 eDebugNoNewLine("schedule");
1922                                 break;
1923                         case SCHEDULE_OTHER:
1924                                 m_ScheduleOtherConn=0;
1925                                 eDebugNoNewLine("schedule other");
1926                                 break;
1927                         case VIASAT:
1928                                 m_ViasatConn=0;
1929                                 eDebugNoNewLine("viasat");
1930                                 break;
1931 #ifdef ENABLE_NETMED
1932                         case NETMED_SCHEDULE:
1933                                 m_NetmedScheduleConn=0;
1934                                 eDebugNoNewLine("netmed schedule");
1935                                 break;
1936                         case NETMED_SCHEDULE_OTHER:
1937                                 m_NetmedScheduleOtherConn=0;
1938                                 eDebugNoNewLine("netmed schedule other");
1939                                 break;
1940 #endif
1941 #ifdef ENABLE_VIRGIN
1942                         case VIRGIN_NOWNEXT:
1943                                 m_VirginNowNextConn=0;
1944                                 eDebugNoNewLine("virgin nownext");
1945                                 break;
1946                         case VIRGIN_SCHEDULE:
1947                                 m_VirginScheduleConn=0;
1948                                 eDebugNoNewLine("virgin schedule");
1949                                 break;
1950 #endif
1951                         default: eDebugNoNewLine("unknown");break;
1952                 }
1953                 eDebugNoNewLine(" finished(%ld)\n", ::time(0));
1954                 if ( reader )
1955                         reader->stop();
1956                 isRunning &= ~source;
1957                 if (!isRunning)
1958                         finishEPG();
1959         }
1960         else
1961         {
1962                 eit_t *eit = (eit_t*) data;
1963                 uint32_t sectionNo = data[0] << 24;
1964                 sectionNo |= data[3] << 16;
1965                 sectionNo |= data[4] << 8;
1966                 sectionNo |= eit->section_number;
1967
1968                 tidMap::iterator it =
1969                         seenSections.find(sectionNo);
1970
1971                 if ( it == seenSections.end() )
1972                 {
1973                         seenSections.insert(sectionNo);
1974                         calcedSections.insert(sectionNo);
1975                         uint32_t tmpval = sectionNo & 0xFFFFFF00;
1976                         uint8_t incr = source == NOWNEXT ? 1 : 8;
1977                         for ( int i = 0; i <= eit->last_section_number; i+=incr )
1978                         {
1979                                 if ( i == eit->section_number )
1980                                 {
1981                                         for (int x=i; x <= eit->segment_last_section_number; ++x)
1982                                         {
1983                                                 calcedSections.insert(tmpval|(x&0xFF));
1984                                         }
1985                                 }
1986                                 else
1987                                 {
1988                                         calcedSections.insert(tmpval|(i&0xFF));
1989                                 }
1990                         }
1991                         cache->sectionRead(data, source, this);
1992                 }
1993         }
1994 }
1995
1996 #if ENABLE_FREESAT
1997
1998 freesatEITSubtableStatus::freesatEITSubtableStatus(u_char version, uint8_t maxSection) : version(version)
1999 {
2000         initMap(maxSection);
2001 }
2002
2003 void freesatEITSubtableStatus::initMap(uint8_t maxSection)
2004 {
2005         int i, maxSectionIdx = maxSection / 8;
2006         for (i = 0; i < 32; i++)
2007         {
2008                 sectionMap[i] = (i <= maxSectionIdx ? 0x0100 : 0x0000 );
2009         }
2010 }
2011
2012 bool freesatEITSubtableStatus::isSectionPresent(uint8_t sectionNo)
2013 {
2014         uint8_t sectionIdx = sectionNo / 8;
2015         uint8_t bitOffset = sectionNo % 8;
2016
2017         return ((sectionMap[sectionIdx] & (1 << bitOffset)) != 0);
2018 }
2019
2020 bool freesatEITSubtableStatus::isCompleted()
2021 {
2022         uint32_t i = 0;
2023         uint8_t calc;
2024
2025         while ( i < 32 )
2026         {
2027                 calc = sectionMap[i] >> 8;
2028                 if (! calc) return true; // Last segment passed
2029                 if (calc ^ ( sectionMap[i] & 0xFF ) ) // Segment not fully found
2030                         return false;
2031                 i++;
2032         }
2033         return true; // All segments ok
2034 }
2035
2036 void freesatEITSubtableStatus::seen(uint8_t sectionNo, uint8_t maxSegmentSection)
2037 {
2038         uint8_t sectionIdx = sectionNo / 8;
2039         uint8_t bitOffset = sectionNo % 8;
2040         uint8_t maxBitOffset = maxSegmentSection % 8;
2041
2042         sectionMap[sectionIdx] &= 0x00FF; // Clear calc map
2043         sectionMap[sectionIdx] |= ((0x01FF << maxBitOffset) & 0xFF00); // Set calc map
2044         sectionMap[sectionIdx] |= (1 << bitOffset); // Set seen map
2045 }
2046
2047 bool freesatEITSubtableStatus::isVersionChanged(u_char testVersion)
2048 {
2049         return version != testVersion;
2050 }
2051
2052 void freesatEITSubtableStatus::updateVersion(u_char newVersion, uint8_t maxSection)
2053 {
2054         version = newVersion;
2055         initMap(maxSection);
2056 }
2057
2058 void eEPGCache::channel_data::cleanupFreeSat()
2059 {
2060         m_FreeSatSubTableStatus.clear();
2061         m_FreesatTablesToComplete = 0;
2062 }
2063
2064 void eEPGCache::channel_data::readFreeSatScheduleOtherData( const uint8_t *data)
2065 {
2066         eit_t *eit = (eit_t*) data;
2067         uint32_t subtableNo = data[0] << 24; // Table ID
2068         subtableNo |= data[3] << 16; // Service ID Hi
2069         subtableNo |= data[4] << 8; // Service ID Lo
2070
2071         // Check for sub-table version in map
2072         std::map<uint32_t, freesatEITSubtableStatus> &freeSatSubTableStatus = this->m_FreeSatSubTableStatus;
2073         std::map<uint32_t, freesatEITSubtableStatus>::iterator itmap = freeSatSubTableStatus.find(subtableNo);
2074
2075         freesatEITSubtableStatus *fsstatus;
2076         if ( itmap == freeSatSubTableStatus.end() )
2077         {
2078                 // New sub table. Store version.
2079                 //eDebug("[eEPGCache] New subtable (%x) version (%d) now/next (%d) tsid (%x/%x) onid (%x/%x)", subtableNo, eit->version_number, eit->current_next_indicator, eit->transport_stream_id_hi, eit->transport_stream_id_lo, eit->original_network_id_hi, eit->original_network_id_lo);
2080                 fsstatus = new freesatEITSubtableStatus(eit->version_number, eit->last_section_number);
2081                 m_FreesatTablesToComplete++;
2082                 freeSatSubTableStatus.insert(std::pair<uint32_t,freesatEITSubtableStatus>(subtableNo, *fsstatus));
2083         }
2084         else
2085         {
2086                 fsstatus = &itmap->second;
2087                 // Existing subtable. Check version. Should check current / next as well? Seems to always be current for Freesat
2088                 if ( fsstatus->isVersionChanged(eit->version_number) )
2089                 {
2090                         eDebug("[eEPGCache] FS subtable (%x) version changed (%d) now/next (%d)", subtableNo, eit->version_number, eit->current_next_indicator);
2091                         m_FreesatTablesToComplete++;
2092                         fsstatus->updateVersion(eit->version_number, eit->last_section_number);
2093                 }
2094                 else
2095                 {
2096                         if ( fsstatus->isSectionPresent(eit->section_number) )
2097                         {
2098 //                              eDebug("[eEPGCache] DUP FS sub/sec/ver (%x/%d/%d)", subtableNo, eit->section_number, eit->version_number);
2099                                 return;
2100                         }
2101                 }
2102         }
2103
2104 //      eDebug("[eEPGCache] New FS sub/sec/ls/lss/ver (%x/%d/%d/%d/%d)", subtableNo, eit->section_number, eit->last_section_number, eit->segment_last_section_number, eit->version_number);
2105         fsstatus->seen(eit->section_number, eit->segment_last_section_number);
2106         if (fsstatus->isCompleted())
2107         {
2108                 m_FreesatTablesToComplete--;
2109         }
2110         cache->sectionRead(data, FREESAT_SCHEDULE_OTHER, this);
2111 }
2112 #endif
2113
2114 RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, const eventData *&result, int direction)
2115 // if t == -1 we search the current event...
2116 {
2117         uniqueEPGKey key(handleGroup(service));
2118
2119         // check if EPG for this service is ready...
2120         eventCache::iterator It = eventDB.find( key );
2121         if ( It != eventDB.end() && !It->second.byEvent.empty() ) // entrys cached ?
2122         {
2123                 if (t==-1)
2124                         t = ::time(0);
2125                 timeMap::iterator i = direction <= 0 ? It->second.byTime.lower_bound(t) :  // find > or equal
2126                         It->second.byTime.upper_bound(t); // just >
2127                 if ( i != It->second.byTime.end() )
2128                 {
2129                         if ( direction < 0 || (direction == 0 && i->first > t) )
2130                         {
2131                                 timeMap::iterator x = i;
2132                                 --x;
2133                                 if ( x != It->second.byTime.end() )
2134                                 {
2135                                         time_t start_time = x->first;
2136                                         if (direction >= 0)
2137                                         {
2138                                                 if (t < start_time)
2139                                                         return -1;
2140                                                 if (t > (start_time+x->second->getDuration()))
2141                                                         return -1;
2142                                         }
2143                                         i = x;
2144                                 }
2145                                 else
2146                                         return -1;
2147                         }
2148                         result = i->second;
2149                         return 0;
2150                 }
2151         }
2152         return -1;
2153 }
2154
2155 RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, Event *& result, int direction)
2156 {
2157         singleLock s(cache_lock);
2158         const eventData *data=0;
2159         RESULT ret = lookupEventTime(service, t, data, direction);
2160         if ( !ret && data )
2161                 result = new Event((uint8_t*)data->get());
2162         return ret;
2163 }
2164
2165 RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, ePtr<eServiceEvent> &result, int direction)
2166 {
2167         singleLock s(cache_lock);
2168         const eventData *data=0;
2169         RESULT ret = lookupEventTime(service, t, data, direction);
2170         result = NULL;
2171         if ( !ret && data )
2172         {
2173                 Event ev((uint8_t*)data->get());
2174                 result = new eServiceEvent();
2175                 const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)service;
2176                 ret = result->parseFrom(&ev, (ref.getTransportStreamID().get()<<16)|ref.getOriginalNetworkID().get());
2177         }
2178         return ret;
2179 }
2180
2181 RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, const eventData *&result )
2182 {
2183         uniqueEPGKey key(handleGroup(service));
2184
2185         eventCache::iterator It = eventDB.find(key);
2186         if (It != eventDB.end())
2187         {
2188                 eventMap::iterator i = It->second.byEvent.find(event_id);
2189                 if ( i != It->second.byEvent.end() )
2190                 {
2191                         result = i->second;
2192                         return 0;
2193                 }
2194                 else
2195                 {
2196                         result = 0;
2197                         eDebug("[eEPGCache] event %04x not found in epgcache", event_id);
2198                 }
2199         }
2200         return -1;
2201 }
2202
2203 RESULT eEPGCache::saveEventToFile(const char* filename, const eServiceReference &service, int eit_event_id, time_t begTime, time_t endTime)
2204 {
2205         RESULT ret = -1;
2206         singleLock s(cache_lock);
2207         const eventData *data = NULL;
2208         if ( eit_event_id != -1 )
2209         {
2210                 eDebug("[eEPGCache] %s epg event id %x", __func__, eit_event_id);
2211                 ret = lookupEventId(service, eit_event_id, data);
2212         }
2213         if ( (ret != 0) && (begTime != -1) )
2214         {
2215                 time_t queryTime = begTime;
2216                 if (endTime != -1)
2217                         queryTime += (endTime - begTime) / 2;
2218                 ret = lookupEventTime(service, queryTime, data);
2219         }
2220         if (ret == 0)
2221         {
2222                 int fd = open(filename, O_CREAT|O_WRONLY, 0666);
2223                 if (fd < 0)
2224                 {
2225                         eDebug("[eEPGCache] Failed to create file: %s", filename);
2226                         return fd;
2227                 }
2228                 const eit_event_struct *event = data->get();
2229                 int evLen = event->getDescriptorsLoopLength() + 12/*EIT_LOOP_SIZE*/;
2230                 int wr = ::write( fd, event, evLen );
2231                 ::close(fd);
2232                 if ( wr != evLen )
2233                 {
2234                         ::unlink(filename); /* Remove faulty file */
2235                         eDebug("[eEPGCache] eit write error on %s: %m", filename);
2236                         ret = (wr < 0) ? wr : -1;
2237                 }
2238         }
2239         return ret;
2240 }
2241
2242 RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, Event *& result)
2243 {
2244         singleLock s(cache_lock);
2245         const eventData *data=0;
2246         RESULT ret = lookupEventId(service, event_id, data);
2247         if ( !ret && data )
2248                 result = new Event((uint8_t*)data->get());
2249         return ret;
2250 }
2251
2252 RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, ePtr<eServiceEvent> &result)
2253 {
2254         singleLock s(cache_lock);
2255         const eventData *data=0;
2256         RESULT ret = lookupEventId(service, event_id, data);
2257         result = NULL;
2258         if ( !ret && data )
2259         {
2260                 Event ev((uint8_t*)data->get());
2261                 result = new eServiceEvent();
2262                 const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)service;
2263                 ret = result->parseFrom(&ev, (ref.getTransportStreamID().get()<<16)|ref.getOriginalNetworkID().get());
2264         }
2265         return ret;
2266 }
2267
2268 RESULT eEPGCache::startTimeQuery(const eServiceReference &service, time_t begin, int minutes)
2269 {
2270         singleLock s(cache_lock);
2271         const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)handleGroup(service);
2272         if (begin == -1)
2273                 begin = ::time(0);
2274         eventCache::iterator It = eventDB.find(ref);
2275         if ( It != eventDB.end() && !It->second.byTime.empty() )
2276         {
2277                 m_timemap_cursor = It->second.byTime.lower_bound(begin);
2278                 if ( m_timemap_cursor != It->second.byTime.end() )
2279                 {
2280                         if ( m_timemap_cursor->first != begin )
2281                         {
2282                                 timeMap::iterator x = m_timemap_cursor;
2283                                 --x;
2284                                 if ( x != It->second.byTime.end() )
2285                                 {
2286                                         time_t start_time = x->first;
2287                                         if ( begin > start_time && begin < (start_time+x->second->getDuration()))
2288                                                 m_timemap_cursor = x;
2289                                 }
2290                         }
2291                 }
2292
2293                 if (minutes != -1)
2294                         m_timemap_end = It->second.byTime.lower_bound(begin+minutes*60);
2295                 else
2296                         m_timemap_end = It->second.byTime.end();
2297
2298                 currentQueryTsidOnid = (ref.getTransportStreamID().get()<<16) | ref.getOriginalNetworkID().get();
2299                 return m_timemap_cursor == m_timemap_end ? -1 : 0;
2300         }
2301         return -1;
2302 }
2303
2304 RESULT eEPGCache::getNextTimeEntry(Event *&result)
2305 {
2306         if ( m_timemap_cursor != m_timemap_end )
2307         {
2308                 result = new Event((uint8_t*)m_timemap_cursor++->second->get());
2309                 return 0;
2310         }
2311         return -1;
2312 }
2313
2314 RESULT eEPGCache::getNextTimeEntry(ePtr<eServiceEvent> &result)
2315 {
2316         if ( m_timemap_cursor != m_timemap_end )
2317         {
2318                 Event ev((uint8_t*)m_timemap_cursor++->second->get());
2319                 result = new eServiceEvent();
2320                 return result->parseFrom(&ev, currentQueryTsidOnid);
2321         }
2322         return -1;
2323 }
2324
2325 void fillTuple(ePyObject tuple, const char *argstring, int argcount, ePyObject service_reference, eServiceEvent *ptr, ePyObject service_name, ePyObject nowTime, eventData *evData )
2326 {
2327         //eDebug("[eEPGCache] fillTuple arg=%s argcnt=%d, ptr=%d evData=%d", argstring, argcount, ptr ? 1 : 0, evData ? 1 : 0);
2328         ePyObject tmp;
2329         int spos=0, tpos=0;
2330         char c;
2331         while(spos < argcount)
2332         {
2333                 bool inc_refcount=false;
2334                 switch((c=argstring[spos++]))
2335                 {
2336                         case '0': // PyLong 0
2337                                 tmp = PyLong_FromLong(0);
2338                                 break;
2339                         case 'I': // Event Id
2340                                 tmp = evData ? PyLong_FromLong(evData->getEventID()) : (ptr ? PyLong_FromLong(ptr->getEventId()) : ePyObject());
2341                                 break;
2342                         case 'B': // Event Begin Time
2343                                 tmp = ptr ? PyLong_FromLong(ptr->getBeginTime()) : (evData ? PyLong_FromLong(evData->getStartTime()) : ePyObject());
2344                                 break;
2345                         case 'D': // Event Duration
2346                                 tmp = ptr ? PyLong_FromLong(ptr->getDuration()) : (evData ? PyLong_FromLong(evData->getDuration()) : ePyObject());
2347                                 break;
2348                         case 'T': // Event Title
2349                                 tmp = ptr ? PyString_FromString(ptr->getEventName().c_str()) : ePyObject();
2350                                 break;
2351                         case 'S': // Event Short Description
2352                                 tmp = ptr ? PyString_FromString(ptr->getShortDescription().c_str()) : ePyObject();
2353                                 break;
2354                         case 'E': // Event Extended Description
2355                                 tmp = ptr ? PyString_FromString(ptr->getExtendedDescription().c_str()) : ePyObject();
2356                                 break;
2357                         case 'P': // Event Parental Rating
2358                                 tmp = ptr ? ePyObject(ptr->getParentalData()) : ePyObject();
2359                                 break;
2360                         case 'W': // Event Content Description
2361                                 tmp = ptr ? ePyObject(ptr->getGenreData()) : ePyObject();
2362                                 break;
2363                         case 'C': // Current Time
2364                                 tmp = nowTime;
2365                                 inc_refcount = true;
2366                                 break;
2367                         case 'R': // service reference string
2368                                 tmp = service_reference;
2369                                 inc_refcount = true;
2370                                 break;
2371                         case 'n': // short service name
2372                         case 'N': // service name
2373                                 tmp = service_name;
2374                                 inc_refcount = true;
2375                                 break;
2376                         case 'X':
2377                                 ++argcount;
2378                                 continue;
2379                         default:  // ignore unknown
2380                                 tmp = ePyObject();
2381                                 eDebug("[eEPGCache] fillTuple unknown '%c'... insert 'None' in result", c);
2382                 }
2383                 if (!tmp)
2384                 {
2385                         tmp = Py_None;
2386                         inc_refcount = true;
2387                 }
2388                 if (inc_refcount)
2389                         Py_INCREF(tmp);
2390                 PyTuple_SET_ITEM(tuple, tpos++, tmp);
2391         }
2392 }
2393
2394 int handleEvent(eServiceEvent *ptr, ePyObject dest_list, const char* argstring, int argcount, ePyObject service, ePyObject nowTime, ePyObject service_name, ePyObject convertFunc, ePyObject convertFuncArgs)
2395 {
2396         if (convertFunc)
2397         {
2398                 fillTuple(convertFuncArgs, argstring, argcount, service, ptr, service_name, nowTime, 0);
2399                 ePyObject result = PyObject_CallObject(convertFunc, convertFuncArgs);
2400                 if (!result)
2401                 {
2402                         if (service_name)
2403                                 Py_DECREF(service_name);
2404                         if (nowTime)
2405                                 Py_DECREF(nowTime);
2406                         Py_DECREF(convertFuncArgs);
2407                         Py_DECREF(dest_list);
2408                         PyErr_SetString(PyExc_StandardError,
2409                                 "error in convertFunc execute");
2410                         eDebug("[eEPGCache] handleEvent: error in convertFunc execute");
2411                         return -1;
2412                 }
2413                 PyList_Append(dest_list, result);
2414                 Py_DECREF(result);
2415         }
2416         else
2417         {
2418                 ePyObject tuple = PyTuple_New(argcount);
2419                 fillTuple(tuple, argstring, argcount, service, ptr, service_name, nowTime, 0);
2420                 PyList_Append(dest_list, tuple);
2421                 Py_DECREF(tuple);
2422         }
2423         return 0;
2424 }
2425
2426 // here we get a python list
2427 // the first entry in the list is a python string to specify the format of the returned tuples (in a list)
2428 //   0 = PyLong(0)
2429 //   I = Event Id
2430 //   B = Event Begin Time
2431 //   D = Event Duration
2432 //   T = Event Title
2433 //   S = Event Short Description
2434 //   E = Event Extended Description
2435 //   P = Event Parental Rating
2436 //   W = Event Content Description ('W'hat)
2437 //   C = Current Time
2438 //   R = Service Reference
2439 //   N = Service Name
2440 //   n = Short Service Name
2441 //   X = Return a minimum of one tuple per service in the result list... even when no event was found.
2442 //       The returned tuple is filled with all available infos... non avail is filled as None
2443 //       The position and existence of 'X' in the format string has no influence on the result tuple... its completely ignored..
2444 // then for each service follows a tuple
2445 //   first tuple entry is the servicereference (as string... use the ref.toString() function)
2446 //   the second is the type of query
2447 //     2 = event_id
2448 //    -1 = event before given start_time
2449 //     0 = event intersects given start_time
2450 //    +1 = event after given start_time
2451 //   the third
2452 //      when type is eventid it is the event_id
2453 //      when type is time then it is the start_time ( -1 for now_time )
2454 //   the fourth is the end_time .. ( optional .. for query all events in time range)
2455
2456 PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc)
2457 {
2458         ePyObject convertFuncArgs;
2459         int argcount=0;
2460         const char *argstring=NULL;
2461         if (!PyList_Check(list))
2462         {
2463                 PyErr_SetString(PyExc_StandardError,
2464                         "type error");
2465                 eDebug("[eEPGCache] no list");
2466                 return NULL;
2467         }
2468         int listIt=0;
2469         int listSize=PyList_Size(list);
2470         if (!listSize)
2471         {
2472                 PyErr_SetString(PyExc_StandardError,
2473                         "no params given");
2474                 eDebug("[eEPGCache] no params given");
2475                 return NULL;
2476         }
2477         else
2478         {
2479                 ePyObject argv=PyList_GET_ITEM(list, 0); // borrowed reference!
2480                 if (PyString_Check(argv))
2481                 {
2482                         argstring = PyString_AS_STRING(argv);
2483                         ++listIt;
2484                 }
2485                 else
2486                         argstring = "I"; // just event id as default
2487                 argcount = strlen(argstring);
2488 //              eDebug("[eEPGCache] have %d args('%s')", argcount, argstring);
2489         }
2490
2491         bool forceReturnOne = strchr(argstring, 'X') ? true : false;
2492         if (forceReturnOne)
2493                 --argcount;
2494
2495         if (convertFunc)
2496         {
2497                 if (!PyCallable_Check(convertFunc))
2498                 {
2499                         PyErr_SetString(PyExc_StandardError,
2500                                 "convertFunc must be callable");
2501                         eDebug("[eEPGCache] convertFunc is not callable");
2502                         return NULL;
2503                 }
2504                 convertFuncArgs = PyTuple_New(argcount);
2505         }
2506
2507         ePyObject nowTime = strchr(argstring, 'C') ?
2508                 PyLong_FromLong(::time(0)) :
2509                 ePyObject();
2510
2511         int must_get_service_name = strchr(argstring, 'N') ? 1 : strchr(argstring, 'n') ? 2 : 0;
2512
2513         // create dest list
2514         ePyObject dest_list=PyList_New(0);
2515         while(listSize > listIt)
2516         {
2517                 ePyObject item=PyList_GET_ITEM(list, listIt++); // borrowed reference!
2518                 if (PyTuple_Check(item))
2519                 {
2520                         bool service_changed=false;
2521                         int type=0;
2522                         long event_id=-1;
2523                         time_t stime=-1;
2524                         int minutes=0;
2525                         int tupleSize=PyTuple_Size(item);
2526                         int tupleIt=0;
2527                         ePyObject service;
2528                         while(tupleSize > tupleIt)  // parse query args
2529                         {
2530                                 ePyObject entry=PyTuple_GET_ITEM(item, tupleIt); // borrowed reference!
2531                                 switch(tupleIt++)
2532                                 {
2533                                         case 0:
2534                                         {
2535                                                 if (!PyString_Check(entry))
2536                                                 {
2537                                                         eDebug("[eEPGCache] tuple entry 0 is no a string");
2538                                                         goto skip_entry;
2539                                                 }
2540                                                 service = entry;
2541                                                 break;
2542                                         }
2543                                         case 1:
2544                                                 type=PyInt_AsLong(entry);
2545                                                 if (type < -1 || type > 2)
2546                                                 {
2547                                                         eDebug("[eEPGCache] unknown type %d", type);
2548                                                         goto skip_entry;
2549                                                 }
2550                                                 break;
2551                                         case 2:
2552                                                 event_id=stime=PyInt_AsLong(entry);
2553                                                 break;
2554                                         case 3:
2555                                                 minutes=PyInt_AsLong(entry);
2556                                                 break;
2557                                         default:
2558                                                 eDebug("[eEPGCache] unneeded extra argument");
2559                                                 break;
2560                                 }
2561                         }
2562
2563                         if (minutes && stime == -1)
2564                                 stime = ::time(0);
2565
2566                         eServiceReference ref(handleGroup(eServiceReference(PyString_AS_STRING(service))));
2567                         // redirect subservice querys to parent service
2568                         eServiceReferenceDVB &dvb_ref = (eServiceReferenceDVB&)ref;
2569                         if (dvb_ref.getParentTransportStreamID().get()) // linkage subservice
2570                         {
2571                                 eServiceCenterPtr service_center;
2572                                 if (!eServiceCenter::getPrivInstance(service_center))
2573                                 {
2574                                         dvb_ref.setTransportStreamID( dvb_ref.getParentTransportStreamID() );
2575                                         dvb_ref.setServiceID( dvb_ref.getParentServiceID() );
2576                                         dvb_ref.setParentTransportStreamID(eTransportStreamID(0));
2577                                         dvb_ref.setParentServiceID(eServiceID(0));
2578                                         dvb_ref.name="";
2579                                         service = PyString_FromString(dvb_ref.toString().c_str());
2580                                         service_changed = true;
2581                                 }
2582                         }
2583
2584                         ePyObject service_name;
2585                         if (must_get_service_name)
2586                         {
2587                                 ePtr<iStaticServiceInformation> sptr;
2588                                 eServiceCenterPtr service_center;
2589                                 eServiceCenter::getPrivInstance(service_center);
2590                                 if (service_center)
2591                                 {
2592                                         service_center->info(ref, sptr);
2593                                         if (sptr)
2594                                         {
2595                                                 std::string name;
2596                                                 sptr->getName(ref, name);
2597
2598                                                 if (must_get_service_name == 1)
2599                                                 {
2600                                                         size_t pos;
2601                                                         // filter short name brakets
2602                                                         while((pos = name.find("\xc2\x86")) != std::string::npos)
2603                                                                 name.erase(pos,2);
2604                                                         while((pos = name.find("\xc2\x87")) != std::string::npos)
2605                                                                 name.erase(pos,2);
2606                                                 }
2607                                                 else
2608                                                         name = buildShortName(name);
2609
2610                                                 if (name.length())
2611                                                         service_name = PyString_FromString(name.c_str());
2612                                         }
2613                                 }
2614                                 if (!service_name)
2615                                         service_name = PyString_FromString("<n/a>");
2616                         }
2617                         if (minutes)
2618                         {
2619                                 singleLock s(cache_lock);
2620                                 if (!startTimeQuery(ref, stime, minutes))
2621                                 {
2622                                         while ( m_timemap_cursor != m_timemap_end )
2623                                         {
2624                                                 Event ev((uint8_t*)m_timemap_cursor++->second->get());
2625                                                 eServiceEvent evt;
2626                                                 evt.parseFrom(&ev, currentQueryTsidOnid);
2627                                                 if (handleEvent(&evt, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs))
2628                                                         return 0;  // error
2629                                         }
2630                                 }
2631                                 else if (forceReturnOne && handleEvent(0, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs))
2632                                         return 0;  // error
2633                         }
2634                         else
2635                         {
2636                                 eServiceEvent evt;
2637                                 const eventData *ev_data=0;
2638                                 if (stime)
2639                                 {
2640                                         singleLock s(cache_lock);
2641                                         if (type == 2)
2642                                                 lookupEventId(ref, event_id, ev_data);
2643                                         else
2644                                                 lookupEventTime(ref, stime, ev_data, type);
2645                                         if (ev_data)
2646                                         {
2647                                                 const eServiceReferenceDVB &dref = (const eServiceReferenceDVB&)ref;
2648                                                 Event ev((uint8_t*)ev_data->get());
2649                                                 evt.parseFrom(&ev, (dref.getTransportStreamID().get()<<16)|dref.getOriginalNetworkID().get());
2650                                         }
2651                                 }
2652                                 if (ev_data)
2653                                 {
2654                                         if (handleEvent(&evt, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs))
2655                                                 return 0; // error
2656                                 }
2657                                 else if (forceReturnOne && handleEvent(0, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs))
2658                                         return 0; // error
2659                         }
2660                         if (service_changed)
2661                                 Py_DECREF(service);
2662                         if (service_name)
2663                                 Py_DECREF(service_name);
2664                 }
2665 skip_entry:
2666                 ;
2667         }
2668         if (convertFuncArgs)
2669                 Py_DECREF(convertFuncArgs);
2670         if (nowTime)
2671                 Py_DECREF(nowTime);
2672         return dest_list;
2673 }
2674
2675 static void fill_eit_start(eit_event_struct *evt, time_t t)
2676 {
2677     tm *time = gmtime(&t);
2678
2679     int l = 0;
2680     int month = time->tm_mon + 1;
2681     if (month == 1 || month == 2)
2682         l = 1;
2683     int mjd = 14956 + time->tm_mday + (int)((time->tm_year - l) * 365.25) + (int)((month + 1 + l*12) * 30.6001);
2684     evt->start_time_1 = mjd >> 8;
2685     evt->start_time_2 = mjd & 0xFF;
2686
2687     evt->start_time_3 = toBCD(time->tm_hour);
2688     evt->start_time_4 = toBCD(time->tm_min);
2689     evt->start_time_5 = toBCD(time->tm_sec);
2690
2691 }
2692
2693 static void fill_eit_duration(eit_event_struct *evt, int time)
2694 {
2695     //time is given in second
2696     //convert to hour, minutes, seconds
2697     evt->duration_1 = toBCD(time / 3600);
2698     evt->duration_2 = toBCD((time % 3600) / 60);
2699     evt->duration_3 = toBCD((time % 3600) % 60);
2700 }
2701
2702 // convert from set of strings to DVB format (EIT)
2703 void eEPGCache::submitEventData(const std::vector<eServiceReferenceDVB>& serviceRefs, long start,
2704         long duration, const char* title, const char* short_summary,
2705         const char* long_description, char event_type)
2706 {
2707         std::vector<int> sids;
2708         std::vector<eDVBChannelID> chids;
2709         for (std::vector<eServiceReferenceDVB>::const_iterator serviceRef = serviceRefs.begin();
2710                 serviceRef != serviceRefs.end();
2711                 ++serviceRef)
2712         {
2713                 eDVBChannelID chid;
2714                 serviceRef->getChannelID(chid);
2715                 chids.push_back(chid);
2716                 sids.push_back(serviceRef->getServiceID().get());
2717         }
2718         submitEventData(sids, chids, start, duration, title, short_summary, long_description, event_type, EPG_IMPORT);
2719 }
2720
2721 void eEPGCache::submitEventData(const std::vector<int>& sids, const std::vector<eDVBChannelID>& chids, long start,
2722         long duration, const char* title, const char* short_summary,
2723         const char* long_description, char event_type, int source)
2724 {
2725         if (!title)
2726                 return;
2727         if (sids.size() != chids.size())
2728                 return;
2729         static const int EIT_LENGTH = 4108;
2730         static const uint8_t codePage = 0x15; // UTF-8 encoding
2731         uint8_t data[EIT_LENGTH];
2732
2733         eit_t *packet = (eit_t *) data;
2734         packet->table_id = 0x50;
2735         packet->section_syntax_indicator = 1;
2736
2737         packet->version_number = 0;     // eEPGCache::sectionRead() will dig this for the moment
2738         packet->current_next_indicator = 0;
2739         packet->section_number = 0;     // eEPGCache::sectionRead() will dig this for the moment
2740         packet->last_section_number = 0;        // eEPGCache::sectionRead() will dig this for the moment
2741
2742         packet->segment_last_section_number = 0; // eEPGCache::sectionRead() will dig this for the moment
2743         packet->segment_last_table_id = 0x50;
2744
2745         eit_event_t *evt_struct = (eit_event_t*) (data + EIT_SIZE);
2746
2747         uint16_t eventId = start & 0xFFFF;
2748         evt_struct->setEventId(eventId);
2749
2750         //6 bytes start time, 3 bytes duration
2751         fill_eit_start(evt_struct, start);
2752         fill_eit_duration(evt_struct, duration);
2753
2754         evt_struct->running_status = 0;
2755         evt_struct->free_CA_mode = 0;
2756
2757         //no support for different code pages, only DVB's latin1 character set
2758         //TODO: convert text to correct character set (data is probably passed in as UTF-8)
2759         uint8_t *x = (uint8_t *) evt_struct;
2760         x += EIT_LOOP_SIZE;
2761         int nameLength = strnlen(title, 246);
2762         int descLength = short_summary ? strnlen(short_summary, 246 - nameLength) : 0;
2763
2764         eit_short_event_descriptor_struct *short_evt = (eit_short_event_descriptor_struct*) x;
2765         short_evt->descriptor_tag = SHORT_EVENT_DESCRIPTOR;
2766         short_evt->descriptor_length = EIT_SHORT_EVENT_DESCRIPTOR_SIZE + nameLength + descLength + 1 - 2; //+1 for length of short description, -2 for tag and length
2767         if (nameLength) ++short_evt->descriptor_length; // +1 for codepage byte
2768         if (descLength) ++short_evt->descriptor_length;
2769         short_evt->language_code_1 = 'e';
2770         short_evt->language_code_2 = 'n';
2771         short_evt->language_code_3 = 'g';
2772         short_evt->event_name_length = nameLength ? nameLength + 1 : 0;
2773         x = (uint8_t *) short_evt;
2774         x += EIT_SHORT_EVENT_DESCRIPTOR_SIZE;
2775         *x = codePage;
2776         ++x;
2777         memcpy(x, title, nameLength);
2778         x += nameLength;
2779         if (descLength)
2780         {
2781                 *x = descLength + 1;
2782                 ++x;
2783                 *x = codePage;
2784                 ++x;
2785                 memcpy(x, short_summary, descLength);
2786                 x += descLength;
2787         }
2788         else
2789         {
2790                 *x = 0;
2791                 ++x;
2792         }
2793
2794         //Content type
2795         if (event_type != 0)
2796         {
2797                 x[0] = 0x54;
2798                 x[1] = 2;
2799                 x[2] = event_type;
2800                 x[3] = 0;
2801                 x += 4;
2802         }
2803
2804         //Long description
2805         int currentLoopLength = x - (uint8_t*)short_evt;
2806         static const int overheadPerDescriptor = 9; //increase if codepages are added!!!
2807         static const int MAX_LEN = 256 - overheadPerDescriptor;
2808
2809         int textLength = long_description ? strnlen(long_description, EIT_LENGTH) : 0;//EIT_LENGTH is a bit too much, but it's only here as a reasonable end point
2810         int lastDescriptorNumber = (textLength + MAX_LEN-1) / MAX_LEN - 1;
2811         int remainingTextLength = textLength - lastDescriptorNumber * MAX_LEN;
2812
2813         //if long description is too long, just try to fill as many descriptors as possible
2814         while ( (lastDescriptorNumber+1) * 256 + currentLoopLength > EIT_LENGTH - EIT_LOOP_SIZE)
2815         {
2816                 lastDescriptorNumber--;
2817                 remainingTextLength = MAX_LEN;
2818         }
2819
2820         for (int descrIndex = 0; descrIndex <= lastDescriptorNumber; ++descrIndex)
2821         {
2822                 eit_extended_descriptor_struct *ext_evt = (eit_extended_descriptor_struct*) x;
2823                 ext_evt->descriptor_tag = EIT_EXTENDED_EVENT_DESCRIPOR;
2824                 //descriptor header length is 6, including the 2 tag and length bytes
2825                 //so the length field must be: stringlength + 1 (2 4-bits numbers) + 3 (lang code) + 2 bytes for item info length field and text length field
2826                 int currentTextLength = descrIndex < lastDescriptorNumber ? MAX_LEN : remainingTextLength;
2827                 ext_evt->descriptor_length = 6 + currentTextLength + 1;
2828
2829                 ext_evt->descriptor_number = descrIndex;
2830                 ext_evt->last_descriptor_number = lastDescriptorNumber;
2831                 ext_evt->iso_639_2_language_code_1 = 'e';
2832                 ext_evt->iso_639_2_language_code_2 = 'n';
2833                 ext_evt->iso_639_2_language_code_3 = 'g';
2834
2835                 x[6] = 0; //item information (car, year, director, etc. Unsupported for now)
2836                 x[7] = currentTextLength + 1; //length of description string (part in this message)
2837                 x[8] = codePage;
2838                 memcpy(x + 9, &long_description[descrIndex*MAX_LEN], currentTextLength);
2839
2840                 x += 2 + ext_evt->descriptor_length;
2841         }
2842
2843         //TODO: add age and more
2844         int desc_loop_length = x - ((uint8_t*)evt_struct + EIT_LOOP_SIZE);
2845         evt_struct->setDescriptorsLoopLength(desc_loop_length);
2846
2847         int packet_length = (x - data) - 3; //should add 1 for crc....
2848         packet->setSectionLength(packet_length);
2849         // Add channelrefs and submit data.
2850         for (unsigned int i = 0; i < chids.size(); i++)
2851         {
2852                 packet->setServiceId(sids[i]);
2853                 packet->setTransportStreamId(chids[i].transport_stream_id.get());
2854                 packet->setOriginalNetworkId(chids[i].original_network_id.get());
2855                 sectionRead(data, source, 0);
2856         }
2857 }
2858
2859 void eEPGCache::setEpgHistorySeconds(time_t seconds)
2860 {
2861         historySeconds = seconds;
2862 }
2863
2864 void eEPGCache::setEpgSources(unsigned int mask)
2865 {
2866         enabledSources = mask;
2867 }
2868
2869 unsigned int eEPGCache::getEpgSources()
2870 {
2871         return enabledSources;
2872 }
2873
2874 static const char* getStringFromPython(ePyObject obj)
2875 {
2876         char *result = 0;
2877         if (PyString_Check(obj))
2878         {
2879                 result = PyString_AS_STRING(obj);
2880         }
2881         return result;
2882 }
2883
2884 void eEPGCache::importEvent(ePyObject serviceReference, ePyObject list)
2885 {
2886         importEvents(serviceReference, list);
2887 }
2888
2889 //here we get a python tuple of tuples ;)
2890 // consider it an array of objects with the following data
2891 // 1. start time (long)
2892 // 2. duration (int)
2893 // 3. event title (string)
2894 // 4. short description (string)
2895 // 5. extended description (string)
2896 // 6. event type (byte)
2897 void eEPGCache::importEvents(ePyObject serviceReferences, ePyObject list)
2898 {
2899         std::vector<eServiceReferenceDVB> refs;
2900
2901         if (PyString_Check(serviceReferences))
2902         {
2903                 char *refstr;
2904                 refstr = PyString_AS_STRING(serviceReferences);
2905                 if (!refstr)
2906                 {
2907                         eDebug("[eEPGCache:import] serviceReference string is 0, aborting");
2908                         return;
2909                 }
2910                 refs.push_back(eServiceReferenceDVB(refstr));
2911         }
2912         else if (PyList_Check(serviceReferences))
2913         {
2914                 int nRefs = PyList_Size(serviceReferences);
2915                 for (int i = 0; i < nRefs; ++i)
2916                 {
2917                         PyObject* item = PyList_GET_ITEM(serviceReferences, i);
2918                         char *refstr;
2919                         refstr = PyString_AS_STRING(item);
2920                         if (!refstr)
2921                         {
2922                                 eDebug("[eEPGCache:import] a serviceref item is not a string");
2923                         }
2924                         else
2925                         {
2926                                 refs.push_back(eServiceReferenceDVB(refstr));
2927                         }
2928                 }
2929         }
2930         else
2931         {
2932                 eDebug("[eEPGCache:import] serviceReference string is neither string nor list, aborting");
2933                 return;
2934         }
2935
2936         bool isTuple = PyTuple_Check(list);
2937         if (!isTuple && !PyList_Check(list))
2938         {
2939
2940                 eDebug("[eEPGCache:import] argument 'list' is neither list nor tuple.");
2941                 return;
2942         }
2943
2944         int numberOfEvents = isTuple ? PyTuple_Size(list) : PyList_Size(list);
2945
2946         for (int i = 0; i < numberOfEvents;  ++i)
2947         {
2948                 ePyObject singleEvent = isTuple ? PyTuple_GET_ITEM(list, i) : PyList_GET_ITEM(list, i);
2949                 if (!PyTuple_Check(singleEvent))
2950                 {
2951                         eDebug("[eEPGCache:import] eventdata tuple does not pass PyTuple_Check, aborting");
2952                         return;
2953                 }
2954                 int tupleSize = PyTuple_Size(singleEvent);
2955                 if (tupleSize < 5)
2956                 {
2957                         eDebug("[eEPGCache:import] eventdata tuple does not contain enough fields, aborting");
2958                         return;
2959                 }
2960
2961                 long start = PyLong_AsLong(PyTuple_GET_ITEM(singleEvent, 0));
2962                 long duration = PyInt_AsLong(PyTuple_GET_ITEM(singleEvent, 1));
2963                 const char *title = getStringFromPython(PyTuple_GET_ITEM(singleEvent, 2));
2964                 const char *short_summary = getStringFromPython(PyTuple_GET_ITEM(singleEvent, 3));
2965                 const char *long_description = getStringFromPython(PyTuple_GET_ITEM(singleEvent, 4));
2966                 char event_type = (char) PyInt_AsLong(PyTuple_GET_ITEM(singleEvent, 5));
2967
2968                 Py_BEGIN_ALLOW_THREADS;
2969                 submitEventData(refs, start, duration, title, short_summary, long_description, event_type);
2970                 Py_END_ALLOW_THREADS;
2971         }
2972 }
2973
2974 // here we get a python tuple
2975 // the first entry in the tuple is a python string to specify the format of the returned tuples (in a list)
2976 //   I = Event Id
2977 //   B = Event Begin Time
2978 //   D = Event Duration
2979 //   T = Event Title
2980 //   S = Event Short Description
2981 //   P = Event Parental Rating
2982 //   W = Event Content Description
2983 //   E = Event Extended Description
2984 //   R = Service Reference
2985 //   N = Service Name
2986 //   n = Short Service Name
2987 //  the second tuple entry is the MAX matches value
2988 //  the third tuple entry is the type of query
2989 //     0 = search for similar broadcastings (SIMILAR_BROADCASTINGS_SEARCH)
2990 //     1 = search events with exactly title name (EXACT_TITLE_SEARCH)
2991 //     2 = search events with text in title name (PARTIAL_TITLE_SEARCH)
2992 //     3 = search events starting with title name (START_TITLE_SEARCH)
2993 //  when type is 0 (SIMILAR_BROADCASTINGS_SEARCH)
2994 //   the fourth is the servicereference string
2995 //   the fifth is the eventid
2996 //  when type > 0 (*_TITLE_SEARCH)
2997 //   the fourth is the search text
2998 //   the fifth is
2999 //     0 = case sensitive (CASE_CHECK)
3000 //     1 = case insensitive (NO_CASECHECK)
3001
3002 PyObject *eEPGCache::search(ePyObject arg)
3003 {
3004         ePyObject ret;
3005         std::deque<uint32_t> descr;
3006         int eventid = -1;
3007         const char *argstring=0;
3008         char *refstr=0;
3009         int argcount=0;
3010         int querytype=-1;
3011         bool needServiceEvent=false;
3012         int maxmatches=0;
3013         int must_get_service_name = 0;
3014         bool must_get_service_reference = false;
3015
3016         if (PyTuple_Check(arg))
3017         {
3018                 int tuplesize=PyTuple_Size(arg);
3019                 if (tuplesize > 0)
3020                 {
3021                         ePyObject obj = PyTuple_GET_ITEM(arg,0);
3022                         if (PyString_Check(obj))
3023                         {
3024 #if PY_VERSION_HEX < 0x02060000
3025                                 argcount = PyString_GET_SIZE(obj);
3026 #else
3027                                 argcount = PyString_Size(obj);
3028 #endif
3029                                 argstring = PyString_AS_STRING(obj);
3030                                 for (int i=0; i < argcount; ++i)
3031                                 {
3032                                         switch(argstring[i])
3033                                         {
3034                                         case 'S':
3035                                         case 'E':
3036                                         case 'T':
3037                                         case 'P':
3038                                         case 'W':
3039                                                 needServiceEvent=true;
3040                                                 break;
3041                                         case 'N':
3042                                                 must_get_service_name = 1;
3043                                                 break;
3044                                         case 'n':
3045                                                 must_get_service_name = 2;
3046                                                 break;
3047                                         case 'R':
3048                                                 must_get_service_reference = true;
3049                                                 break;
3050                                         default:
3051                                                 break;
3052                                         }
3053                                 }
3054                         }
3055                         else
3056                         {
3057                                 PyErr_SetString(PyExc_StandardError,
3058                                         "type error");
3059                                 eDebug("[eEPGCache] tuple arg 0 is not a string");
3060                                 return NULL;
3061                         }
3062                 }
3063                 if (tuplesize > 1)
3064                 {
3065                         maxmatches = PyLong_AsLong(PyTuple_GET_ITEM(arg, 1));
3066                 }
3067                 if (tuplesize > 2)
3068                 {
3069                         querytype = PyLong_AsLong(PyTuple_GET_ITEM(arg, 2));
3070
3071                         if (tuplesize > 4 && querytype == 0)
3072                         {
3073                                 ePyObject obj = PyTuple_GET_ITEM(arg, 3);
3074                                 if (PyString_Check(obj))
3075                                 {
3076                                         refstr = PyString_AS_STRING(obj);
3077                                         eServiceReferenceDVB ref(refstr);
3078                                         if (ref.valid())
3079                                         {
3080                                                 eventid = PyLong_AsLong(PyTuple_GET_ITEM(arg, 4));
3081                                                 singleLock s(cache_lock);
3082                                                 const eventData *evData = 0;
3083                                                 lookupEventId(ref, eventid, evData);
3084                                                 if (evData)
3085                                                 {
3086                                                         // search short and extended event descriptors
3087                                                         for (uint8_t i = 0; i < evData->n_crc; ++i)
3088                                                         {
3089                                                                 uint32_t crc = evData->crc_list[i];
3090                                                                 DescriptorMap::iterator it =
3091                                                                         eventData::descriptors.find(crc);
3092                                                                 if (it != eventData::descriptors.end())
3093                                                                 {
3094                                                                         uint8_t *descr_data = it->second.data;
3095                                                                         switch(descr_data[0])
3096                                                                         {
3097                                                                         case 0x4D ... 0x4E:
3098                                                                                 descr.push_back(crc);
3099                                                                                 break;
3100                                                                         default:
3101                                                                                 break;
3102                                                                         }
3103                                                                 }
3104                                                         }
3105                                                 }
3106                                                 if (descr.empty())
3107                                                         eDebug("[eEPGCache] event not found");
3108                                         }
3109                                         else
3110                                         {
3111                                                 PyErr_SetString(PyExc_StandardError, "type error");
3112                                                 eDebug("[eEPGCache] tuple arg 4 is not a valid service reference string");
3113                                                 return NULL;
3114                                         }
3115                                 }
3116                                 else
3117                                 {
3118                                         PyErr_SetString(PyExc_StandardError, "type error");
3119                                         eDebug("[eEPGCache] tuple arg 4 is not a string");
3120                                         return NULL;
3121                                 }
3122                         }
3123                         else if (tuplesize > 4 && (querytype > 0) )
3124                         {
3125                                 ePyObject obj = PyTuple_GET_ITEM(arg, 3);
3126                                 if (PyString_Check(obj))
3127                                 {
3128                                         int casetype = PyLong_AsLong(PyTuple_GET_ITEM(arg, 4));
3129                                         const char *str = PyString_AS_STRING(obj);
3130 #if PY_VERSION_HEX < 0x02060000
3131                                         int textlen = PyString_GET_SIZE(obj);
3132 #else
3133                                         int textlen = PyString_Size(obj);
3134 #endif
3135                                         switch (querytype)
3136                                         {
3137                                                 case 1:
3138                                                         eDebug("[eEPGCache] lookup events with '%s' as title (%s)", str, casetype?"ignore case":"case sensitive");
3139                                                         break;
3140                                                 case 2:
3141                                                         eDebug("[eEPGCache] lookup events with '%s' in title (%s)", str, casetype?"ignore case":"case sensitive");
3142                                                         break;
3143                                                 case 3:
3144                                                         eDebug("[eEPGCache] lookup events, title starting with '%s' (%s)", str, casetype?"ignore case":"case sensitive");
3145                                                         break;
3146                                         }
3147                                         Py_BEGIN_ALLOW_THREADS; /* No Python code in this section, so other threads can run */
3148                                         singleLock s(cache_lock);
3149                                         std::string title;
3150                                         for (DescriptorMap::iterator it(eventData::descriptors.begin());
3151                                                 it != eventData::descriptors.end(); ++it)
3152                                         {
3153                                                 uint8_t *data = it->second.data;
3154                                                 if ( data[0] == SHORT_EVENT_DESCRIPTOR )
3155                                                 {
3156                                                         const char *titleptr = (const char*)&data[6];
3157                                                         int title_len = data[5];
3158                                                         if (data[6] < 0x20)
3159                                                         {
3160                                                                 /* custom encoding */
3161                                                                 title = convertDVBUTF8((unsigned char*)titleptr, title_len, 0x40, 0);
3162                                                                 titleptr = title.data();
3163                                                                 title_len = title.length();
3164                                                         }
3165                                                         if (title_len < textlen)
3166                                                                 /*Doesn't fit, so cannot match anything */
3167                                                                 continue;
3168                                                         if (querytype == 1)
3169                                                         {
3170                                                                 /* require exact title match */
3171                                                                 if (title_len != textlen)
3172                                                                         continue;
3173                                                         }
3174                                                         else if (querytype == 3)
3175                                                         {
3176                                                                 /* Do a "startswith" match by pretending the text isn't that long */
3177                                                                 title_len = textlen;
3178                                                         }
3179                                                         if (casetype)
3180                                                         {
3181                                                                 while (title_len >= textlen)
3182                                                                 {
3183                                                                         if (!strncasecmp(titleptr, str, textlen))
3184                                                                         {
3185                                                                                 descr.push_back(it->first);
3186                                                                                 break;
3187                                                                         }
3188                                                                         title_len--;
3189                                                                         titleptr++;
3190                                                                 }
3191                                                         }
3192                                                         else
3193                                                         {
3194                                                                 while (title_len >= textlen)
3195                                                                 {
3196                                                                         if (!memcmp(titleptr, str, textlen))
3197                                                                         {
3198                                                                                 descr.push_back(it->first);
3199                                                                                 break;
3200                                                                         }
3201                                                                         title_len--;
3202                                                                         titleptr++;
3203                                                                 }
3204                                                         }
3205                                                 }
3206                                         }
3207                                         Py_END_ALLOW_THREADS;
3208                                 }
3209                                 else
3210                                 {
3211                                         PyErr_SetString(PyExc_StandardError,
3212                                                 "type error");
3213                                         eDebug("[eEPGCache] tuple arg 4 is not a string");
3214                                         return NULL;
3215                                 }
3216                         }
3217                         else
3218                         {
3219                                 PyErr_SetString(PyExc_StandardError,
3220                                         "type error");
3221                                 eDebug("[eEPGCache] tuple arg 3(%d) is not a known querytype(0..3)", querytype);
3222                                 return NULL;
3223                         }
3224                 }
3225                 else
3226                 {
3227                         PyErr_SetString(PyExc_StandardError,
3228                                 "type error");
3229                         eDebug("[eEPGCache] not enough args in tuple");
3230                         return NULL;
3231                 }
3232         }
3233         else
3234         {
3235                 PyErr_SetString(PyExc_StandardError,
3236                         "type error");
3237                 eDebug("[eEPGCache] arg 0 is not a tuple");
3238                 return NULL;
3239         }
3240
3241         if (!descr.empty())
3242         {
3243                 int maxcount=maxmatches;
3244                 eServiceReferenceDVB ref(refstr?(const eServiceReferenceDVB&)handleGroup(eServiceReference(refstr)):eServiceReferenceDVB(""));
3245                 // ref is only valid in SIMILAR_BROADCASTING_SEARCH
3246                 // in this case we start searching with the base service
3247                 bool first = ref.valid() ? true : false;
3248                 singleLock s(cache_lock);
3249                 eventCache::iterator cit(ref.valid() ? eventDB.find(ref) : eventDB.begin());
3250                 while(cit != eventDB.end() && maxcount)
3251                 {
3252                         if ( ref.valid() && !first && cit->first == ref )
3253                         {
3254                                 // do not scan base service twice ( only in SIMILAR BROADCASTING SEARCH )
3255                                 ++cit;
3256                                 continue;
3257                         }
3258                         timeMap &evmap = cit->second.byTime;
3259                         // check all events
3260                         for (timeMap::iterator evit(evmap.begin()); evit != evmap.end() && maxcount; ++evit)
3261                         {
3262                                 if (querytype == 0)
3263                                 {
3264                                         /* ignore the current event, when looking for similar events */
3265                                         if (evit->second->getEventID() == eventid)
3266                                                 continue;
3267                                 }
3268                                 // check if any of our descriptor used by this event
3269                                 unsigned int cnt = 0;
3270                                 for (uint8_t i = 0; i < evit->second->n_crc; ++i)
3271                                 {
3272                                         uint32_t crc32 = evit->second->crc_list[i];
3273                                         for (std::deque<uint32_t>::const_iterator it = descr.begin();
3274                                                 it != descr.end(); ++it)
3275                                         {
3276                                                 if (*it == crc32)  // found...
3277                                                 {
3278                                                         ++cnt;
3279                                                         if (querytype)
3280                                                         {
3281                                                                 /* we need only one match, when we're not looking for similar broadcasting events */
3282                                                                 i = evit->second->n_crc;
3283                                                                 break;
3284                                                         }
3285                                                 }
3286                                         }
3287                                 }
3288                                 if ( (querytype == 0 && cnt == descr.size()) ||
3289                                          ((querytype > 0) && cnt != 0) )
3290                                 {
3291                                         const uniqueEPGKey &service = cit->first;
3292                                         std::vector<eServiceReference> refs;
3293                                         eDVBDB::getInstance()->searchAllReferences(refs, service.tsid, service.onid, service.sid);
3294                                         for (unsigned int i = 0; i < refs.size(); i++)
3295                                         {
3296                                                 eServiceReference ref = refs[i];
3297                                                 if (ref.valid())
3298                                                 {
3299                                                         ePyObject service_name;
3300                                                         ePyObject service_reference;
3301                                                 // create servive event
3302                                                         eServiceEvent ptr;
3303                                                         const eventData *ev_data=0;
3304                                                         if (needServiceEvent)
3305                                                         {
3306                                                                 if (lookupEventId(ref, evit->second->getEventID(), ev_data))
3307                                                                         eDebug("[eEPGCache] event not found !!!!!!!!!!!");
3308                                                                 else
3309                                                                 {
3310                                                                         const eServiceReferenceDVB &dref = (const eServiceReferenceDVB&)ref;
3311                                                                         Event ev((uint8_t*)ev_data->get());
3312                                                                         ptr.parseFrom(&ev, (dref.getTransportStreamID().get()<<16)|dref.getOriginalNetworkID().get());
3313                                                                 }
3314                                                         }
3315                                                 // create service name
3316                                                         if (must_get_service_name && !service_name)
3317                                                         {
3318                                                                 ePtr<iStaticServiceInformation> sptr;
3319                                                                 eServiceCenterPtr service_center;
3320                                                                 eServiceCenter::getPrivInstance(service_center);
3321                                                                 if (service_center)
3322                                                                 {
3323                                                                         service_center->info(ref, sptr);
3324                                                                         if (sptr)
3325                                                                         {
3326                                                                                 std::string name;
3327                                                                                 sptr->getName(ref, name);
3328
3329                                                                                 if (must_get_service_name == 1)
3330                                                                                 {
3331                                                                                         size_t pos;
3332                                                                                         // filter short name brakets
3333                                                                                         while((pos = name.find("\xc2\x86")) != std::string::npos)
3334                                                                                                 name.erase(pos,2);
3335                                                                                         while((pos = name.find("\xc2\x87")) != std::string::npos)
3336                                                                                                 name.erase(pos,2);
3337                                                                                 }
3338                                                                                 else
3339                                                                                         name = buildShortName(name);
3340
3341                                                                                 if (name.length())
3342                                                                                         service_name = PyString_FromString(name.c_str());
3343                                                                         }
3344                                                                 }
3345                                                                 if (!service_name)
3346                                                                         service_name = PyString_FromString("<n/a>");
3347                                                         }
3348                                                 // create servicereference string
3349                                                         if (must_get_service_reference && !service_reference)
3350                                                                 service_reference = PyString_FromString(ref.toString().c_str());
3351                                                 // create list
3352                                                         if (!ret)
3353                                                                 ret = PyList_New(0);
3354                                                 // create tuple
3355                                                         ePyObject tuple = PyTuple_New(argcount);
3356                                                 // fill tuple
3357                                                         ePyObject tmp = ePyObject();
3358                                                         fillTuple(tuple, argstring, argcount, service_reference, ev_data ? &ptr : 0, service_name, tmp, evit->second);
3359                                                         PyList_Append(ret, tuple);
3360                                                         Py_DECREF(tuple);
3361                                                         if (service_name)
3362                                                                 Py_DECREF(service_name);
3363                                                         if (service_reference)
3364                                                                 Py_DECREF(service_reference);
3365                                                         --maxcount;
3366                                                 }
3367                                         }
3368                                 }
3369                         }
3370                         if (first)
3371                         {
3372                                 // now start at first service in epgcache database ( only in SIMILAR BROADCASTING SEARCH )
3373                                 first=false;
3374                                 cit=eventDB.begin();
3375                         }
3376                         else
3377                                 ++cit;
3378                 }
3379         }
3380
3381         if (!ret)
3382                 Py_RETURN_NONE;
3383
3384         return ret;
3385 }
3386
3387 #ifdef ENABLE_PRIVATE_EPG
3388 #include <dvbsi++/descriptor_tag.h>
3389 #include <dvbsi++/unknown_descriptor.h>
3390 #include <dvbsi++/private_data_specifier_descriptor.h>
3391
3392 void eEPGCache::PMTready(eDVBServicePMTHandler *pmthandler)
3393 {
3394         ePtr<eTable<ProgramMapSection> > ptr;
3395         if (!pmthandler->getPMT(ptr) && ptr)
3396         {
3397                 std::vector<ProgramMapSection*>::const_iterator i;
3398                 for (i = ptr->getSections().begin(); i != ptr->getSections().end(); ++i)
3399                 {
3400                         const ProgramMapSection &pmt = **i;
3401
3402                         ElementaryStreamInfoConstIterator es;
3403                         for (es = pmt.getEsInfo()->begin(); es != pmt.getEsInfo()->end(); ++es)
3404                         {
3405                                 int tmp=0;
3406                                 switch ((*es)->getType())
3407                                 {
3408                                 case 0xC1: // user private
3409                                         for (DescriptorConstIterator desc = (*es)->getDescriptors()->begin();
3410                                                 desc != (*es)->getDescriptors()->end(); ++desc)
3411                                         {
3412                                                 switch ((*desc)->getTag())
3413                                                 {
3414                                                         case 0xC2: // user defined
3415                                                                 if ((*desc)->getLength() == 8)
3416                                                                 {
3417                                                                         uint8_t buffer[10];
3418                                                                         (*desc)->writeToBuffer(buffer);
3419                                                                         if (!memcmp((const char *)buffer+2, "EPGDATA", 7))
3420                                                                         {
3421                                                                                 eServiceReferenceDVB ref;
3422                                                                                 if (!pmthandler->getServiceReference(ref))
3423                                                                                 {
3424                                                                                         int pid = (*es)->getPid();
3425                                                                                         messages.send(Message(Message::got_mhw2_channel_pid, ref, pid));
3426                                                                                 }
3427                                                                         }
3428                                                                         else if(!memcmp((const char *)buffer+2, "FICHAS", 6))
3429                                                                         {
3430                                                                                 eServiceReferenceDVB ref;
3431                                                                                 if (!pmthandler->getServiceReference(ref))
3432                                                                                 {
3433                                                                                         int pid = (*es)->getPid();
3434                                                                                         messages.send(Message(Message::got_mhw2_summary_pid, ref, pid));
3435                                                                                 }
3436                                                                         }
3437                                                                         else if(!memcmp((const char *)buffer+2, "GENEROS", 7))
3438                                                                         {
3439                                                                                 eServiceReferenceDVB ref;
3440                                                                                 if (!pmthandler->getServiceReference(ref))
3441                                                                                 {
3442                                                                                         int pid = (*es)->getPid();
3443                                                                                         messages.send(Message(Message::got_mhw2_title_pid, ref, pid));
3444                                                                                 }
3445                                                                         }
3446                                                                 }
3447                                                                 break;
3448                                                         default:
3449                                                                 break;
3450                                                 }
3451                                         }
3452                                 case 0x05: // private
3453                                         for (DescriptorConstIterator desc = (*es)->getDescriptors()->begin();
3454                                                 desc != (*es)->getDescriptors()->end(); ++desc)
3455                                         {
3456                                                 switch ((*desc)->getTag())
3457                                                 {
3458                                                         case PRIVATE_DATA_SPECIFIER_DESCRIPTOR:
3459                                                                 if (((PrivateDataSpecifierDescriptor*)(*desc))->getPrivateDataSpecifier() == 190)
3460                                                                         tmp |= 1;
3461                                                                 break;
3462                                                         case 0x90:
3463                                                         {
3464                                                                 Descriptor *descr = (Descriptor*)*desc;
3465                                                                 int descr_len = descr->getLength();
3466                                                                 if (descr_len == 4)
3467                                                                 {
3468                                                                         uint8_t data[descr_len+2];
3469                                                                         descr->writeToBuffer(data);
3470                                                                         if ( !data[2] && !data[3] && data[4] == 0xFF && data[5] == 0xFF )
3471                                                                                 tmp |= 2;
3472                                                                 }
3473                                                                 break;
3474                                                         }
3475                                                         default:
3476                                                                 break;
3477                                                 }
3478                                         }
3479                                 default:
3480                                         break;
3481                                 }
3482                                 if (tmp==3)
3483                                 {
3484                                         eServiceReferenceDVB ref;
3485                                         if (!pmthandler->getServiceReference(ref))
3486                                         {
3487                                                 int pid = (*es)->getPid();
3488                                                 messages.send(Message(Message::got_private_pid, ref, pid));
3489                                                 return;
3490                                         }
3491                                 }
3492                         }
3493                 }
3494         }
3495         else
3496                 eDebug("[eEPGCache] PMTready but no pmt!!");
3497 }
3498
3499 struct date_time
3500 {
3501         uint8_t data[5];
3502         time_t tm;
3503         date_time( const date_time &a )
3504         {
3505                 memcpy(data, a.data, 5);
3506                 tm = a.tm;
3507         }
3508         date_time( const uint8_t data[5])
3509         {
3510                 memcpy(this->data, data, 5);
3511                 tm = parseDVBtime(data);
3512         }
3513         date_time()
3514         {
3515         }
3516         const uint8_t& operator[](int pos) const
3517         {
3518                 return data[pos];
3519         }
3520 };
3521
3522 struct less_datetime
3523 {
3524         bool operator()( const date_time &a, const date_time &b ) const
3525         {
3526                 return abs(a.tm-b.tm) < 360 ? false : a.tm < b.tm;
3527         }
3528 };
3529
3530 void eEPGCache::privateSectionRead(const uniqueEPGKey &current_service, const uint8_t *data)
3531 {
3532         contentMap &content_time_table = content_time_tables[current_service];
3533         singleLock s(cache_lock);
3534         std::map< date_time, std::list<uniqueEPGKey>, less_datetime > start_times;
3535         EventCacheItem &eventDBitem = eventDB[current_service];
3536         eventMap &evMap = eventDBitem.byEvent;
3537         timeMap &tmMap = eventDBitem.byTime;
3538         int ptr = 8;
3539         int content_id = data[ptr++] << 24;
3540         content_id |= data[ptr++] << 16;
3541         content_id |= data[ptr++] << 8;
3542         content_id |= data[ptr++];
3543
3544         contentTimeMap &time_event_map = content_time_table[content_id];
3545         for ( contentTimeMap::iterator it( time_event_map.begin() );
3546                 it != time_event_map.end(); ++it )
3547         {
3548                 eventMap::iterator evIt( evMap.find(it->second.second) );
3549                 if ( evIt != evMap.end() )
3550                 {
3551                         // time_event_map can have other timestamp -> get timestamp from eventData
3552                         time_t ev_time = evIt->second->getStartTime();
3553                         delete evIt->second;
3554                         evMap.erase(evIt);
3555                         tmMap.erase(ev_time);
3556                 }
3557         }
3558         time_event_map.clear();
3559
3560         uint8_t duration[3];
3561         memcpy(duration, data+ptr, 3);
3562         ptr+=3;
3563         int duration_sec =
3564                 fromBCD(duration[0])*3600+fromBCD(duration[1])*60+fromBCD(duration[2]);
3565
3566         const uint8_t *descriptors[65];
3567         const uint8_t **pdescr = descriptors;
3568
3569         int descriptors_length = (data[ptr++]&0x0F) << 8;
3570         descriptors_length |= data[ptr++];
3571         while ( descriptors_length > 1 )
3572         {
3573                 int descr_type = data[ptr];
3574                 int descr_len = data[ptr+1];
3575                 descriptors_length -= 2;
3576                 if (descriptors_length >= descr_len)
3577                 {
3578                         descriptors_length -= descr_len;
3579                         if ( descr_type == 0xf2 && descr_len > 5)
3580                         {
3581                                 ptr+=2;
3582                                 int tsid = data[ptr++] << 8;
3583                                 tsid |= data[ptr++];
3584                                 int onid = data[ptr++] << 8;
3585                                 onid |= data[ptr++];
3586                                 int sid = data[ptr++] << 8;
3587                                 sid |= data[ptr++];
3588
3589 // WORKAROUND for wrong transmitted epg data (01.10.2007)
3590                                 if ( onid == 0x85 )
3591                                 {
3592                                         switch( (tsid << 16) | sid )
3593                                         {
3594                                                 case 0x01030b: sid = 0x1b; tsid = 4; break;  // Premiere Win
3595                                                 case 0x0300f0: sid = 0xe0; tsid = 2; break;
3596                                                 case 0x0300f1: sid = 0xe1; tsid = 2; break;
3597                                                 case 0x0300f5: sid = 0xdc; break;
3598                                                 case 0x0400d2: sid = 0xe2; tsid = 0x11; break;
3599                                                 case 0x1100d3: sid = 0xe3; break;
3600                                                 case 0x0100d4: sid = 0xe4; tsid = 4; break;
3601                                         }
3602                                 }
3603 ////////////////////////////////////////////
3604
3605                                 uniqueEPGKey service( sid, onid, tsid );
3606                                 descr_len -= 6;
3607                                 while( descr_len > 2 )
3608                                 {
3609                                         uint8_t datetime[5];
3610                                         datetime[0] = data[ptr++];
3611                                         datetime[1] = data[ptr++];
3612                                         int tmp_len = data[ptr++];
3613                                         descr_len -= 3;
3614                                         if (descr_len >= tmp_len)
3615                                         {
3616                                                 descr_len -= tmp_len;
3617                                                 while( tmp_len > 2 )
3618                                                 {
3619                                                         memcpy(datetime+2, data+ptr, 3);
3620                                                         ptr += 3;
3621                                                         tmp_len -= 3;
3622                                                         start_times[datetime].push_back(service);
3623                                                 }
3624                                         }
3625                                 }
3626                         }
3627                         else
3628                         {
3629                                 *pdescr++=data+ptr;
3630                                 ptr += 2;
3631                                 ptr += descr_len;
3632                         }
3633                 }
3634         }
3635         ASSERT(pdescr <= &descriptors[65]);
3636         uint8_t event[4098];
3637         eit_event_struct *ev_struct = (eit_event_struct*) event;
3638         ev_struct->running_status = 0;
3639         ev_struct->free_CA_mode = 1;
3640         memcpy(event+7, duration, 3);
3641         ptr = 12;
3642         const uint8_t **d=descriptors;
3643         while ( d < pdescr )
3644         {
3645                 memcpy(event+ptr, *d, ((*d)[1])+2);
3646                 ptr+=(*d++)[1];
3647                 ptr+=2;
3648         }
3649         ASSERT(ptr <= 4098);
3650         for ( std::map< date_time, std::list<uniqueEPGKey> >::iterator it(start_times.begin()); it != start_times.end(); ++it )
3651         {
3652                 time_t now = ::time(0);
3653                 if ( (it->first.tm + duration_sec) < now )
3654                         continue;
3655                 memcpy(event+2, it->first.data, 5);
3656                 int bptr = ptr;
3657                 int cnt=0;
3658                 for (std::list<uniqueEPGKey>::iterator i(it->second.begin()); i != it->second.end(); ++i)
3659                 {
3660                         event[bptr++] = 0x4A;
3661                         uint8_t *len = event+(bptr++);
3662                         event[bptr++] = (i->tsid & 0xFF00) >> 8;
3663                         event[bptr++] = (i->tsid & 0xFF);
3664                         event[bptr++] = (i->onid & 0xFF00) >> 8;
3665                         event[bptr++] = (i->onid & 0xFF);
3666                         event[bptr++] = (i->sid & 0xFF00) >> 8;
3667                         event[bptr++] = (i->sid & 0xFF);
3668                         event[bptr++] = 0xB0;
3669                         bptr += sprintf((char*)(event+bptr), "Option %d", ++cnt);
3670                         *len = ((event+bptr) - len)-1;
3671                 }
3672                 int llen = bptr - 12;
3673                 ev_struct->descriptors_loop_length_hi = (llen & 0xF00) >> 8;
3674                 ev_struct->descriptors_loop_length_lo = (llen & 0xFF);
3675
3676                 time_t stime = it->first.tm;
3677                 while( tmMap.find(stime) != tmMap.end() )
3678                         ++stime;
3679                 event[6] += (stime - it->first.tm);
3680                 uint16_t event_id = 0;
3681                 while( evMap.find(event_id) != evMap.end() )
3682                         ++event_id;
3683                 event[0] = (event_id & 0xFF00) >> 8;
3684                 event[1] = (event_id & 0xFF);
3685                 time_event_map[it->first.tm]=std::pair<time_t, uint16_t>(stime, event_id);
3686                 eventData *d = new eventData( ev_struct, bptr, PRIVATE );
3687                 evMap[event_id] = d;
3688                 tmMap[stime] = d;
3689                 ASSERT(bptr <= 4098);
3690         }
3691 }
3692
3693 void eEPGCache::channel_data::startPrivateReader()
3694 {
3695         eDVBSectionFilterMask mask;
3696         memset(&mask, 0, sizeof(mask));
3697         mask.pid = m_PrivatePid;
3698         mask.flags = eDVBSectionFilterMask::rfCRC;
3699         mask.data[0] = 0xA0;
3700         mask.mask[0] = 0xFF;
3701         eDebug("[eEPGCache] start privatefilter for pid %04x and version %d", m_PrivatePid, m_PrevVersion);
3702         if (m_PrevVersion != -1)
3703         {
3704                 mask.data[3] = m_PrevVersion << 1;
3705                 mask.mask[3] = 0x3E;
3706                 mask.mode[3] = 0x3E;
3707         }
3708         seenPrivateSections.clear();
3709         if (!m_PrivateConn)
3710                 m_PrivateReader->connectRead(slot(*this, &eEPGCache::channel_data::readPrivateData), m_PrivateConn);
3711         m_PrivateReader->start(mask);
3712 }
3713
3714 void eEPGCache::channel_data::readPrivateData( const uint8_t *data)
3715 {
3716         if ( seenPrivateSections.find(data[6]) == seenPrivateSections.end() )
3717         {
3718                 cache->privateSectionRead(m_PrivateService, data);
3719                 seenPrivateSections.insert(data[6]);
3720         }
3721         if ( seenPrivateSections.size() == (unsigned int)(data[7] + 1) )
3722         {
3723                 eDebug("[eEPGCache] private finished");
3724                 eDVBChannelID chid = channel->getChannelID();
3725                 int tmp = chid.original_network_id.get();
3726                 tmp |= 0x80000000; // we use highest bit as private epg indicator
3727                 chid.original_network_id = tmp;
3728                 cache->channelLastUpdated[chid] = ::time(0);
3729                 m_PrevVersion = (data[5] & 0x3E) >> 1;
3730                 startPrivateReader();
3731         }
3732 }
3733
3734 #endif // ENABLE_PRIVATE_EPG
3735
3736 #ifdef ENABLE_MHW_EPG
3737 void eEPGCache::channel_data::cleanupMHW()
3738 {
3739         m_MHWTimeoutTimer->stop();
3740         m_channels.clear();
3741         m_themes.clear();
3742         m_titles.clear();
3743         m_program_ids.clear();
3744 }
3745
3746 uint8_t *eEPGCache::channel_data::delimitName( uint8_t *in, uint8_t *out, int len_in )
3747 {
3748         // Names in mhw structs are not strings as they are not '\0' terminated.
3749         // This function converts the mhw name into a string.
3750         // Constraint: "length of out" = "length of in" + 1.
3751         int i;
3752         for ( i=0; i < len_in; i++ )
3753                 out[i] = in[i];
3754
3755         i = len_in - 1;
3756         while ( ( i >=0 ) && ( out[i] == 0x20 ) )
3757                 i--;
3758
3759         out[i+1] = 0;
3760         return out;
3761 }
3762
3763 void eEPGCache::channel_data::timeMHW2DVB( u_char hours, u_char minutes, u_char *return_time)
3764 // For time of day
3765 {
3766         return_time[0] = toBCD( hours );
3767         return_time[1] = toBCD( minutes );
3768         return_time[2] = 0;
3769 }
3770
3771 void eEPGCache::channel_data::timeMHW2DVB( int minutes, u_char *return_time)
3772 {
3773         timeMHW2DVB( int(minutes/60), minutes%60, return_time );
3774 }
3775
3776 void eEPGCache::channel_data::timeMHW2DVB( u_char day, u_char hours, u_char minutes, u_char *return_time)
3777 // For date plus time of day
3778 {
3779         char tz_saved[1024];
3780         // Remove offset in mhw time.
3781         uint8_t local_hours = hours;
3782         if ( hours >= 16 )
3783                 local_hours -= 4;
3784         else if ( hours >= 8 )
3785                 local_hours -= 2;
3786
3787         // As far as we know all mhw time data is sent in central Europe time zone.
3788         // So, temporarily set timezone to western europe
3789         time_t dt = ::time(0);
3790
3791         char *old_tz = getenv( "TZ" );
3792         if (old_tz)
3793                 strcpy(tz_saved, old_tz);
3794         putenv((char*)"TZ=CET-1CEST,M3.5.0/2,M10.5.0/3");
3795         tzset();
3796
3797         tm localnow;
3798         localtime_r(&dt, &localnow);
3799
3800         if (day == 7)
3801                 day = 0;
3802         if ( day + 1 < localnow.tm_wday )               // day + 1 to prevent old events to show for next week.
3803                 day += 7;
3804         if (local_hours <= 5)
3805                 day++;
3806
3807         dt += 3600*24*(day - localnow.tm_wday); // Shift dt to the recording date (local time zone).
3808         dt += 3600*(local_hours - localnow.tm_hour);  // Shift dt to the recording hour.
3809
3810         tm recdate;
3811         gmtime_r( &dt, &recdate );   // This will also take care of DST.
3812
3813         if ( old_tz == NULL )
3814                 unsetenv( "TZ" );
3815         else
3816                 setenv("TZ", tz_saved, 1);
3817         tzset();
3818
3819         // Calculate MJD according to annex in ETSI EN 300 468
3820         int l=0;
3821         if ( recdate.tm_mon <= 1 )      // Jan or Feb
3822                 l=1;
3823         int mjd = 14956 + recdate.tm_mday + int( (recdate.tm_year - l) * 365.25) +
3824                 int( (recdate.tm_mon + 2 + l * 12) * 30.6001);
3825
3826         return_time[0] = (mjd & 0xFF00)>>8;
3827         return_time[1] = mjd & 0xFF;
3828
3829         timeMHW2DVB( recdate.tm_hour, minutes, return_time+2 );
3830 }
3831
3832 void eEPGCache::channel_data::storeMHWTitle(std::map<uint32_t, mhw_title_t>::iterator itTitle, std::string sumText, const uint8_t *data)
3833 // data is borrowed from calling proc to save memory space.
3834 {
3835         uint8_t name[34];
3836
3837         // For each title a separate EIT packet will be sent to eEPGCache::sectionRead()
3838         bool isMHW2 = itTitle->second.mhw2_mjd_hi || itTitle->second.mhw2_mjd_lo ||
3839                 itTitle->second.mhw2_duration_hi || itTitle->second.mhw2_duration_lo;
3840
3841         eit_t *packet = (eit_t *) data;
3842         packet->table_id = 0x50;
3843         packet->section_syntax_indicator = 1;
3844
3845         packet->service_id_hi = m_channels[ itTitle->second.channel_id - 1 ].channel_id_hi;
3846         packet->service_id_lo = m_channels[ itTitle->second.channel_id - 1 ].channel_id_lo;
3847         packet->version_number = 0;     // eEPGCache::sectionRead() will dig this for the moment
3848         packet->current_next_indicator = 0;
3849         packet->section_number = 0;     // eEPGCache::sectionRead() will dig this for the moment
3850         packet->last_section_number = 0;        // eEPGCache::sectionRead() will dig this for the moment
3851         packet->transport_stream_id_hi = m_channels[ itTitle->second.channel_id - 1 ].transport_stream_id_hi;
3852         packet->transport_stream_id_lo = m_channels[ itTitle->second.channel_id - 1 ].transport_stream_id_lo;
3853         packet->original_network_id_hi = m_channels[ itTitle->second.channel_id - 1 ].network_id_hi;
3854         packet->original_network_id_lo = m_channels[ itTitle->second.channel_id - 1 ].network_id_lo;
3855         packet->segment_last_section_number = 0; // eEPGCache::sectionRead() will dig this for the moment
3856         packet->segment_last_table_id = 0x50;
3857
3858         uint8_t *title = isMHW2 ? ((uint8_t*)(itTitle->second.title))-4 : (uint8_t*)itTitle->second.title;
3859         std::string prog_title = (char *) delimitName( title, name, isMHW2 ? 35 : 23 );
3860         int prog_title_length = prog_title.length();
3861
3862         int packet_length = EIT_SIZE + EIT_LOOP_SIZE + EIT_SHORT_EVENT_DESCRIPTOR_SIZE +
3863                 prog_title_length + 1;
3864
3865         eit_event_t *event_data = (eit_event_t *) (data + EIT_SIZE);
3866         event_data->event_id_hi = (( itTitle->first ) >> 8 ) & 0xFF;
3867         event_data->event_id_lo = ( itTitle->first ) & 0xFF;
3868
3869         if (isMHW2)
3870         {
3871                 u_char *data = (u_char*) event_data;
3872                 data[2] = itTitle->second.mhw2_mjd_hi;
3873                 data[3] = itTitle->second.mhw2_mjd_lo;
3874                 data[4] = itTitle->second.mhw2_hours;
3875                 data[5] = itTitle->second.mhw2_minutes;
3876                 data[6] = itTitle->second.mhw2_seconds;
3877                 timeMHW2DVB( itTitle->second.getMhw2Duration(), data+7 );
3878         }
3879         else
3880         {
3881                 timeMHW2DVB( itTitle->second.dh.day, itTitle->second.dh.hours, itTitle->second.ms.minutes,
3882                 (u_char *) event_data + 2 );
3883                 timeMHW2DVB( itTitle->second.getDuration(), (u_char *) event_data+7 );
3884         }
3885
3886         event_data->running_status = 0;
3887         event_data->free_CA_mode = 0;
3888         int descr_ll = EIT_SHORT_EVENT_DESCRIPTOR_SIZE + 1 + prog_title_length;
3889
3890         eit_short_event_descriptor_struct *short_event_descriptor =
3891                 (eit_short_event_descriptor_struct *) ( (u_char *) event_data + EIT_LOOP_SIZE);
3892         short_event_descriptor->descriptor_tag = EIT_SHORT_EVENT_DESCRIPTOR;
3893         short_event_descriptor->descriptor_length = EIT_SHORT_EVENT_DESCRIPTOR_SIZE +
3894                 prog_title_length - 1;
3895         short_event_descriptor->language_code_1 = 'e';
3896         short_event_descriptor->language_code_2 = 'n';
3897         short_event_descriptor->language_code_3 = 'g';
3898         short_event_descriptor->event_name_length = prog_title_length;
3899         u_char *event_name = (u_char *) short_event_descriptor + EIT_SHORT_EVENT_DESCRIPTOR_SIZE;
3900         memcpy(event_name, prog_title.c_str(), prog_title_length);
3901
3902         // Set text length
3903         event_name[prog_title_length] = 0;
3904
3905         if ( sumText.length() > 0 )
3906         // There is summary info
3907         {
3908                 unsigned int sum_length = sumText.length();
3909                 if ( sum_length + short_event_descriptor->descriptor_length <= 0xff )
3910                 // Store summary in short event descriptor
3911                 {
3912                         // Increase all relevant lengths
3913                         event_name[prog_title_length] = sum_length;
3914                         short_event_descriptor->descriptor_length += sum_length;
3915                         packet_length += sum_length;
3916                         descr_ll += sum_length;
3917                         sumText.copy( (char *) event_name+prog_title_length+1, sum_length );
3918                 }
3919                 else
3920                 // Store summary in extended event descriptors
3921                 {
3922                         int remaining_sum_length = sumText.length();
3923                         int nbr_descr = int(remaining_sum_length/247) + 1;
3924                         for ( int i=0; i < nbr_descr; i++)
3925                         // Loop once per extended event descriptor
3926                         {
3927                                 eit_extended_descriptor_struct *ext_event_descriptor = (eit_extended_descriptor_struct *) (data + packet_length);
3928                                 sum_length = remaining_sum_length > 247 ? 247 : remaining_sum_length;
3929                                 remaining_sum_length -= sum_length;
3930                                 packet_length += 8 + sum_length;
3931                                 descr_ll += 8 + sum_length;
3932
3933                                 ext_event_descriptor->descriptor_tag = EIT_EXTENDED_EVENT_DESCRIPOR;
3934                                 ext_event_descriptor->descriptor_length = sum_length + 6;
3935                                 ext_event_descriptor->descriptor_number = i;
3936                                 ext_event_descriptor->last_descriptor_number = nbr_descr - 1;
3937                                 ext_event_descriptor->iso_639_2_language_code_1 = 'e';
3938                                 ext_event_descriptor->iso_639_2_language_code_2 = 'n';
3939                                 ext_event_descriptor->iso_639_2_language_code_3 = 'g';
3940                                 u_char *the_text = (u_char *) ext_event_descriptor + 8;
3941                                 the_text[-2] = 0;
3942                                 the_text[-1] = sum_length;
3943                                 sumText.copy( (char *) the_text, sum_length, sumText.length() - sum_length - remaining_sum_length );
3944                         }
3945                 }
3946         }
3947
3948         if (!isMHW2)
3949         {
3950                 // Add content descriptor
3951                 u_char *descriptor = (u_char *) data + packet_length;
3952                 packet_length += 4;
3953                 descr_ll += 4;
3954
3955                 int content_id = 0;
3956                 std::string content_descr = (char *) delimitName( m_themes[itTitle->second.theme_id].name, name, 15 );
3957                 if ( content_descr.find( "FILM" ) != std::string::npos )
3958                         content_id = 0x10;
3959                 else if ( content_descr.find( "SPORT" ) != std::string::npos )
3960                         content_id = 0x40;
3961
3962                 descriptor[0] = 0x54;
3963                 descriptor[1] = 2;
3964                 descriptor[2] = content_id;
3965                 descriptor[3] = 0;
3966         }
3967
3968         event_data->descriptors_loop_length_hi = (descr_ll & 0xf00)>>8;
3969         event_data->descriptors_loop_length_lo = (descr_ll & 0xff);
3970
3971         packet->section_length_hi =  ((packet_length - 3)&0xf00)>>8;
3972         packet->section_length_lo =  (packet_length - 3)&0xff;
3973
3974         // Feed the data to eEPGCache::sectionRead()
3975         cache->sectionRead( data, MHW, this );
3976 }
3977
3978 void eEPGCache::channel_data::startMHWTimeout(int msec)
3979 {
3980         m_MHWTimeoutTimer->start(msec,true);
3981         m_MHWTimeoutet=false;
3982 }
3983
3984 void eEPGCache::channel_data::startMHWReader(uint16_t pid, uint8_t tid)
3985 {
3986         m_MHWFilterMask.pid = pid;
3987         m_MHWFilterMask.data[0] = tid;
3988         m_MHWReader->start(m_MHWFilterMask);
3989 //      eDebug("[eEPGCache] start 0x%02x 0x%02x", pid, tid);
3990 }
3991
3992 void eEPGCache::channel_data::startMHWReader2(uint16_t pid, uint8_t tid, int ext)
3993 {
3994         m_MHWFilterMask2.pid = pid;
3995         m_MHWFilterMask2.data[0] = tid;
3996         if (ext != -1)
3997         {
3998                 m_MHWFilterMask2.data[1] = ext;
3999                 m_MHWFilterMask2.mask[1] = 0xFF;
4000 //              eDebug("[eEPGCache] start 0x%03x 0x%02x 0x%02x", pid, tid, ext);
4001         }
4002         else
4003         {
4004                 m_MHWFilterMask2.data[1] = 0;
4005                 m_MHWFilterMask2.mask[1] = 0;
4006 //              eDebug("[eEPGCache] start 0x%02x 0x%02x", pid, tid);
4007         }
4008         m_MHWReader2->start(m_MHWFilterMask2);
4009 }
4010
4011 void eEPGCache::channel_data::readMHWData(const uint8_t *data)
4012 {
4013         if ( m_MHWReader2 )
4014                 m_MHWReader2->stop();
4015
4016         if ( state > 1 || // aborted
4017                 // have si data.. so we dont read mhw data
4018                 (haveData & (SCHEDULE|SCHEDULE_OTHER|VIASAT)) )
4019         {
4020                 eDebug("[eEPGCache] mhw aborted %d", state);
4021         }
4022         else if (m_MHWFilterMask.pid == 0xD3 && m_MHWFilterMask.data[0] == 0x91)
4023         // Channels table
4024         {
4025                 int len = ((data[1]&0xf)<<8) + data[2] - 1;
4026                 int record_size = sizeof( mhw_channel_name_t );
4027                 int nbr_records = int (len/record_size);
4028
4029                 m_channels.resize(nbr_records);
4030                 for ( int i = 0; i < nbr_records; i++ )
4031                 {
4032                         mhw_channel_name_t *channel = (mhw_channel_name_t*) &data[4 + i*record_size];
4033                         m_channels[i]=*channel;
4034                 }
4035                 haveData |= MHW;
4036
4037                 eDebug("[eEPGCache] mhw %d channels found", m_channels.size());
4038
4039                 // Channels table has been read, start reading the themes table.
4040                 startMHWReader(0xD3, 0x92);
4041                 return;
4042         }
4043         else if (m_MHWFilterMask.pid == 0xD3 && m_MHWFilterMask.data[0] == 0x92)
4044         // Themes table
4045         {
4046                 int len = ((data[1]&0xf)<<8) + data[2] - 16;
4047                 int record_size = sizeof( mhw_theme_name_t );
4048                 int nbr_records = int (len/record_size);
4049                 int idx_ptr = 0;
4050                 uint8_t next_idx = (uint8_t) *(data + 3 + idx_ptr);
4051                 uint8_t idx = 0;
4052                 uint8_t sub_idx = 0;
4053                 for ( int i = 0; i < nbr_records; i++ )
4054                 {
4055                         mhw_theme_name_t *theme = (mhw_theme_name_t*) &data[19 + i*record_size];
4056                         if ( i >= next_idx )
4057                         {
4058                                 idx = (idx_ptr<<4);
4059                                 idx_ptr++;
4060                                 next_idx = (uint8_t) *(data + 3 + idx_ptr);
4061                                 sub_idx = 0;
4062                         }
4063                         else
4064                                 sub_idx++;
4065
4066                         m_themes[idx+sub_idx] = *theme;
4067                 }
4068                 eDebug("[eEPGCache] mhw %d themes found", m_themes.size());
4069                 // Themes table has been read, start reading the titles table.
4070                 startMHWReader(0xD2, 0x90);
4071                 startMHWTimeout(4000);
4072                 return;
4073         }
4074         else if (m_MHWFilterMask.pid == 0xD2 && m_MHWFilterMask.data[0] == 0x90)
4075         // Titles table
4076         {
4077                 mhw_title_t *title = (mhw_title_t*) data;
4078                 uint8_t name[24];
4079                 std::string prog_title = (char *) delimitName( title->title, name, 23 );
4080
4081                 if ( title->channel_id == 0xFF || prog_title.substr(0,7) == "BIENTOT" ) // Separator or BIENTOT record
4082                         return; // Continue reading of the current table.
4083                 else
4084                 {
4085                         // Create unique key per title
4086                         uint32_t title_id = ((title->channel_id)<<16)|((title->dh.day)<<13)|((title->dh.hours)<<8)|
4087                                 (title->ms.minutes);
4088                         uint32_t program_id = ((title->program_id_hi)<<24)|((title->program_id_mh)<<16)|
4089                                 ((title->program_id_ml)<<8)|(title->program_id_lo);
4090
4091                         if ( m_titles.find( title_id ) == m_titles.end() )
4092                         {
4093                                 startMHWTimeout(4000);
4094                                 title->mhw2_mjd_hi = 0;
4095                                 title->mhw2_mjd_lo = 0;
4096                                 title->mhw2_duration_hi = 0;
4097                                 title->mhw2_duration_lo = 0;
4098                                 m_titles[ title_id ] = *title;
4099                                 if ( (title->ms.summary_available) && (m_program_ids.find(program_id) == m_program_ids.end()) )
4100                                         // program_ids will be used to gather summaries.
4101                                         m_program_ids.insert(std::pair<uint32_t,uint32_t>(program_id,title_id));
4102                                 return; // Continue reading of the current table.
4103                         }
4104                         else if (!checkMHWTimeout())
4105                                 return;
4106                 }
4107                 if ( !m_program_ids.empty())
4108                 {
4109                         // Titles table has been read, there are summaries to read.
4110                         // Start reading summaries, store corresponding titles on the fly.
4111                         startMHWReader(0xD3, 0x90);
4112                         eDebug("[eEPGCache] mhw %d titles(%d with summary) found",
4113                                 m_titles.size(),
4114                                 m_program_ids.size());
4115                         startMHWTimeout(4000);
4116                         return;
4117                 }
4118         }
4119         else if (m_MHWFilterMask.pid == 0xD3 && m_MHWFilterMask.data[0] == 0x90)
4120         // Summaries table
4121         {
4122                 mhw_summary_t *summary = (mhw_summary_t*) data;
4123
4124                 // Create unique key per record
4125                 uint32_t program_id = ((summary->program_id_hi)<<24)|((summary->program_id_mh)<<16)|
4126                         ((summary->program_id_ml)<<8)|(summary->program_id_lo);
4127                 int len = ((data[1]&0xf)<<8) + data[2];
4128
4129                 // ugly workaround to convert const uint8_t* to char*
4130                 char *tmp=0;
4131                 memcpy(&tmp, &data, sizeof(void*));
4132                 tmp[len+3] = 0; // Terminate as a string.
4133
4134                 std::multimap<uint32_t, uint32_t>::iterator itProgid( m_program_ids.find( program_id ) );
4135                 if ( itProgid == m_program_ids.end() )
4136                 { /*    This part is to prevent to looping forever if some summaries are not received yet.
4137                         There is a timeout of 4 sec. after the last successfully read summary. */
4138                         if (!m_program_ids.empty() && !checkMHWTimeout())
4139                                 return; // Continue reading of the current table.
4140                 }
4141                 else
4142                 {
4143                         std::string the_text = (char *) (data + 11 + summary->nb_replays * 7);
4144
4145                         unsigned int pos=0;
4146                         while((pos = the_text.find("\r\n")) != std::string::npos)
4147                                 the_text.replace(pos, 2, " ");
4148
4149                         // Find corresponding title, store title and summary in epgcache.
4150                         std::map<uint32_t, mhw_title_t>::iterator itTitle( m_titles.find( itProgid->second ) );
4151                         if ( itTitle != m_titles.end() )
4152                         {
4153                                 startMHWTimeout(4000);
4154                                 storeMHWTitle( itTitle, the_text, data );
4155                                 m_titles.erase( itTitle );
4156                         }
4157                         m_program_ids.erase( itProgid );
4158                         if ( !m_program_ids.empty() )
4159                                 return; // Continue reading of the current table.
4160                 }
4161         }
4162         eDebug("[eEPGCache] mhw finished(%ld) %d summaries not found",
4163                 ::time(0),
4164                 m_program_ids.size());
4165         // Summaries have been read, titles that have summaries have been stored.
4166         // Now store titles that do not have summaries.
4167         for (std::map<uint32_t, mhw_title_t>::iterator itTitle(m_titles.begin()); itTitle != m_titles.end(); itTitle++)
4168                 storeMHWTitle( itTitle, "", data );
4169         isRunning &= ~MHW;
4170         m_MHWConn=0;
4171         if ( m_MHWReader )
4172                 m_MHWReader->stop();
4173         if (haveData)
4174                 finishEPG();
4175 }
4176
4177 void eEPGCache::channel_data::readMHWData2(const uint8_t *data)
4178 {
4179         int dataLen = (((data[1]&0xf) << 8) | data[2]) + 3;
4180
4181         if ( m_MHWReader )
4182                 m_MHWReader->stop();
4183
4184         if ( state > 1 || // aborted
4185                 // have si data.. so we dont read mhw data
4186                 (haveData & (SCHEDULE|SCHEDULE_OTHER|VIASAT)) )
4187         {
4188                 eDebug("[eEPGCache] mhw2 aborted %d", state);
4189         }
4190         else if (m_MHWFilterMask2.pid == m_mhw2_channel_pid && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 0)
4191         // Channels table
4192         {
4193                 int num_channels = data[120];
4194                 m_channels.resize(num_channels);
4195                 if(dataLen > 120)
4196                 {
4197                         int ptr = 121 + 8 * num_channels;
4198                         if( dataLen > ptr )
4199                         {
4200                                 for( int chid = 0; chid < num_channels; ++chid )
4201                                 {
4202                                         ptr += ( data[ptr] & 0x0f ) + 1;
4203                                         if( dataLen < ptr )
4204                                                 goto abort;
4205                                 }
4206                         }
4207                         else
4208                                 goto abort;
4209                 }
4210                 else
4211                         goto abort;
4212                 // data seems consistent...
4213                 const uint8_t *tmp = data+121;
4214                 for (int i=0; i < num_channels; ++i)
4215                 {
4216                         mhw_channel_name_t channel;
4217                         channel.network_id_hi = *(tmp++);
4218                         channel.network_id_lo = *(tmp++);
4219                         channel.transport_stream_id_hi = *(tmp++);
4220                         channel.transport_stream_id_lo = *(tmp++);
4221                         channel.channel_id_hi = *(tmp++);
4222                         channel.channel_id_lo = *(tmp++);
4223                         m_channels[i]=channel;
4224 //                      eDebug("[eEPGCache] %d(%02x) %04x: %02x %02x", i, i, (channel.channel_id_hi << 8) | channel.channel_id_lo, *tmp, *(tmp+1));
4225                         tmp+=2;
4226                 }
4227                 for (int i=0; i < num_channels; ++i)
4228                 {
4229                         mhw_channel_name_t &channel = m_channels[i];
4230                         int channel_name_len=*(tmp++)&0x0f;
4231                         int x=0;
4232                         for (; x < channel_name_len; ++x)
4233                                 channel.name[x]=*(tmp++);
4234                         channel.name[x+1]=0;
4235 //                      eDebug("[eEPGCache] %d(%02x) %s", i, i, channel.name);
4236                 }
4237                 haveData |= MHW;
4238                 eDebug("[eEPGCache] mhw2 %d channels found", m_channels.size());
4239         }
4240         else if (m_MHWFilterMask2.pid == m_mhw2_channel_pid && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 1)
4241         {
4242                 // Themes table
4243                 eDebug("[eEPGCache] mhw2 themes nyi");
4244         }
4245         else if (m_MHWFilterMask2.pid == m_mhw2_title_pid && m_MHWFilterMask2.data[0] == 0xe6)
4246         // Titles table
4247         {
4248                 int pos=18;
4249                 bool valid=false;
4250                 bool finish=false;
4251
4252 //              eDebug("[eEPGCache] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
4253 //                      data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10],
4254 //                      data[11], data[12], data[13], data[14], data[15], data[16], data[17] );
4255
4256                 while( pos < dataLen && !valid)
4257                 {
4258                         pos += 18;
4259                         pos += (data[pos] & 0x3F) + 4;
4260                         if( pos == dataLen )
4261                                 valid = true;
4262                 }
4263
4264                 if (!valid)
4265                 {
4266                         if (dataLen > 18)
4267                                 eDebug("[eEPGCache] mhw2 title table invalid!!");
4268                         if (checkMHWTimeout())
4269                                 goto abort;
4270                         if (!m_MHWTimeoutTimer->isActive())
4271                                 startMHWTimeout(5000);
4272                         return; // continue reading
4273                 }
4274
4275                 // data seems consistent...
4276                 mhw_title_t title;
4277                 pos = 18;
4278                 while (pos < dataLen)
4279                 {
4280 //                      eDebugNoNewLine("[eEPGCache]     [%02x] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x [%02x %02x %02x %02x %02x %02x %02x] LL - DESCR - ",
4281 //                              data[pos], data[pos+1], data[pos+2], data[pos+3], data[pos+4], data[pos+5], data[pos+6], data[pos+7], 
4282 //                              data[pos+8], data[pos+9], data[pos+10], data[pos+11], data[pos+12], data[pos+13], data[pos+14], data[pos+15], data[pos+16], data[pos+17]);
4283                         title.channel_id = data[pos]+1;
4284                         title.mhw2_mjd_hi = data[pos+11];
4285                         title.mhw2_mjd_lo = data[pos+12];
4286                         title.mhw2_hours = data[pos+13];
4287                         title.mhw2_minutes = data[pos+14];
4288                         title.mhw2_seconds = data[pos+15];
4289                         int duration = ((data[pos+16] << 8)|data[pos+17]) >> 4;
4290                         title.mhw2_duration_hi = (duration&0xFF00) >> 8;
4291                         title.mhw2_duration_lo = duration&0xFF;
4292
4293                         // Create unique key per title
4294                         uint32_t title_id = (data[pos+7] << 24) | (data[pos+8] << 16) | (data[pos+9] << 8) | data[pos+10];
4295
4296                         uint8_t slen = data[pos+18] & 0x3f;
4297                         uint8_t *dest = ((uint8_t*)title.title)-4;
4298                         memcpy(dest, &data[pos+19], slen>35 ? 35 : slen);
4299                         memset(dest+slen, 0, 35-slen);
4300                         pos += 19 + slen;
4301 //                      eDebug("%02x [%02x %02x]: %s", data[pos], data[pos+1], data[pos+2], dest);
4302
4303 //                      not used theme id (data[7] & 0x3f) + (data[pos] & 0x3f);
4304                         uint32_t summary_id = (data[pos+1] << 8) | data[pos+2];
4305
4306 //                      if (title.channel_id > m_channels.size())
4307 //                              eDebug("[eEPGCache] channel_id(%d %02x) to big!!", title.channel_id);
4308
4309 //                      eDebug("[eEPGCache] pos %d prog_id %02x %02x chid %02x summary_id %04x dest %p len %d\n",
4310 //                              pos, title.program_id_ml, title.program_id_lo, title.channel_id, summary_id, dest, slen);
4311
4312 //                      eDebug("[eEPGCache] title_id %08x -> summary_id %04x\n", title_id, summary_id);
4313
4314                         pos += 3;
4315
4316                         std::map<uint32_t, mhw_title_t>::iterator it = m_titles.find( title_id );
4317                         if ( it == m_titles.end() )
4318                         {
4319                                 startMHWTimeout(5000);
4320                                 m_titles[ title_id ] = title;
4321                                 if (summary_id != 0xFFFF)
4322                                 {
4323                                         bool add=true;
4324                                         std::multimap<uint32_t, uint32_t>::iterator it(m_program_ids.lower_bound(summary_id));
4325                                         while (it != m_program_ids.end() && it->first == summary_id)
4326                                         {
4327                                                 if (it->second == title_id) {
4328                                                         add=false;
4329                                                         break;
4330                                                 }
4331                                                 ++it;
4332                                         }
4333                                         if (add)
4334                                                 m_program_ids.insert(std::pair<uint32_t,uint32_t>(summary_id,title_id));
4335                                 }
4336                         }
4337                         else
4338                         {
4339                                 if ( !checkMHWTimeout() )
4340                                         continue;       // Continue reading of the current table.
4341                                 finish=true;
4342                                 break;
4343                         }
4344                 }
4345                 if (finish)
4346                 {
4347                         eDebug("[eEPGCache] mhw2 %d titles(%d with summary) found", m_titles.size(), m_program_ids.size());
4348                         if (!m_program_ids.empty())
4349                         {
4350                                 // Titles table has been read, there are summaries to read.
4351                                 // Start reading summaries, store corresponding titles on the fly.
4352                                 startMHWReader2(m_mhw2_summary_pid, 0x96);
4353                                 startMHWTimeout(15000);
4354                                 return;
4355                         }
4356                 }
4357                 else
4358                         return;
4359         }
4360         else if (m_MHWFilterMask2.pid == m_mhw2_summary_pid && m_MHWFilterMask2.data[0] == 0x96)
4361         // Summaries table
4362         {
4363                 if (!checkMHWTimeout())
4364                 {
4365                         int len, loop, pos, lenline;
4366                         bool valid;
4367                         valid = true;
4368                         if( dataLen > 15 )
4369                         {
4370                                 loop = data[14];
4371                                 pos = 15 + loop;
4372                                 if( dataLen > pos )
4373                                 {
4374                                         loop = data[pos] & 0x0f;
4375                                         pos += 1;
4376                                         if( dataLen > pos )
4377                                         {
4378                                                 len = 0;
4379                                                 for( ; loop > 0; --loop )
4380                                                 {
4381                                                         if( dataLen > (pos+len) )
4382                                                         {
4383                                                                 lenline = data[pos+len];
4384                                                                 len += lenline + 1;
4385                                                         }
4386                                                         else
4387                                                                 valid=false;
4388                                                 }
4389                                         }
4390                                 }
4391                         }
4392                         else
4393                                 return;  // continue reading
4394
4395                         if (valid)
4396                         {
4397                                 // data seems consistent...
4398                                 uint32_t summary_id = (data[3]<<8)|data[4];
4399 //                              eDebug ("[eEPGCache] summary id %04x\n", summary_id);
4400 //                              eDebug("[eEPGCache] [%02x %02x] %02x %02x %02x %02x %02x %02x %02x %02x XX\n", data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12], data[13] );
4401
4402                                 // ugly workaround to convert const uint8_t* to char*
4403                                 char *tmp=0;
4404                                 memcpy(&tmp, &data, sizeof(void*));
4405
4406                                 len = 0;
4407                                 loop = data[14];
4408                                 pos = 15 + loop;
4409                                 loop = tmp[pos] & 0x0f;
4410                                 pos += 1;
4411                                 for( ; loop > 0; loop -- )
4412                                 {
4413                                         lenline = tmp[pos+len];
4414                                         tmp[pos+len] = ' ';
4415                                         len += lenline + 1;
4416                                 }
4417                                 if( len > 0 )
4418                                         tmp[pos+len] = 0;
4419                                 else
4420                                         tmp[pos+1] = 0;
4421
4422                                 std::multimap<uint32_t, uint32_t>::iterator itProgId( m_program_ids.lower_bound(summary_id) );
4423                                 if ( itProgId == m_program_ids.end() || itProgId->first != summary_id)
4424                                 { /*    This part is to prevent to looping forever if some summaries are not received yet.
4425                                         There is a timeout of 4 sec. after the last successfully read summary. */
4426                                         if ( !m_program_ids.empty() )
4427                                                 return; // Continue reading of the current table.
4428                                 }
4429                                 else
4430                                 {
4431                                         startMHWTimeout(15000);
4432                                         std::string the_text = (char *) (data + pos + 1);
4433
4434 //                                      eDebug ("[eEPGCache] summary id %04x : %s\n", summary_id, data+pos+1);
4435
4436                                         while( itProgId != m_program_ids.end() && itProgId->first == summary_id )
4437                                         {
4438 //                                              eDebug("[eEPGCache] .");
4439                                                 // Find corresponding title, store title and summary in epgcache.
4440                                                 std::map<uint32_t, mhw_title_t>::iterator itTitle( m_titles.find( itProgId->second ) );
4441                                                 if ( itTitle != m_titles.end() )
4442                                                 {
4443                                                         storeMHWTitle( itTitle, the_text, data );
4444                                                         m_titles.erase( itTitle );
4445                                                 }
4446                                                 m_program_ids.erase( itProgId++ );
4447                                         }
4448                                         if ( !m_program_ids.empty() )
4449                                                 return; // Continue reading of the current table.
4450                                 }
4451                         }
4452                         else
4453                                 return;  // continue reading
4454                 }
4455         }
4456         if (isRunning & eEPGCache::MHW)
4457         {
4458                 if ( m_MHWFilterMask2.pid == m_mhw2_channel_pid && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 0)
4459                 {
4460                         // Channels table has been read, start reading the themes table.
4461                         startMHWReader2(m_mhw2_channel_pid, 0xC8, 1);
4462                         return;
4463                 }
4464                 else if ( m_MHWFilterMask2.pid == m_mhw2_channel_pid && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 1)
4465                 {
4466                         // Themes table has been read, start reading the titles table.
4467                         startMHWReader2(m_mhw2_title_pid, 0xe6);
4468                         return;
4469                 }
4470                 else
4471                 {
4472                         // Summaries have been read, titles that have summaries have been stored.
4473                         // Now store titles that do not have summaries.
4474                         for (std::map<uint32_t, mhw_title_t>::iterator itTitle(m_titles.begin()); itTitle != m_titles.end(); itTitle++)
4475                                 storeMHWTitle( itTitle, "", data );
4476                         eDebug("[eEPGCache] mhw2 finished(%ld) %d summaries not found",
4477                                 ::time(0),
4478                                 m_program_ids.size());
4479                 }
4480         }
4481 abort:
4482         isRunning &= ~MHW;
4483         m_MHWConn2=0;
4484         if ( m_MHWReader2 )
4485                 m_MHWReader2->stop();
4486         if (haveData)
4487                 finishEPG();
4488 }
4489 #endif