premiereepg.c
branchtrunk
changeset 10 967afc97e51d
parent 8 b5bd55cfd28f
child 12 5213337a6614
equal deleted inserted replaced
9:23e350c6b6d9 10:967afc97e51d
     1 /*
     1 /*
     2  * PremiereEpg plugin to VDR (C++)
     2  * PremiereEpg plugin to VDR (C++)
     3  *
     3  *
     4  * (C) 2005 Stefan Huelswitt <s.huelswitt@gmx.de>
     4  * (C) 2005-2006 Stefan Huelswitt <s.huelswitt@gmx.de>
     5  *
     5  *
     6  * This code is base on the commandline tool premiereepg2vdr
     6  * This code is base on the commandline tool premiereepg2vdr
     7  * (C) 2004-2005 by Axel Katzur software@katzur.de
     7  * (C) 2004-2005 by Axel Katzur software@katzur.de
     8  * but has been rewritten from scratch
     8  * but has been rewritten from scratch
     9  *
     9  *
    27 #include <vdr/filter.h>
    27 #include <vdr/filter.h>
    28 #include <vdr/epg.h>
    28 #include <vdr/epg.h>
    29 #include <vdr/channels.h>
    29 #include <vdr/channels.h>
    30 #include <vdr/dvbdevice.h>
    30 #include <vdr/dvbdevice.h>
    31 #include <vdr/i18n.h>
    31 #include <vdr/i18n.h>
       
    32 #include <vdr/config.h>
    32 #include <libsi/section.h>
    33 #include <libsi/section.h>
    33 #include <libsi/descriptor.h>
    34 #include <libsi/descriptor.h>
    34 
    35 
    35 //#define DEBUG
    36 //#define DEBUG
    36 //#define DEBUG2
    37 //#define DEBUG2
    47 #endif
    48 #endif
    48 
    49 
    49 #define PMT_SCAN_TIMEOUT  10  // seconds
    50 #define PMT_SCAN_TIMEOUT  10  // seconds
    50 #define PMT_SCAN_IDLE     300 // seconds
    51 #define PMT_SCAN_IDLE     300 // seconds
    51 
    52 
    52 static const char *VERSION        = "0.0.5";
    53 static const char *VERSION        = "0.0.6";
    53 static const char *DESCRIPTION    = "Parses extended Premiere EPG data";
    54 static const char *DESCRIPTION    = "Parses extended Premiere EPG data";
       
    55 
       
    56 #if APIVERSNUM < 10401
       
    57 #error You need at least VDR API version 1.4.1 for this plugin
       
    58 #endif
    54 
    59 
    55 // --- cSetupPremiereEpg -------------------------------------------------------
    60 // --- cSetupPremiereEpg -------------------------------------------------------
    56 
    61 
    57 const char *optPats[] = {
    62 const char *optPats[] = {
    58   "%s",
    63   "%s",
   328   SetupStore("OptionPattern",SetupPE.OptPat);
   333   SetupStore("OptionPattern",SetupPE.OptPat);
   329   SetupStore("OrderInfo",SetupPE.OrderInfo);
   334   SetupStore("OrderInfo",SetupPE.OrderInfo);
   330   SetupStore("RatingInfo",SetupPE.RatingInfo);
   335   SetupStore("RatingInfo",SetupPE.RatingInfo);
   331 }
   336 }
   332 
   337 
   333 // --- CIT ---------------------------------------------------------------------
   338 // --- CRC16 -------------------------------------------------------------------
   334 
   339 
   335 namespace SI {
   340 #define POLY 0xA001 // CRC16
   336 
   341 
   337 #define CIT_LEN 17
   342 unsigned int crc16(unsigned int crc, unsigned char const *p, int len)
   338 
   343 {
   339 struct cit {
   344   while(len--) {
   340    u_char table_id                               :8;
   345     crc^=*p++;
   341 #if BYTE_ORDER == BIG_ENDIAN
   346     for(int i=0; i<8; i++)
   342    u_char section_syntax_indicator               :1;
   347       crc=(crc&1) ? (crc>>1)^POLY : (crc>>1);
   343    u_char                                        :3;
       
   344    u_char section_length_hi                      :4;
       
   345 #else
       
   346    u_char section_length_hi                      :4;
       
   347    u_char                                        :3;
       
   348    u_char section_syntax_indicator               :1;
       
   349 #endif
       
   350    u_char section_length_lo                      :8;
       
   351    u_char service_id_hi                          :8;
       
   352    u_char service_id_lo                          :8;
       
   353 #if BYTE_ORDER == BIG_ENDIAN
       
   354    u_char                                        :2;
       
   355    u_char version_number                         :5;
       
   356    u_char current_next_indicator                 :1;
       
   357 #else
       
   358    u_char current_next_indicator                 :1;
       
   359    u_char version_number                         :5;
       
   360    u_char                                        :2;
       
   361 #endif
       
   362    u_char section_number                         :8;
       
   363    u_char last_section_number                    :8;
       
   364    u_char content_id_hi_hi                       :8;
       
   365    u_char content_id_hi_lo                       :8;
       
   366    u_char content_id_lo_hi                       :8;
       
   367    u_char content_id_lo_lo                       :8;
       
   368    u_char duration_h                             :8;
       
   369    u_char duration_m                             :8;
       
   370    u_char duration_s                             :8;
       
   371 #if BYTE_ORDER == BIG_ENDIAN
       
   372    u_char                                        :4;
       
   373    u_char descriptors_loop_length_hi             :4;
       
   374 #else
       
   375    u_char descriptors_loop_length_hi             :4;
       
   376    u_char                                        :4;
       
   377 #endif
       
   378    u_char descriptors_loop_length_lo             :8;
       
   379 };
       
   380 
       
   381 class CIT : public NumberedSection {
       
   382 public:
       
   383    CIT(const unsigned char *data, bool doCopy=true) : NumberedSection(data, doCopy) {}
       
   384    CIT() {}
       
   385    int getContentId(void) const;
       
   386    time_t getDuration(void) const;
       
   387    DescriptorLoop eventDescriptors;
       
   388 protected:
       
   389    virtual void Parse(void);
       
   390 private:
       
   391    const cit *s;
       
   392 };
       
   393 
       
   394 int CIT::getContentId(void) const {
       
   395    return (HILO(s->content_id_hi)<<16) | (HILO(s->content_id_lo));
       
   396 }
       
   397 
       
   398 time_t CIT::getDuration(void) const {
       
   399    return DVBTime::getDuration(s->duration_h,s->duration_m,s->duration_s);
       
   400 }
       
   401 
       
   402 void CIT::Parse(void) {
       
   403 #if VDRVERSNUM >= 10343
       
   404    int offset=0;
       
   405 #else
       
   406    unsigned int offset=0;
       
   407 #endif
       
   408    data.setPointerAndOffset<const cit>(s, offset);
       
   409    eventDescriptors.setData(data+offset,HILO(s->descriptors_loop_length));
       
   410 }
       
   411 
       
   412 } // end of namespace
       
   413 
       
   414 // --- cDescrF2 ----------------------------------------------------------------
       
   415 
       
   416 class cDescrF2 {
       
   417 private:
       
   418   SI::Descriptor *d;
       
   419   SI::CharArray data;
       
   420   int idx, loop, nloop, index;
       
   421 public:
       
   422   cDescrF2(SI::Descriptor *D);
       
   423   int TransportStreamId(void) { return data.TwoBytes(2); }
       
   424   int OrgNetworkId(void)      { return data.TwoBytes(4); }
       
   425   int ServiceId(void)         { return data.TwoBytes(6); }
       
   426   void Start(void);
       
   427   bool Next(void);
       
   428   time_t StartTime(void);
       
   429   int Index(void) { return index; }
       
   430   };
       
   431 
       
   432 cDescrF2::cDescrF2(SI::Descriptor *D)
       
   433 {
       
   434   d=D;
       
   435   data=d->getData();
       
   436   Start();
       
   437 }
       
   438 
       
   439 void cDescrF2::Start(void)
       
   440 {
       
   441   idx=8; loop=0; nloop=-3; index=-1;
       
   442 }
       
   443 
       
   444 bool cDescrF2::Next(void)
       
   445 {
       
   446   loop+=3;
       
   447   if(loop>=nloop) {
       
   448     idx+=nloop+3;
       
   449     if(idx>=d->getLength()) return false;
       
   450     loop=0; nloop=data[idx+2];
       
   451     }
   348     }
   452  index++;
   349   return crc&0xFFFF;
   453  return true;
       
   454 }
       
   455 
       
   456 time_t cDescrF2::StartTime(void)
       
   457 {
       
   458   int off=idx+3+loop;
       
   459   return SI::DVBTime::getTime(data[idx+0],data[idx+1],data[off+0],data[off+1],data[off+2]);
       
   460 }
   350 }
   461 
   351 
   462 // --- cFilterPremiereEpg ------------------------------------------------------
   352 // --- cFilterPremiereEpg ------------------------------------------------------
       
   353 
       
   354 #define STARTTIME_BIAS (20*60)
   463 
   355 
   464 class cFilterPremiereEpg : public cFilter {
   356 class cFilterPremiereEpg : public cFilter {
   465 private:
   357 private:
   466   int pmtpid, pmtidx, pmtnext;
   358   int pmtpid, pmtsid, pmtidx, pmtnext;
   467   //
   359   //
   468   void NextPmt(void);
   360   void NextPmt(void);
   469 protected:
   361 protected:
   470   virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length);
   362   virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length);
   471 public:
   363 public:
   501   d(printf("PMT next\n"))
   393   d(printf("PMT next\n"))
   502 }
   394 }
   503 
   395 
   504 void cFilterPremiereEpg::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
   396 void cFilterPremiereEpg::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
   505 {
   397 {
       
   398   int now=time(0);
   506   if(Pid==0 && Tid==SI::TableIdPAT) {
   399   if(Pid==0 && Tid==SI::TableIdPAT) {
   507     int now=time(0);
       
   508     if(!pmtnext || now>pmtnext) {
   400     if(!pmtnext || now>pmtnext) {
   509       if(pmtpid) NextPmt();
   401       if(pmtpid) NextPmt();
   510       if(!pmtpid) {
   402       if(!pmtpid) {
   511         SI::PAT pat(Data,false);
   403         SI::PAT pat(Data,false);
   512         if(pat.CheckCRCAndParse()) {
   404         if(pat.CheckCRCAndParse()) {
   514           int idx=0;
   406           int idx=0;
   515           for(SI::Loop::Iterator it; pat.associationLoop.getNext(assoc,it);) {
   407           for(SI::Loop::Iterator it; pat.associationLoop.getNext(assoc,it);) {
   516             if(!assoc.isNITPid()) {
   408             if(!assoc.isNITPid()) {
   517               if(idx++==pmtidx) {
   409               if(idx++==pmtidx) {
   518                 pmtpid=assoc.getPid();
   410                 pmtpid=assoc.getPid();
       
   411                 pmtsid=assoc.getServiceId();
   519                 Add(pmtpid,0x02);
   412                 Add(pmtpid,0x02);
   520                 pmtnext=now+PMT_SCAN_TIMEOUT;
   413                 pmtnext=now+PMT_SCAN_TIMEOUT;
   521                 d(printf("PMT pid now 0x%04x (idx=%d)\n",pmtpid,pmtidx))
   414                 d(printf("PMT pid now 0x%04x (idx=%d)\n",pmtpid,pmtidx))
   522                 break;
   415                 break;
   523                 }
   416                 }
   532         }
   425         }
   533       }
   426       }
   534     }
   427     }
   535   else if(pmtpid>0 && Pid==pmtpid && Tid==SI::TableIdPMT && Source() && Transponder()) {
   428   else if(pmtpid>0 && Pid==pmtpid && Tid==SI::TableIdPMT && Source() && Transponder()) {
   536     SI::PMT pmt(Data,false);
   429     SI::PMT pmt(Data,false);
   537     if(pmt.CheckCRCAndParse()) {
   430     if(pmt.CheckCRCAndParse() && pmt.getServiceId()==pmtsid) {
   538       SI::PMT::Stream stream;
   431       SI::PMT::Stream stream;
   539       for(SI::Loop::Iterator it; pmt.streamLoop.getNext(stream,it); ) {
   432       for(SI::Loop::Iterator it; pmt.streamLoop.getNext(stream,it); ) {
   540         if(stream.getStreamType()==0x05) {
   433         if(stream.getStreamType()==0x05) {
   541           SI::CharArray data=stream.getData();
   434           SI::CharArray data=stream.getData();
   542           if((data[1]&0xE0)==0xE0 && (data[3]&0xF0)==0xF0) {
   435           if((data[1]&0xE0)==0xE0 && (data[3]&0xF0)==0xF0) {
   573         }
   466         }
   574       NextPmt(); pmtnext=0;
   467       NextPmt(); pmtnext=0;
   575       }
   468       }
   576     }
   469     }
   577   else if(Tid==0xA0 && Source()) {
   470   else if(Tid==0xA0 && Source()) {
   578     SI::CIT cit(Data,false);
   471     SI::PremiereCIT cit(Data,false);
   579     if(cit.CheckCRCAndParse()) {
   472     if(cit.CheckCRCAndParse()) {
   580       cSchedulesLock SchedulesLock(true,10);
   473       cSchedulesLock SchedulesLock(true,10);
   581       cSchedules *Schedules=(cSchedules *)cSchedules::Schedules(SchedulesLock);
   474       cSchedules *Schedules=(cSchedules *)cSchedules::Schedules(SchedulesLock);
   582       if(Schedules) {
   475       if(Schedules) {
   583         int nCount=0;
   476         int nCount=0;
   584         time_t firstTime=0;
       
   585         SI::Descriptor *d;
       
   586         int LanguagePreferenceShort=-1;
       
   587         int LanguagePreferenceExt=-1;
       
   588         bool UseExtendedEventDescriptor=false;
       
   589         SI::ExtendedEventDescriptors *ExtendedEventDescriptors=0;
   477         SI::ExtendedEventDescriptors *ExtendedEventDescriptors=0;
   590         SI::ShortEventDescriptor *ShortEventDescriptor=0;
   478         SI::ShortEventDescriptor *ShortEventDescriptor=0;
   591         char *order=0, *rating=0;
   479         char *order=0, *rating=0;
       
   480         {
       
   481         time_t firstTime=0;
       
   482         SI::Descriptor *d;
       
   483         bool UseExtendedEventDescriptor=false;
       
   484         int LanguagePreferenceShort=-1;
       
   485         int LanguagePreferenceExt=-1;
   592         for(SI::Loop::Iterator it; (d=cit.eventDescriptors.getNext(it)); ) {
   486         for(SI::Loop::Iterator it; (d=cit.eventDescriptors.getNext(it)); ) {
   593           switch(d->getDescriptorTag()) {
   487           switch(d->getDescriptorTag()) {
   594             case 0xF0: // order information
   488             case 0xF0: // order information
   595               if(SetupPE.OrderInfo) {
   489               if(SetupPE.OrderInfo) {
   596                 static const char *text[] = {
   490                 static const char *text[] = {
   621                 int l=data[0]; 
   515                 int l=data[0]; 
   622                 if(l>0) p+=snprintf(&buff[p],sizeof(buff)-p," (%.*s)",l,&data[1]);
   516                 if(l>0) p+=snprintf(&buff[p],sizeof(buff)-p," (%.*s)",l,&data[1]);
   623                 if(p>0) rating=strdup(buff);
   517                 if(p>0) rating=strdup(buff);
   624                 }
   518                 }
   625               break;
   519               break;
   626             case 0xF2: // transmisions
   520             case SI::PremiereContentTransmissionDescriptorTag:
   627               if(nCount>=0) {
   521               if(nCount>=0) {
       
   522                 SI::PremiereContentTransmissionDescriptor *pct=(SI::PremiereContentTransmissionDescriptor *)d;
   628                 nCount++;
   523                 nCount++;
   629                 cDescrF2 f2(d);
   524                 SI::PremiereContentTransmissionDescriptor::StartDayEntry sd;
   630                 if(f2.Next()) {
   525                 SI::Loop::Iterator it;
   631                   if(nCount==1) firstTime=f2.StartTime();
   526                 if(pct->startDayLoop.getNext(sd,it)) {
   632                   else {
   527                   SI::PremiereContentTransmissionDescriptor::StartDayEntry::StartTimeEntry st;
   633                     time_t time=f2.StartTime();
   528                   SI::Loop::Iterator it2;
   634                     if(firstTime<time-5*50 || firstTime>time+5*60)
   529                   if(sd.startTimeLoop.getNext(st,it2)) {
       
   530                     time_t StartTime=st.getStartTime(sd.getMJD());
       
   531                     if(nCount==1) firstTime=StartTime;
       
   532                     else if(firstTime<StartTime-5*50 || firstTime>StartTime+5*60)
   635                       nCount=-1;
   533                       nCount=-1;
   636                     }
   534                     }
   637                   }
   535                   }
   638                 }
   536                 }
   639               break;
   537               break;
   640             case SI::ExtendedEventDescriptorTag:
   538             case SI::ExtendedEventDescriptorTag:
   641               {
   539               {
   642               SI::ExtendedEventDescriptor *eed=(SI::ExtendedEventDescriptor *)d;
   540               SI::ExtendedEventDescriptor *eed=(SI::ExtendedEventDescriptor *)d;
   643 #if VDRVERSNUM < 10332
       
   644               if(I18nIsPreferredLanguage(Setup.EPGLanguages,I18nLanguageIndex(eed->languageCode), LanguagePreferenceExt) || !ExtendedEventDescriptors) {
       
   645 #else
       
   646               if(I18nIsPreferredLanguage(Setup.EPGLanguages,eed->languageCode, LanguagePreferenceExt) || !ExtendedEventDescriptors) {
   541               if(I18nIsPreferredLanguage(Setup.EPGLanguages,eed->languageCode, LanguagePreferenceExt) || !ExtendedEventDescriptors) {
   647 #endif
       
   648                  delete ExtendedEventDescriptors;
   542                  delete ExtendedEventDescriptors;
   649                  ExtendedEventDescriptors=new SI::ExtendedEventDescriptors;
   543                  ExtendedEventDescriptors=new SI::ExtendedEventDescriptors;
   650                  UseExtendedEventDescriptor=true;
   544                  UseExtendedEventDescriptor=true;
   651                  }
   545                  }
   652               if(UseExtendedEventDescriptor) {
   546               if(UseExtendedEventDescriptor) {
   658               }
   552               }
   659               break;
   553               break;
   660             case SI::ShortEventDescriptorTag:
   554             case SI::ShortEventDescriptorTag:
   661               {
   555               {
   662               SI::ShortEventDescriptor *sed=(SI::ShortEventDescriptor *)d;
   556               SI::ShortEventDescriptor *sed=(SI::ShortEventDescriptor *)d;
   663 #if VDRVERSNUM < 10332
       
   664               if(I18nIsPreferredLanguage(Setup.EPGLanguages,I18nLanguageIndex(sed->languageCode), LanguagePreferenceShort) || !ShortEventDescriptor) {
       
   665 #else
       
   666               if(I18nIsPreferredLanguage(Setup.EPGLanguages,sed->languageCode, LanguagePreferenceShort) || !ShortEventDescriptor) {
   557               if(I18nIsPreferredLanguage(Setup.EPGLanguages,sed->languageCode, LanguagePreferenceShort) || !ShortEventDescriptor) {
   667 #endif
       
   668                  delete ShortEventDescriptor;
   558                  delete ShortEventDescriptor;
   669                  ShortEventDescriptor=sed;
   559                  ShortEventDescriptor=sed;
   670                  d=NULL; // so that it is not deleted
   560                  d=NULL; // so that it is not deleted
   671                  }
   561                  }
   672               }
   562               }
   674             default:
   564             default:
   675               break;
   565               break;
   676             }
   566             }
   677           delete d;
   567           delete d;
   678           }
   568           }
   679 
   569         }
       
   570 
       
   571         {
   680         bool Modified=false;
   572         bool Modified=false;
   681         int optCount=0;
   573         int optCount=0;
   682         for(SI::Loop::Iterator it; (d=cit.eventDescriptors.getNext(it)); ) {
   574         unsigned int crc[3];
   683           if(d->getDescriptorTag()==0xF2) {
   575         crc[0]=cit.getContentId();
   684             optCount++;
   576         SI::PremiereContentTransmissionDescriptor *pct;
   685 
   577         for(SI::Loop::Iterator it; (pct=(SI::PremiereContentTransmissionDescriptor *)cit.eventDescriptors.getNext(it,SI::PremiereContentTransmissionDescriptorTag)); ) {
   686             cDescrF2 f2(d);
   578           tChannelID channelID(Source(),pct->getOriginalNetworkId(),pct->getTransportStreamId(),pct->getServiceId());
   687             tChannelID channelID(Source(),f2.OrgNetworkId(),f2.TransportStreamId(),f2.ServiceId());
   579           cChannel *channel=Channels.GetByChannelID(channelID,true);
   688             cChannel *channel=Channels.GetByChannelID(channelID,true);
   580           if(!channel) continue;
   689             if(!channel) continue;
   581 
   690 
   582           cSchedule *pSchedule=(cSchedule *)Schedules->GetSchedule(channelID);
   691             cSchedule *pSchedule=(cSchedule *)Schedules->GetSchedule(channelID);
   583           if(!pSchedule) {
   692             if(!pSchedule) {
   584              pSchedule=new cSchedule(channelID);
   693                pSchedule=new cSchedule(channelID);
   585              Schedules->Add(pSchedule);
   694                Schedules->Add(pSchedule);
   586              }
   695                }
   587 
   696 
   588           optCount++;
   697             for(f2.Start(); f2.Next();) {
   589           SI::PremiereContentTransmissionDescriptor::StartDayEntry sd;
   698               u_int16_t EventId=(cit.getContentId()<<4) | f2.Index();
   590           int index=0;
   699               time_t StartTime=f2.StartTime();
   591           for(SI::Loop::Iterator it; pct->startDayLoop.getNext(sd,it); ) {
   700 
   592             int mjd=sd.getMJD();
       
   593             SI::PremiereContentTransmissionDescriptor::StartDayEntry::StartTimeEntry st;
       
   594             for(SI::Loop::Iterator it2; sd.startTimeLoop.getNext(st,it2); ) {
       
   595               time_t StartTime=st.getStartTime(mjd);
       
   596               time_t EndTime=StartTime+cit.getDuration();
       
   597               int runningStatus=(StartTime<now && now<EndTime) ? SI::RunningStatusRunning : ((StartTime-30<now && now<StartTime) ? SI::RunningStatusStartsInAFewSeconds : SI::RunningStatusNotRunning);
   701               bool isOpt=false;
   598               bool isOpt=false;
   702               if(f2.Index()==0 && nCount>1) isOpt=true;
   599               if(index++==0 && nCount>1) isOpt=true;
   703 
   600               crc[1]=isOpt ? optCount : 0;
   704               d2(printf("ch=%s id=%04x/%08x %d opt=%d/%d st=%s ",*channelID.ToString(),EventId,cit.getContentId(),f2.Index(),isOpt,optCount,stripspace(ctime(&StartTime))))
   601               crc[2]=StartTime / STARTTIME_BIAS;
   705               if(StartTime+cit.getDuration()+Setup.EPGLinger*60<time(0)) {
   602               tEventID EventId=((('P'<<8)|'W')<<16) | crc16(0,(unsigned char *)crc,sizeof(crc));
       
   603 
       
   604               d2(printf("%s R%d %04x/%.4x %d %d/%d %s +%d ",*channelID.ToString(),runningStatus,EventId&0xFFFF,cit.getContentId(),index,isOpt,optCount,stripspace(ctime(&StartTime)),(int)cit.getDuration()/60))
       
   605               if(EndTime+Setup.EPGLinger*60<now) {
   706                 d2(printf("(old)\n"))
   606                 d2(printf("(old)\n"))
   707                 continue;
   607                 continue;
   708                 }
   608                 }
   709 
   609 
   710               bool newEvent=false;
   610               bool newEvent=false;
   711               cEvent *pEvent=(cEvent *)pSchedule->GetEvent(EventId,StartTime);
   611               cEvent *pEvent=(cEvent *)pSchedule->GetEvent(EventId,-1);
   712               if(!pEvent) {
   612               if(!pEvent) {
   713                  d2(printf("(new)\n"))
   613                 d2(printf("(new)\n"))
   714 #if VDRVERSNUM >= 10325
   614                 pEvent=new cEvent(EventId);
   715                  pEvent=new cEvent(EventId);
   615                 if(!pEvent) continue;
   716 #else
   616                 newEvent=true;
   717                  pEvent=new cEvent(channelID,EventId);
   617                 }
   718 #endif
       
   719                  if(!pEvent) continue;
       
   720                  newEvent=true;
       
   721                  }
       
   722               else {
   618               else {
   723                  d2(printf("(upd)\n"))
   619                 d2(printf("(upd)\n"))
   724                  pEvent->SetSeen();
   620                 pEvent->SetSeen();
   725                  if(pEvent->TableID()==0x00) continue;
   621                 if(pEvent->TableID()==0x00 || pEvent->Version()==cit.getVersionNumber()) {
   726                  if(Tid==pEvent->TableID() && pEvent->Version()==cit.getVersionNumber()) continue;
   622                   if(pEvent->RunningStatus()!=runningStatus)
   727                  }
   623                     pSchedule->SetRunningStatus(pEvent,runningStatus,channel);
       
   624                   continue;
       
   625                   }
       
   626                 }
   728               pEvent->SetEventID(EventId);
   627               pEvent->SetEventID(EventId);
   729               pEvent->SetTableID(Tid);
   628               pEvent->SetTableID(Tid);
   730               pEvent->SetVersion(cit.getVersionNumber());
   629               pEvent->SetVersion(cit.getVersionNumber());
   731               pEvent->SetStartTime(StartTime);
   630               pEvent->SetStartTime(StartTime);
   732               pEvent->SetDuration(cit.getDuration());
   631               pEvent->SetDuration(cit.getDuration());
   739                   snprintf(buffer2,sizeof(buffer2),optPats[SetupPE.OptPat],buffer,optCount);
   638                   snprintf(buffer2,sizeof(buffer2),optPats[SetupPE.OptPat],buffer,optCount);
   740                   pEvent->SetTitle(buffer2);
   639                   pEvent->SetTitle(buffer2);
   741                   }
   640                   }
   742                 else
   641                 else
   743                   pEvent->SetTitle(buffer);
   642                   pEvent->SetTitle(buffer);
       
   643                 d2(printf("title: %s\n",pEvent->Title()))
   744                 pEvent->SetShortText(ShortEventDescriptor->text.getText(buffer,sizeof(buffer)));
   644                 pEvent->SetShortText(ShortEventDescriptor->text.getText(buffer,sizeof(buffer)));
   745                 }
   645                 }
   746               if(ExtendedEventDescriptors) {
   646               if(ExtendedEventDescriptors) {
   747                 char buffer[ExtendedEventDescriptors->getMaximumTextLength(": ")+1];
   647                 char buffer[ExtendedEventDescriptors->getMaximumTextLength(": ")+1];
   748                 pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer,sizeof(buffer),": "));
   648                 pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer,sizeof(buffer),": "));
   758                 if(order)                 strcat(buffer,order);
   658                 if(order)                 strcat(buffer,order);
   759                 pEvent->SetDescription(buffer);
   659                 pEvent->SetDescription(buffer);
   760                 }
   660                 }
   761 
   661 
   762               if(newEvent) pSchedule->AddEvent(pEvent);
   662               if(newEvent) pSchedule->AddEvent(pEvent);
   763 #if VDRVERSNUM >= 10318
       
   764               pEvent->SetComponents(NULL);
   663               pEvent->SetComponents(NULL);
   765 #endif
       
   766               pEvent->FixEpgBugs();
   664               pEvent->FixEpgBugs();
       
   665               if(pEvent->RunningStatus()!=runningStatus)
       
   666                 pSchedule->SetRunningStatus(pEvent,runningStatus,channel);
       
   667               pSchedule->DropOutdated(StartTime,EndTime,Tid,cit.getVersionNumber());
   767               Modified=true;
   668               Modified=true;
   768               }
   669               }
   769             if(Modified) {
       
   770               pSchedule->Sort();
       
   771               Schedules->SetModified(pSchedule);
       
   772               }
       
   773             }
   670             }
   774           delete d;
   671           if(Modified) {
       
   672             pSchedule->Sort();
       
   673             Schedules->SetModified(pSchedule);
       
   674             }
       
   675           delete pct;
   775           }
   676           }
       
   677         }
   776         delete ExtendedEventDescriptors;
   678         delete ExtendedEventDescriptors;
   777         delete ShortEventDescriptor;
   679         delete ShortEventDescriptor;
   778         free(order);
   680         free(order);
   779         free(rating);
   681         free(rating);
   780         }
   682         }