Example #1
0
void CZapitChannel::dumpBouquetXml(FILE * fd, bool bUser)
{
	// TODO : gui->manage configuration: writeChannelsNames (if nessessary or wanted) in zapit.conf
	// menu > installation > Servicesscan > under 'Bouquet' => "Write DVB-names in bouquets:" f.e. =>0=never 1=ubouquets 2=bouquets 3=both
	int write_names =  zapitCfg.writeChannelsNames;

	fprintf(fd, "\t\t<S");

	// references (mandatory)
	if (url.empty())
		fprintf(fd, " i=\"%x\" t=\"%x\" on=\"%x\" s=\"%hd\" frq=\"%hd\"",getServiceId(), getTransportStreamId(), getOriginalNetworkId(), getSatellitePosition(), getFreqId());
	else
		fprintf(fd, " u=\"%s\"",convert_UTF8_To_UTF8_XML(url.c_str()).c_str());

	// service names
	if (bUser || !url.empty()) {
		if ((write_names & CBouquetManager::BWN_UBOUQUETS) == CBouquetManager::BWN_UBOUQUETS)
			fprintf(fd, " n=\"%s\"", convert_UTF8_To_UTF8_XML(name.c_str()).c_str());
	}
	else {
		if ((write_names & CBouquetManager::BWN_BOUQUETS) == CBouquetManager::BWN_BOUQUETS)
			fprintf(fd, " n=\"%s\"", convert_UTF8_To_UTF8_XML(name.c_str()).c_str());
	}

	// usecase optional attributes
	if (bUser && !uname.empty()) fprintf(fd, " un=\"%s\"", convert_UTF8_To_UTF8_XML(uname.c_str()).c_str());
	// TODO : be sure to save bouquets.xml after "l"L is changed only in ubouquets.xml (set dirty_bit ?)
	if (bLocked!=DEFAULT_CH_LOCKED) fprintf(fd," l=\"%d\"", bLocked ? 1 : 0);

	fprintf(fd, "/>\n");
}
Example #2
0
void CZapitChannel::dumpServiceXml(FILE * fd, const char * action)
{
	if(action) {
		fprintf(fd, "\t\t\t<S action=\"%s\" i=\"%04x\" n=\"%s\" t=\"%x\" s=\"%d\" num=\"%d\" f=\"%d\"/>\n", action,
				getServiceId(), convert_UTF8_To_UTF8_XML(name.c_str()).c_str(),
				getServiceType(), scrambled, number, flags);

	} else if(getPidsFlag()) {
		fprintf(fd, "\t\t\t<S i=\"%04x\" n=\"%s\" v=\"%x\" a=\"%x\" p=\"%x\" pmt=\"%x\" tx=\"%x\" t=\"%x\" vt=\"%d\" s=\"%d\" num=\"%d\" f=\"%d\"/>\n",
				getServiceId(), convert_UTF8_To_UTF8_XML(name.c_str()).c_str(),
				getVideoPid(), getPreAudioPid(),
				getPcrPid(), getPmtPid(), getTeletextPid(),
				getServiceType(true), type, scrambled, number, flags);
	} else {
		fprintf(fd, "\t\t\t<S i=\"%04x\" n=\"%s\" t=\"%x\" s=\"%d\" num=\"%d\" f=\"%d\"/>\n",
				getServiceId(), convert_UTF8_To_UTF8_XML(name.c_str()).c_str(),
				getServiceType(true), scrambled, number, flags);
	}
}
Example #3
0
void SensorResource::callService(const string &service) {
    int serviceId = getServiceId(service);
    switch(serviceId){
        case NOT_FOUND:
            //TODO throw exception
            break;
        case GET:
            serviceReturnStorage = getState();
            break;
    }
}
int main(int argc, char **argv)
{
	int i, j;
	struct timeval time_interval;
	fd_set useRead;
	fd_set useExcept;
	int selRet;
	char errTxt[256];
	RsslBuffer errorText = {255, (char*)errTxt};
	RsslInProgInfo inProg = RSSL_INIT_IN_PROG_INFO;
	RsslRet	retval = 0;
	int iargs;
	RsslErrorInfo rsslErrorInfo;
	RsslBool cacheOption = RSSL_FALSE;

	RsslReactorOMMProviderRole providerRole;

	RsslBindOptions sopts = RSSL_INIT_BIND_OPTS;

	RsslCreateReactorOptions reactorOpts;

	RsslReactorDispatchOptions dispatchOpts;

	time_t nextSendTime;

	/* Initialize RSSL. The locking mode RSSL_LOCK_GLOBAL_AND_CHANNEL is required to use the RsslReactor. */
	if (rsslInitialize(RSSL_LOCK_GLOBAL_AND_CHANNEL, &rsslErrorInfo.rsslError) != RSSL_RET_SUCCESS)
	{
		printf("rsslInitialize(): failed <%s>\n",rsslErrorInfo.rsslError.text);
		/* WINDOWS: wait for user to enter something before exiting  */
#ifdef _WIN32
		printf("\nPress Enter or Return key to exit application:");
		getchar();
#endif
		exit(RSSL_RET_FAILURE);
	}

	rsslClearOMMProviderRole(&providerRole);

	providerRole.base.channelEventCallback = channelEventCallback;
	providerRole.base.defaultMsgCallback = defaultMsgCallback;
	providerRole.loginMsgCallback = loginMsgCallback;
	providerRole.directoryMsgCallback = directoryMsgCallback;
	providerRole.dictionaryMsgCallback = dictionaryMsgCallback;
	providerRole.tunnelStreamListenerCallback = tunnelStreamListenerCallback;

	rsslClearCreateReactorOptions(&reactorOpts);

	if (!(pReactor = rsslCreateReactor(&reactorOpts, &rsslErrorInfo)))
	{
		printf("Reactor creation failed: %s\n", rsslErrorInfo.rsslError.text);
		cleanUpAndExit();
	}

	snprintf(portNo, 128, "%s", defaultPortNo);
	snprintf(serviceName, 128, "%s", defaultServiceName);
	setServiceId(1);
	for(iargs = 1; iargs < argc; ++iargs)
	{
		if (0 == strcmp("-p", argv[iargs]))
		{
			++iargs; if (iargs == argc) exitWithUsage();
			snprintf(portNo, 128, "%s", argv[iargs]);
		}
		else if (0 == strcmp("-s", argv[iargs]))
		{
			++iargs; if (iargs == argc) exitWithUsage();
			snprintf(serviceName, 128, "%s", argv[iargs]);
		}
		else if (0 == strcmp("-id", argv[iargs]))
		{
			long tmpId = 0;
			++iargs; if (iargs == argc) exitWithUsage();
			tmpId = atol(argv[iargs]);
			if (tmpId < 0)
			{
				printf("ServiceId must be positive.\n");
				exitWithUsage();
			}
			setServiceId(tmpId);
		}
		else if (0 == strcmp("-x", argv[iargs]))
		{
			xmlTrace = RSSL_TRUE;
			snprintf(traceOutputFile, 128, "RsslVAProvider\0");
		}
		else if (0 == strcmp("-runtime", argv[iargs]))
		{
			++iargs; if (iargs == argc) exitWithUsage();
			timeToRun = atoi(argv[iargs]);
		}
		else if (0 == strcmp("-cache", argv[iargs]))
		{
			cacheOption = RSSL_TRUE;
		}
		else
		{
			printf("Error: Unrecognized option: %s\n\n", argv[iargs]);
			exitWithUsage();
		}
	}
	printf("portNo: %s\n", portNo);
	printf("serviceName: %s\n", serviceName);
	printf("serviceId: %llu\n", getServiceId());

	/* Initialiize client session information */
	for (i = 0; i < MAX_CLIENT_SESSIONS; i++)
	{
		clearClientSessionInfo(&clientSessions[i]);
	}

	initializeCache(cacheOption);

	/* Initialize login handler */
	initLoginHandler();

	/* Initialize source directory handler */
	initDirectoryHandler();

	/* Initialize dictionary provider */
	initDictionaryProvider();

	/* Initialize market price handler */
	initItemHandler();

	/* Initialize symbol list item list */
	initSymbolListItemList();

	/* Initialize market by order items */
	initMarketByOrderItems();


	/* set service name in directory handler */
	setServiceName(serviceName);

	/* load dictionary */
	if (loadDictionary() != RSSL_RET_SUCCESS)
	{
		/* exit if dictionary cannot be loaded */
		/* WINDOWS: wait for user to enter something before exiting  */
#ifdef _WIN32
		printf("\nPress Enter or Return key to exit application:");
		getchar();
#endif
		exit(RSSL_RET_FAILURE);
	}

	initializeCacheDictionary();

	/* Initialize run-time */
	initRuntime();

	FD_ZERO(&readFds);
	FD_ZERO(&exceptFds);
	
	sopts.guaranteedOutputBuffers = 500;
	sopts.serviceName = portNo;
	sopts.majorVersion = RSSL_RWF_MAJOR_VERSION;
	sopts.minorVersion = RSSL_RWF_MINOR_VERSION;
	sopts.protocolType = RSSL_RWF_PROTOCOL_TYPE;

	/* Create the server. */
	if (!(rsslSrvr = rsslBind(&sopts, &rsslErrorInfo.rsslError)))
	{
		printf("Unable to bind RSSL server: <%s>\n",rsslErrorInfo.rsslError.text);
		/* WINDOWS: wait for user to enter something before exiting  */
#ifdef _WIN32
		printf("\nPress Enter or Return key to exit application:");
		getchar();
#endif
		exit(RSSL_RET_FAILURE);
	}

	FD_SET(rsslSrvr->socketId, &readFds);
	FD_SET(pReactor->eventFd, &readFds);
	
	rsslClearReactorDispatchOptions(&dispatchOpts);
	dispatchOpts.maxMessages = MAX_CLIENT_SESSIONS;

	// initialize next send time
	nextSendTime = time(NULL) + UPDATE_INTERVAL;

	/* this is the main loop */
	while(RSSL_TRUE)
	{
		useRead = readFds;
		useExcept = exceptFds;
		time_interval.tv_sec = UPDATE_INTERVAL;
		time_interval.tv_usec = 0;

		/* Call select() to check for any messages */
		selRet = select(FD_SETSIZE,&useRead,
		    NULL,&useExcept,&time_interval);

		if (selRet > 0)
		{
			RsslRet ret;

			/* Accept connection, if one is waiting */
			if (FD_ISSET(rsslSrvr->socketId, &useRead))
			{
				RsslClientSessionInfo *pClientSessionInfo = NULL;
				RsslReactorAcceptOptions aopts;

				rsslClearReactorAcceptOptions(&aopts);

				/* find an available client session */
				for (i = 0; i < MAX_CLIENT_SESSIONS; i++)
				{
					if (!clientSessions[i].isInUse)
					{
						pClientSessionInfo = &clientSessions[i];
						pClientSessionInfo->isInUse = RSSL_TRUE;
						break;
					}
				}

				/* Reject the channel if we are out of client sessions */
				if (!pClientSessionInfo)
					aopts.rsslAcceptOptions.nakMount = RSSL_TRUE;
				else
					aopts.rsslAcceptOptions.userSpecPtr = pClientSessionInfo;


				printf("Accepting new connection...\n");
				if (rsslReactorAccept(pReactor, rsslSrvr, &aopts, (RsslReactorChannelRole*)&providerRole, &rsslErrorInfo) != RSSL_RET_SUCCESS)
				{
					printf("rsslReactorAccept() failed: %s(%s)\n", rsslErrorInfo.rsslError.text, rsslErrorInfo.errorLocation);
					cleanUpAndExit();
				}
			}

			/* Call rsslReactorDispatch().  This will handle any events that have occurred on its channels.
			 * If there are events or messages for the application to process, they will be delivered
			 * through the callback functions given by the providerRole object. 
			 * A return value greater than RSSL_RET_SUCCESS indicates there may be more to process. */
			while ((ret = rsslReactorDispatch(pReactor, &dispatchOpts, &rsslErrorInfo)) > RSSL_RET_SUCCESS)
				;

			if (ret < RSSL_RET_SUCCESS)
			{
				printf("rsslReactorDispatch() failed: %s\n", rsslErrorInfo.rsslError.text);
				cleanUpAndExit();
			}
		}
		else if (selRet < 0)
		{
#ifdef _WIN32
			if (WSAGetLastError() == WSAEINTR)
				continue;
			printf("Error: select: %d\n", WSAGetLastError());
#else
			if (errno == EINTR)
				continue;
			perror("select");
#endif
			cleanUpAndExit();
		}

		// send any updates at next send time
		if (time(NULL) >= nextSendTime)
		{
			/* Send market price updates for each connected channel */
			updateItemInfo();
			for (i = 0; i < MAX_CLIENT_SESSIONS; i++)
			{
				if (clientSessions[i].clientChannel != NULL)
				{
					if (sendItemUpdates(pReactor, clientSessions[i].clientChannel) != RSSL_RET_SUCCESS)
					{
						removeClientSessionForChannel(pReactor, clientSessions[i].clientChannel);
					}

					// send any tunnel stream messages
					for (j = 0; j < MAX_TUNNEL_STREAMS; j++)
					{
						if (clientSessions[i].simpleTunnelMsgHandler[j].tunnelStreamHandler.pTunnelStream != NULL)
						{
							handleSimpleTunnelMsgHandler(pReactor, clientSessions[i].clientChannel, &clientSessions[i].simpleTunnelMsgHandler[j]);
						}
					}
				}
			}

			nextSendTime += UPDATE_INTERVAL;
		}

		/* Handle run-time */
		handleRuntime();
	}
}
Example #5
0
cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data, bool OnlyRunningStatus)
:SI::EIT(Data, false)
{
  if (!CheckCRCAndParse())
     return;

  tChannelID channelID(Source, getOriginalNetworkId(), getTransportStreamId(), getServiceId());
  cChannel *channel = Channels.GetByChannelID(channelID, true);
  if (!channel)
     return; // only collect data for known channels

  cSchedule *pSchedule = (cSchedule *)Schedules->GetSchedule(channel, true);

  bool Empty = true;
  bool Modified = false;
  bool HasExternalData = false;
  time_t SegmentStart = 0;
  time_t SegmentEnd = 0;
  time_t Now = time(NULL);
  struct tm tm_r;
  struct tm t = *localtime_r(&Now, &tm_r); // this initializes the time zone in 't'

  if (Now < VALID_TIME)
     return; // we need the current time for handling PDC descriptors

  SI::EIT::Event SiEitEvent;
  for (SI::Loop::Iterator it; eventLoop.getNext(SiEitEvent, it); ) {
      bool ExternalData = false;
      time_t StartTime = SiEitEvent.getStartTime();
      int Duration = SiEitEvent.getDuration();
      // Drop bogus events - but keep NVOD reference events, where all bits of the start time field are set to 1, resulting in a negative number.
      if (StartTime == 0 || StartTime > 0 && Duration == 0)
         continue;
      Empty = false;
      if (!SegmentStart)
         SegmentStart = StartTime;
      SegmentEnd = StartTime + Duration;
      cEvent *newEvent = NULL;
      cEvent *rEvent = NULL;
      cEvent *pEvent = (cEvent *)pSchedule->GetEvent(SiEitEvent.getEventId(), StartTime);
      if (!pEvent) {
         if (OnlyRunningStatus)
            continue;
         // If we don't have that event yet, we create a new one.
         // Otherwise we copy the information into the existing event anyway, because the data might have changed.
         pEvent = newEvent = new cEvent(SiEitEvent.getEventId());
         if (!pEvent)
            continue;
         }
      else {
         // We have found an existing event, either through its event ID or its start time.
         pEvent->SetSeen();
         // If the existing event has a zero table ID it was defined externally and shall
         // not be overwritten.
         uchar TableID = pEvent->TableID();
         if (TableID == 0x00) {
            if (pEvent->Version() == getVersionNumber())
               continue;
            HasExternalData = ExternalData = true;
            }
         // If the new event has a higher table ID, let's skip it.
         // The lower the table ID, the more "current" the information.
         else if (Tid > TableID)
            continue;
         // If the new event comes from the same table and has the same version number
         // as the existing one, let's skip it to avoid unnecessary work.
         // Unfortunately some stations (like, e.g. "Premiere") broadcast their EPG data on several transponders (like
         // the actual Premiere transponder and the Sat.1/Pro7 transponder), but use different version numbers on
         // each of them :-( So if one DVB card is tuned to the Premiere transponder, while an other one is tuned
         // to the Sat.1/Pro7 transponder, events will keep toggling because of the bogus version numbers.
         else if (Tid == TableID && pEvent->Version() == getVersionNumber())
            continue;
         }
      if (!ExternalData) {
         pEvent->SetEventID(SiEitEvent.getEventId()); // unfortunately some stations use different event ids for the same event in different tables :-(
         pEvent->SetTableID(Tid);
         pEvent->SetStartTime(StartTime);
         pEvent->SetDuration(Duration);
         }
      if (newEvent)
         pSchedule->AddEvent(newEvent);
      if (Tid == 0x4E) { // we trust only the present/following info on the actual TS
         if (SiEitEvent.getRunningStatus() >= SI::RunningStatusNotRunning)
            pSchedule->SetRunningStatus(pEvent, SiEitEvent.getRunningStatus(), channel);
         }
      if (OnlyRunningStatus)
         continue; // do this before setting the version, so that the full update can be done later
      pEvent->SetVersion(getVersionNumber());

      int LanguagePreferenceShort = -1;
      int LanguagePreferenceExt = -1;
      bool UseExtendedEventDescriptor = false;
      SI::Descriptor *d;
      SI::ExtendedEventDescriptors *ExtendedEventDescriptors = NULL;
      SI::ShortEventDescriptor *ShortEventDescriptor = NULL;
      cLinkChannels *LinkChannels = NULL;
      cComponents *Components = NULL;
      for (SI::Loop::Iterator it2; (d = SiEitEvent.eventDescriptors.getNext(it2)); ) {
          if (ExternalData && d->getDescriptorTag() != SI::ComponentDescriptorTag) {
             delete d;
             continue;
             }
          switch (d->getDescriptorTag()) {
            case SI::ExtendedEventDescriptorTag: {
                 SI::ExtendedEventDescriptor *eed = (SI::ExtendedEventDescriptor *)d;
                 if (I18nIsPreferredLanguage(Setup.EPGLanguages, eed->languageCode, LanguagePreferenceExt) || !ExtendedEventDescriptors) {
                    delete ExtendedEventDescriptors;
                    ExtendedEventDescriptors = new SI::ExtendedEventDescriptors;
                    UseExtendedEventDescriptor = true;
                    }
                 if (UseExtendedEventDescriptor) {
                    ExtendedEventDescriptors->Add(eed);
                    d = NULL; // so that it is not deleted
                    }
                 if (eed->getDescriptorNumber() == eed->getLastDescriptorNumber())
                    UseExtendedEventDescriptor = false;
                 }
                 break;
            case SI::ShortEventDescriptorTag: {
                 SI::ShortEventDescriptor *sed = (SI::ShortEventDescriptor *)d;
                 if (I18nIsPreferredLanguage(Setup.EPGLanguages, sed->languageCode, LanguagePreferenceShort) || !ShortEventDescriptor) {
                    delete ShortEventDescriptor;
                    ShortEventDescriptor = sed;
                    d = NULL; // so that it is not deleted
                    }
                 }
                 break;
            case SI::ContentDescriptorTag: {
                 SI::ContentDescriptor *cd = (SI::ContentDescriptor *)d;
                 SI::ContentDescriptor::Nibble Nibble;
                 int NumContents = 0;
                 uchar Contents[MAXEVCONTENTS] = { 0 };
                 for (SI::Loop::Iterator it3; cd->nibbleLoop.getNext(Nibble, it3); ) {
                     if (NumContents < MAXEVCONTENTS) {
                        Contents[NumContents] = ((Nibble.getContentNibbleLevel1() & 0xF) << 4) | (Nibble.getContentNibbleLevel2() & 0xF);
                        NumContents++;
                        }
                     }
                 pEvent->SetContents(Contents);
                 }
                 break;
            case SI::ParentalRatingDescriptorTag: {
                 int LanguagePreferenceRating = -1;
                 SI::ParentalRatingDescriptor *prd = (SI::ParentalRatingDescriptor *)d;
                 SI::ParentalRatingDescriptor::Rating Rating;
                 for (SI::Loop::Iterator it3; prd->ratingLoop.getNext(Rating, it3); ) {
                     if (I18nIsPreferredLanguage(Setup.EPGLanguages, Rating.languageCode, LanguagePreferenceRating)) {
                        int ParentalRating = (Rating.getRating() & 0xFF);
                        switch (ParentalRating) {
                          // values defined by the DVB standard (minimum age = rating + 3 years):
                          case 0x01 ... 0x0F: ParentalRating += 3; break;
                          // values defined by broadcaster CSAT (now why didn't they just use 0x07, 0x09 and 0x0D?):
                          case 0x11:          ParentalRating = 10; break;
                          case 0x12:          ParentalRating = 12; break;
                          case 0x13:          ParentalRating = 16; break;
                          default:            ParentalRating = 0;
                          }
                        pEvent->SetParentalRating(ParentalRating);
                        }
                     }
                 }
                 break;
            case SI::PDCDescriptorTag: {
                 SI::PDCDescriptor *pd = (SI::PDCDescriptor *)d;
                 t.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting
                 int month = t.tm_mon;
                 t.tm_mon = pd->getMonth() - 1;
                 t.tm_mday = pd->getDay();
                 t.tm_hour = pd->getHour();
                 t.tm_min = pd->getMinute();
                 t.tm_sec = 0;
                 if (month == 11 && t.tm_mon == 0) // current month is dec, but event is in jan
                    t.tm_year++;
                 else if (month == 0 && t.tm_mon == 11) // current month is jan, but event is in dec
                    t.tm_year--;
                 time_t vps = mktime(&t);
                 pEvent->SetVps(vps);
                 }
                 break;
            case SI::TimeShiftedEventDescriptorTag: {
                 SI::TimeShiftedEventDescriptor *tsed = (SI::TimeShiftedEventDescriptor *)d;
                 cSchedule *rSchedule = (cSchedule *)Schedules->GetSchedule(tChannelID(Source, channel->Nid(), channel->Tid(), tsed->getReferenceServiceId()));
                 if (!rSchedule)
                    break;
                 rEvent = (cEvent *)rSchedule->GetEvent(tsed->getReferenceEventId());
                 if (!rEvent)
                    break;
                 pEvent->SetTitle(rEvent->Title());
                 pEvent->SetShortText(rEvent->ShortText());
                 pEvent->SetDescription(rEvent->Description());
                 }
                 break;
            case SI::LinkageDescriptorTag: {
                 SI::LinkageDescriptor *ld = (SI::LinkageDescriptor *)d;
                 tChannelID linkID(Source, ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId());
                 if (ld->getLinkageType() == 0xB0) { // Premiere World
                    bool hit = StartTime <= Now && Now < StartTime + Duration;
                    if (hit) {
                       char linkName[ld->privateData.getLength() + 1];
                       strn0cpy(linkName, (const char *)ld->privateData.getData(), sizeof(linkName));
                       // TODO is there a standard way to determine the character set of this string?
                       cChannel *link = Channels.GetByChannelID(linkID);
                       if (link != channel) { // only link to other channels, not the same one
                          //fprintf(stderr, "Linkage %s %4d %4d %5d %5d %5d %5d  %02X  '%s'\n", hit ? "*" : "", channel->Number(), link ? link->Number() : -1, SiEitEvent.getEventId(), ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId(), ld->getLinkageType(), linkName);//XXX
                          if (link) {
                             if (Setup.UpdateChannels == 1 || Setup.UpdateChannels >= 3)
                                link->SetName(linkName, "", "");
                             }
                          else if (Setup.UpdateChannels >= 4) {
                             cChannel *transponder = channel;
                             if (channel->Tid() != ld->getTransportStreamId())
                                transponder = Channels.GetByTransponderID(linkID);
                             link = Channels.NewChannel(transponder, linkName, "", "", ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId());
                             //XXX patFilter->Trigger();
                             }
                          if (link) {
                             if (!LinkChannels)
                                LinkChannels = new cLinkChannels;
                             LinkChannels->Add(new cLinkChannel(link));
                             }
                          }
                       else
                          channel->SetPortalName(linkName);
                       }
                    }
                 }
                 break;
            case SI::ComponentDescriptorTag: {
                 SI::ComponentDescriptor *cd = (SI::ComponentDescriptor *)d;
                 uchar Stream = cd->getStreamContent();
                 uchar Type = cd->getComponentType();
                 if (1 <= Stream && Stream <= 4 && Type != 0) { // 1=video, 2=audio, 3=subtitles, 4=AC3
                    if (!Components)
                       Components = new cComponents;
                    char buffer[Utf8BufSize(256)];
                    Components->SetComponent(Components->NumComponents(), Stream, Type, I18nNormalizeLanguageCode(cd->languageCode), cd->description.getText(buffer, sizeof(buffer)));
                    }
                 }
                 break;
            default: ;
            }
          delete d;
          }

      if (!rEvent) {
         if (ShortEventDescriptor) {
            char buffer[Utf8BufSize(256)];
            pEvent->SetTitle(ShortEventDescriptor->name.getText(buffer, sizeof(buffer)));
            pEvent->SetShortText(ShortEventDescriptor->text.getText(buffer, sizeof(buffer)));
            }
         else if (!HasExternalData) {
            pEvent->SetTitle(NULL);
            pEvent->SetShortText(NULL);
            }
         if (ExtendedEventDescriptors) {
            char buffer[Utf8BufSize(ExtendedEventDescriptors->getMaximumTextLength(": ")) + 1];
            pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer, sizeof(buffer), ": "));
            }
         else if (!HasExternalData)
            pEvent->SetDescription(NULL);
         }
      delete ExtendedEventDescriptors;
      delete ShortEventDescriptor;

      pEvent->SetComponents(Components);

      if (!HasExternalData)
         pEvent->FixEpgBugs();
      if (LinkChannels)
         channel->SetLinkChannels(LinkChannels);
      Modified = true;
      }
Example #6
0
cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data, bool OnlyRunningStatus)
:SI::EIT(Data, false)
{
  if (!CheckCRCAndParse())
     return;

  tChannelID channelID(Source, getOriginalNetworkId(), getTransportStreamId(), getServiceId());

  cChannel *channel = Channels.GetByChannelID(channelID, true);
  if (!channel)
     return; // only collect data for known channels

  //M7X0 BEGIN AK
  eEpgMode em = EpgModes.GetModeByChannelID(&channelID)->GetMode();
  if ((em == emNone) | ((em == emNowNext) & (Tid != 0x4e) & (Tid != 0x4f)))
     return;
//M7X0 END AK

  cSchedule *pSchedule = (cSchedule *)Schedules->GetSchedule(channel, true);

  bool Empty = true;
  bool Modified = false;
  bool HasExternalData = false;
  time_t SegmentStart = 0;
  time_t SegmentEnd = 0;
  time_t now = time(NULL);

  SI::EIT::Event SiEitEvent;
  for (SI::Loop::Iterator it; eventLoop.getNext(SiEitEvent, it); ) {
      bool ExternalData = false;
      // Drop bogus events - but keep NVOD reference events, where all bits of the start time field are set to 1, resulting in a negative number.
      time_t si_stime = SiEitEvent.getStartTime();
      time_t si_dur = SiEitEvent.getDuration();
      if (si_stime == 0 || (si_stime > 0 && si_dur == 0))
         continue;
      Empty = false;
      if (((!SegmentStart) | (si_stime < SegmentStart)) & (si_stime > 0))
         SegmentStart = si_stime;
      if (si_stime + si_dur > SegmentEnd)
         SegmentEnd = si_stime + si_dur;

      cEvent *newEvent = NULL;
      cEvent *rEvent = NULL;
      cEvent *pEvent = (cEvent *)pSchedule->GetEvent(SiEitEvent.getEventId(), si_stime);
      if (!pEvent) {
         bool outdated = (si_stime > 0) &
               (si_stime + si_dur + Setup.EPGLinger * 60 + 3600 < now);
         if (OnlyRunningStatus | (em == emForeign) | outdated)
            continue;
         // If we don't have that event yet, we create a new one.
         // Otherwise we copy the information into the existing event anyway, because the data might have changed.
         pEvent = newEvent = new cEvent(SiEitEvent.getEventId());
         if (!pEvent)
            continue;
         }
      else {
         // We have found an existing event, either through its event ID or its start time.
         pEvent->SetSeen();
         // If the existing event has a zero table ID it was defined externally and shall
         // not be overwritten.
         if (pEvent->TableID() == 0x00) {
            if (pEvent->Version() == getVersionNumber())
               continue;
            HasExternalData = ExternalData = true;
            }
         // If the new event has a higher table ID, let's skip it.
         // The lower the table ID, the more "current" the information.
         else if (Tid > pEvent->TableID())
            continue;
         // If the new event comes from the same table and has the same version number
         // as the existing one, let's skip it to avoid unnecessary work.
         // Unfortunately some stations (like, e.g. "Premiere") broadcast their EPG data on several transponders (like
         // the actual Premiere transponder and the Sat.1/Pro7 transponder), but use different version numbers on
         // each of them :-( So if one DVB card is tuned to the Premiere transponder, while an other one is tuned
         // to the Sat.1/Pro7 transponder, events will keep toggling because of the bogus version numbers.
         else if (Tid == pEvent->TableID() && pEvent->Version() == getVersionNumber())
            continue;
         }
      if ((!ExternalData) & (!OnlyRunningStatus)) {
         pEvent->SetEventID(SiEitEvent.getEventId()); // unfortunately some stations use different event ids for the same event in different tables :-(
         pEvent->SetTableID(Tid);
         pEvent->SetStartTime(si_stime);
         pEvent->SetDuration(si_dur);
         }
      if (newEvent)
         pSchedule->AddEvent(newEvent);
      if (Tid == 0x4E) { // we trust only the present/following info on the actual TS
         if (SiEitEvent.getRunningStatus() >= SI::RunningStatusNotRunning)
            pSchedule->SetRunningStatus(pEvent, SiEitEvent.getRunningStatus(), channel);
         }
      if (OnlyRunningStatus)
         continue; // do this before setting the version, so that the full update can be done later
      pEvent->SetVersion(getVersionNumber());

      int LanguagePreferenceShort = -1;
      int LanguagePreferenceExt = -1;
      bool UseExtendedEventDescriptor = false;
      SI::Descriptor *d;
      SI::ExtendedEventDescriptors *ExtendedEventDescriptors = NULL;
      SI::ShortEventDescriptor *ShortEventDescriptor = NULL;
      cLinkChannels *LinkChannels = NULL;
      cComponents *Components = NULL;
      for (SI::Loop::Iterator it2; (d = SiEitEvent.eventDescriptors.getNext(it2)); ) {
          if (ExternalData && d->getDescriptorTag() != SI::ComponentDescriptorTag) {
             delete d;
             continue;
             }
          switch (d->getDescriptorTag()) {
            case SI::ExtendedEventDescriptorTag: {
                 SI::ExtendedEventDescriptor *eed = (SI::ExtendedEventDescriptor *)d;
                 if (I18nIsPreferredLanguage(Setup.EPGLanguages, eed->languageCode, LanguagePreferenceExt) || !ExtendedEventDescriptors) {
                    delete ExtendedEventDescriptors;
                    ExtendedEventDescriptors = new SI::ExtendedEventDescriptors;
                    UseExtendedEventDescriptor = true;
                    }
                 if (UseExtendedEventDescriptor) {
                    ExtendedEventDescriptors->Add(eed);
                    d = NULL; // so that it is not deleted
                    }
                 if (eed->getDescriptorNumber() == eed->getLastDescriptorNumber())
                    UseExtendedEventDescriptor = false;
                 }
                 break;
            case SI::ShortEventDescriptorTag: {
                 SI::ShortEventDescriptor *sed = (SI::ShortEventDescriptor *)d;
                 if (I18nIsPreferredLanguage(Setup.EPGLanguages, sed->languageCode, LanguagePreferenceShort) || !ShortEventDescriptor) {
                    delete ShortEventDescriptor;
                    ShortEventDescriptor = sed;
                    d = NULL; // so that it is not deleted
                    }
                 }
                 break;
            case SI::ContentDescriptorTag:
                 break;
            case SI::ParentalRatingDescriptorTag:
                 break;
            case SI::PDCDescriptorTag: {
                 SI::PDCDescriptor *pd = (SI::PDCDescriptor *)d;
                 time_t now = time(NULL);
                 struct tm tm_r;
                 struct tm t = *localtime_r(&now, &tm_r); // this initializes the time zone in 't'
                 t.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting
                 int month = t.tm_mon;
                 t.tm_mon = pd->getMonth() - 1;
                 t.tm_mday = pd->getDay();
                 t.tm_hour = pd->getHour();
                 t.tm_min = pd->getMinute();
                 t.tm_sec = 0;
                 if (month == 11 && t.tm_mon == 0) // current month is dec, but event is in jan
                    t.tm_year++;
                 else if (month == 0 && t.tm_mon == 11) // current month is jan, but event is in dec
                    t.tm_year--;
                 time_t vps = mktime(&t);
                 pEvent->SetVps(vps);
                 }
                 break;
            case SI::TimeShiftedEventDescriptorTag: {
                 SI::TimeShiftedEventDescriptor *tsed = (SI::TimeShiftedEventDescriptor *)d;
                 cSchedule *rSchedule = (cSchedule *)Schedules->GetSchedule(tChannelID(Source, channel->Nid(), channel->Tid(), tsed->getReferenceServiceId()));
                 if (!rSchedule)
                    break;
                 rEvent = (cEvent *)rSchedule->GetEvent(tsed->getReferenceEventId());
                 if (!rEvent)
                    break;
                 pEvent->SetTitle(rEvent->Title());
                 pEvent->SetShortText(rEvent->ShortText());
                 pEvent->SetDescription(rEvent->Description());
                 }
                 break;
            case SI::LinkageDescriptorTag: {
                 SI::LinkageDescriptor *ld = (SI::LinkageDescriptor *)d;
                 tChannelID linkID(Source, ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId());
                 if (ld->getLinkageType() == 0xB0) { // Premiere World
                    time_t now = time(NULL);
                    bool hit = SiEitEvent.getStartTime() <= now && now < SiEitEvent.getStartTime() + SiEitEvent.getDuration();
                    if (hit) {
                       char linkName[ld->privateData.getLength() + 1];
                       strn0cpy(linkName, (const char *)ld->privateData.getData(), sizeof(linkName));
                       cChannel *link = Channels.GetByChannelID(linkID);
                       if (link != channel) { // only link to other channels, not the same one
                          //fprintf(stderr, "Linkage %s %4d %4d %5d %5d %5d %5d  %02X  '%s'\n", hit ? "*" : "", channel->Number(), link ? link->Number() : -1, SiEitEvent.getEventId(), ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId(), ld->getLinkageType(), linkName);//XXX
                          if (link) {
                             if (Setup.UpdateChannels == 1 || Setup.UpdateChannels >= 3)
                                link->SetName(linkName, "", "");
                             }
                          else if (Setup.UpdateChannels >= 4) {
                             link = Channels.NewChannel(channel, linkName, "", "", ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId());
                             //XXX patFilter->Trigger();
                             }
                          if (link) {
                             if (!LinkChannels)
                                LinkChannels = new cLinkChannels;
                             LinkChannels->Add(new cLinkChannel(link));
                             }
                          }
                       else
                          channel->SetPortalName(linkName);
                       }
                    }
                 }
                 break;
            case SI::ComponentDescriptorTag: {
                 SI::ComponentDescriptor *cd = (SI::ComponentDescriptor *)d;
                 uchar Stream = cd->getStreamContent();
                 uchar Type = cd->getComponentType();
                 if (1 <= Stream && Stream <= 2 && Type != 0) {
                    if (!Components)
                       Components = new cComponents;
                    char buffer[256];
                    Components->SetComponent(Components->NumComponents(), cd->getStreamContent(), cd->getComponentType(), I18nNormalizeLanguageCode(cd->languageCode), cd->description.getText(buffer, sizeof(buffer)));
                    }
                 }
                 break;
            default: ;
            }
          delete d;
          }

      if (!rEvent) {
         if (ShortEventDescriptor) {
            char buffer[256];
            pEvent->SetTitle(ShortEventDescriptor->name.getText(buffer, sizeof(buffer)));
            pEvent->SetShortText(ShortEventDescriptor->text.getText(buffer, sizeof(buffer)));
            }
         else if (!HasExternalData) {
            pEvent->SetTitle(NULL);
            pEvent->SetShortText(NULL);
            }
         if (ExtendedEventDescriptors) {
            char buffer[ExtendedEventDescriptors->getMaximumTextLength(": ") + 1];
            pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer, sizeof(buffer), ": "));
            }
         else if (!HasExternalData)
            pEvent->SetDescription(NULL);
         }
      delete ExtendedEventDescriptors;
      delete ShortEventDescriptor;

      pEvent->SetComponents(Components);

      if (!HasExternalData)
         pEvent->FixEpgBugs();
      if (LinkChannels)
         channel->SetLinkChannels(LinkChannels);
      Modified = true;
      }
  if (Empty && Tid == 0x4E && getSectionNumber() == 0)
     // ETR 211: an empty entry in section 0 of table 0x4E means there is currently no event running
     pSchedule->ClrRunningStatus(channel);
  if (Tid == 0x4E)
     pSchedule->SetPresentSeen();
  if (OnlyRunningStatus)
     return;
  if (Modified) {
     pSchedule->Sort();
     pSchedule->DropOutdated(SegmentStart, SegmentEnd, Tid, getVersionNumber());
     Schedules->SetModified(pSchedule);
     }
}
Example #7
0
File: eit.c Project: suborb/reelvdr
cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data, bool OnlyRunningStatus)
:SI::EIT(Data, false)
{
  if (!CheckCRCAndParse())
     return;

  tChannelID channelID(Source, getOriginalNetworkId(), getTransportStreamId(), getServiceId());
  cChannel *channel = Channels.GetByChannelID(channelID, true);

  if (!channel)
     return; // only collect data for known channels

  // Channel marked as not to receive EPG data (noEPG patch)
  if (!Channels.isEPGAllowed(channelID))
  {
     return;
  }

  const char *charset;
  if(channelID == lastChannelID) {
     charset = lastCharset;
  } else {
    charset = ProviderCharsets.GetCharset(channel->Provider());
    lastCharset = charset;
  }

  //::printf("========  %s charset: %s ==========\n", channel->Provider(), charset);

  cSchedule *pSchedule = (cSchedule *)Schedules->GetSchedule(channel, true);

  bool Empty = true;
  bool Modified = false;
  bool HasExternalData = false;
  time_t SegmentStart = 0;
  time_t SegmentEnd = 0;
  time_t now = time(NULL);
  struct tm tm_r;
  struct tm t = *localtime_r(&now, &tm_r); // this initializes the time zone in 't'

  if (now < VALID_TIME)
      return; // we need the current time for handling PDC descriptors

  SI::EIT::Event SiEitEvent;
  for (SI::Loop::Iterator it; eventLoop.getNext(SiEitEvent, it); ) {
      bool ExternalData = false;
      // Drop bogus events - but keep NVOD reference events, where all bits of the start time field are set to 1, resulting in a negative number.
      int startTime = SiEitEvent.getStartTime();
      int duration = SiEitEvent.getDuration();
      if (startTime == 0 || (startTime > 0 && duration == 0))
         continue;
      Empty = false;
      if (!SegmentStart)
         SegmentStart = startTime;
      SegmentEnd = startTime + duration;
      cEvent *newEvent = NULL;
      cEvent *rEvent = NULL;
      cEvent *pEvent = (cEvent *)pSchedule->GetEvent(SiEitEvent.getEventId(), startTime);
      if (!pEvent) {
         if (OnlyRunningStatus)
            continue;
         // If we don't have that event yet, we create a new one.
         // Otherwise we copy the information into the existing event anyway, because the data might have changed.
         pEvent = newEvent = new cEvent(SiEitEvent.getEventId());
         if (!pEvent)
            continue;
         }
      else {
         // We have found an existing event, either through its event ID or its start time.
         pEvent->SetSeen();
         // If the existing event has a zero table ID it was defined externally and shall
         // not be overwritten.
         uchar tableID = pEvent->TableID();
         if (tableID == 0x00) {
            if (pEvent->Version() == getVersionNumber())
               continue;
            HasExternalData = ExternalData = true;
            }
         // If the new event has a higher table ID, let's skip it.
         // The lower the table ID, the more "current" the information.
         else if (Tid > tableID)
            continue;
         // If the new event comes from the same table and has the same version number
         // as the existing one, let's skip it to avoid unnecessary work.
         // Unfortunately some stations (like, e.g. "Premiere") broadcast their EPG data on several transponders (like
         // the actual Premiere transponder and the Sat.1/Pro7 transponder), but use different version numbers on
         // each of them :-( So if one DVB card is tuned to the Premiere transponder, while an other one is tuned
         // to the Sat.1/Pro7 transponder, events will keep toggling because of the bogus version numbers.
         else if (Tid == tableID && pEvent->Version() == getVersionNumber())
            continue;
         }
      if (!ExternalData) {
         pEvent->SetEventID(SiEitEvent.getEventId()); // unfortunately some stations use different event ids for the same event in different tables :-(
         pEvent->SetTableID(Tid);
         pEvent->SetStartTime(startTime);
         pEvent->SetDuration(duration);
         }
      if (newEvent)
         pSchedule->AddEvent(newEvent);
      if (Tid == 0x4E) { // we trust only the present/following info on the actual TS
         if (SiEitEvent.getRunningStatus() >= SI::RunningStatusNotRunning)
            pSchedule->SetRunningStatus(pEvent, SiEitEvent.getRunningStatus(), channel);
         }
      if (OnlyRunningStatus)
         continue; // do this before setting the version, so that the full update can be done later
      pEvent->SetVersion(getVersionNumber());

      int LanguagePreferenceShort = -1;
      int LanguagePreferenceExt = -1;
      bool UseExtendedEventDescriptor = false;
      SI::Descriptor *d;
      SI::ExtendedEventDescriptors *ExtendedEventDescriptors = NULL;
      SI::ShortEventDescriptor *ShortEventDescriptor = NULL;
      cLinkChannels *LinkChannels = NULL;
      cComponents *Components = NULL;
      for (SI::Loop::Iterator it2; (d = SiEitEvent.eventDescriptors.getNext(it2)); ) {
          if (ExternalData && d->getDescriptorTag() != SI::ComponentDescriptorTag) {
             delete d;
             continue;
             }
          switch (d->getDescriptorTag()) {
            case SI::ExtendedEventDescriptorTag: {
                 SI::ExtendedEventDescriptor *eed = (SI::ExtendedEventDescriptor *)d;
                 if (I18nIsPreferredLanguage(Setup.EPGLanguages, eed->languageCode, LanguagePreferenceExt) || !ExtendedEventDescriptors) {
                    delete ExtendedEventDescriptors;
                    ExtendedEventDescriptors = new SI::ExtendedEventDescriptors;
                    UseExtendedEventDescriptor = true;
                    }
                 if (UseExtendedEventDescriptor) {
                    ExtendedEventDescriptors->Add(eed);
                    d = NULL; // so that it is not deleted
                    }
                 if (eed->getDescriptorNumber() == eed->getLastDescriptorNumber())
                    UseExtendedEventDescriptor = false;
                 }
                 break;
            case SI::ShortEventDescriptorTag: {
                 SI::ShortEventDescriptor *sed = (SI::ShortEventDescriptor *)d;
                 if (I18nIsPreferredLanguage(Setup.EPGLanguages, sed->languageCode, LanguagePreferenceShort) || !ShortEventDescriptor) {
                    delete ShortEventDescriptor;
                    ShortEventDescriptor = sed;
                    d = NULL; // so that it is not deleted
                    }
                 }
                 break;
            case SI::ContentDescriptorTag:
                 break;
            case SI::ParentalRatingDescriptorTag:
                 break;
            case SI::PDCDescriptorTag: {
                 SI::PDCDescriptor *pd = (SI::PDCDescriptor *)d;
                 t.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting
                 int month = t.tm_mon;
                 t.tm_mon = pd->getMonth() - 1;
                 t.tm_mday = pd->getDay();
                 t.tm_hour = pd->getHour();
                 t.tm_min = pd->getMinute();
                 t.tm_sec = 0;
                 if (month == 11 && t.tm_mon == 0) // current month is dec, but event is in jan
                    t.tm_year++;
                 else if (month == 0 && t.tm_mon == 11) // current month is jan, but event is in dec
                    t.tm_year--;
                 time_t vps = mktime(&t);
                 pEvent->SetVps(vps);
                 }
                 break;
            case SI::TimeShiftedEventDescriptorTag: {
                 SI::TimeShiftedEventDescriptor *tsed = (SI::TimeShiftedEventDescriptor *)d;
                 cSchedule *rSchedule = (cSchedule *)Schedules->GetSchedule(tChannelID(Source, channel->Nid(), channel->Tid(), tsed->getReferenceServiceId()));
                 if (!rSchedule)
                    break;
                 rEvent = (cEvent *)rSchedule->GetEvent(tsed->getReferenceEventId());
                 if (!rEvent)
                    break;
                 pEvent->SetTitle(rEvent->Title());
                 pEvent->SetShortText(rEvent->ShortText());
                 pEvent->SetDescription(rEvent->Description());
                 }
                 break;
            case SI::LinkageDescriptorTag: {
                 SI::LinkageDescriptor *ld = (SI::LinkageDescriptor *)d;
                 tChannelID linkID(Source, ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId());
#ifdef DBG_EIT_LINKS
                 dsyslog("[eit]: Linkage Type %X  (0xB0) == Premiere ", ld->getLinkageType());  
#endif
                 if (ld->getLinkageType() == 0xB0) { // Premiere World
                    bool hit = startTime <= now && now < startTime + duration;
                    if (hit) {
#ifdef DBG_EIT_LINKS
                       dsyslog("[eit]: get hit \n");
#endif
                       SI::String linkNameStr;
                       linkNameStr.setData(ld->privateData, ld->privateData.getLength());
                       char linkName[Utf8BufSize(ld->privateData.getLength() + 1)];
                       linkNameStr.getText(linkName, sizeof(linkName), charset);
                       cChannel *link = Channels.GetByChannelID(linkID);
#ifdef DBG_EIT_LINKS
                       dsyslog("[eit]: linkName %s  \n", linkName);
                       dsyslog("[eit]: linkName:  %s; ID %X  Channel: %s, ID %X \n", link->Name(),link->GetChannelID().Sid(), channel->Name(), channel->GetChannelID().Sid());
#endif
                       if (link != channel) { // only link to other channels, not the same one //XXX ?
#ifdef DBG_EIT_LINKS
                          dsyslog("[eit] Linkage %s %4d %4d %5d %5d %5d %5d  %02X  '%s'\n", hit ? "*" : "", channel->Number(), link ? link->Number() : -1, SiEitEvent.getEventId(), ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId(), ld->getLinkageType(), linkName);//XXX
#endif
                          if (link) {
                             if (Setup.UpdateChannels == 1 || Setup.UpdateChannels >= 3) // Update in any case!
                                link->SetName(linkName, "", channel->Provider());
                             }
                          else if (Setup.UpdateChannels >= 4) {

                              if (channel->Tid() != ld->getTransportStreamId()) {
                                 cChannel *transponder = Channels.GetByTransponderID(linkID);
                                 link = Channels.NewChannel(transponder, linkName, "", channel->Provider(), ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId());
                                 }
                              else
                                 link = Channels.NewChannel(channel, linkName, "", channel->Provider(), ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId());
                             //XXX patFilter->Trigger();
                            }
                          if (link) {
                             if (!LinkChannels)
                                LinkChannels = new cLinkChannels;

#ifdef DBG_EIT_LINKS
                             dsyslog("[eit]: Add new cLinkChannel(link)\n");
#endif
                             LinkChannels->Add(new cLinkChannel(link));
                             }
                          }
                       else {
                          channel->SetPortalName(linkName);
#ifdef DBG_EIT_LINKS
                          dsyslog("[eit]: Set portal name %s to %s   hit \n",channel->Name(), linkName);
#endif
                          }
                       }
                    }
                 }
                 break;
            case SI::ComponentDescriptorTag: {
                 SI::ComponentDescriptor *cd = (SI::ComponentDescriptor *)d;
                 uchar Stream = cd->getStreamContent();
                 uchar Type = cd->getComponentType();
                 if (1 <= Stream && Stream <= 3 && Type != 0) { // 1=video, 2=audio, 3=subtitles
                    if (!Components)
                       Components = new cComponents;
                    char buffer[Utf8BufSize(256)];
                    Components->SetComponent(Components->NumComponents(), cd->getStreamContent(), cd->getComponentType(), I18nNormalizeLanguageCode(cd->languageCode), cd->description.getText(buffer, sizeof(buffer), charset));
                    }
                 }
                 break;
            default: ;
            }
          delete d;
          }

      if (!rEvent) {
         if (ShortEventDescriptor) {
            char buffer[Utf8BufSize(256)];
            pEvent->SetTitle(ShortEventDescriptor->name.getText(buffer, sizeof(buffer), charset));
            pEvent->SetShortText(ShortEventDescriptor->text.getText(buffer, sizeof(buffer), charset));
            }
         else if (!HasExternalData) {
            pEvent->SetTitle(NULL);
            pEvent->SetShortText(NULL);
            }
         if (ExtendedEventDescriptors) {
            char buffer[Utf8BufSize(ExtendedEventDescriptors->getMaximumTextLength(": ") + 1)];
            pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer, sizeof(buffer), charset, ": "));
            }
         else if (!HasExternalData)
            pEvent->SetDescription(NULL);
         }
      delete ExtendedEventDescriptors;
      delete ShortEventDescriptor;

      pEvent->SetComponents(Components);

      if (!HasExternalData)
         pEvent->FixEpgBugs();
      if (LinkChannels)
         channel->SetLinkChannels(LinkChannels);
      Modified = true;
      }
  if (Tid == 0x4E) {
     if (Empty && getSectionNumber() == 0)
        // ETR 211: an empty entry in section 0 of table 0x4E means there is currently no event running
        pSchedule->ClrRunningStatus(channel);
     pSchedule->SetPresentSeen();
  }
  if (OnlyRunningStatus)
     return;
  if (Modified) {
     pSchedule->Sort();
     if (!HasExternalData)
        pSchedule->DropOutdated(SegmentStart, SegmentEnd, Tid, getVersionNumber());
     Schedules->SetModified(pSchedule);
     }
}
/*
 * Encodes the batch item request.  Returns success if
 * encoding succeeds or failure if encoding fails.
 * chnl - The channel to send an item request to
 * msgBuf - The message buffer to encode the item request into
 * streamId - The stream id of the item request
 * isPrivateStream - Flag for private stream request
 *
 * This function is only used within the Market Price Handler
 * and each handler has its own implementation, although much is similar
 */
static RsslRet encodeBatchItemRequest(RsslChannel* chnl, RsslBuffer* msgBuf, RsslInt32 streamId, RsslBool isPrivateStream)
{
	RsslRet ret = 0;
	RsslRequestMsg msg = RSSL_INIT_REQUEST_MSG;
	RsslElementList eList = RSSL_INIT_ELEMENT_LIST;
	RsslElementEntry eEntry = RSSL_INIT_ELEMENT_ENTRY;
	RsslArray elementArray = RSSL_INIT_ARRAY; 
	RsslEncodeIterator encodeIter;
	RsslSourceDirectoryResponseInfo* srcDirRespInfo = 0;
	RsslBuffer itemName;
	int i;

	RsslLoginResponseInfo* loginInfo = getLoginResponseInfo();
	
	if (getSourceDirectoryResponseInfo(getServiceId(), &srcDirRespInfo) != RSSL_RET_SUCCESS)
		return RSSL_RET_FAILURE;

	/* clear encode iterator */
	rsslClearEncodeIterator(&encodeIter);

	/* set-up message */
	msg.msgBase.msgClass = RSSL_MC_REQUEST;
	msg.msgBase.streamId = streamId;
	msg.msgBase.domainType = RSSL_DMT_MARKET_PRICE;
	msg.msgBase.containerType = RSSL_DT_ELEMENT_LIST;
	if (snapshotRequest)
	{
		msg.flags = RSSL_RQMF_HAS_QOS | RSSL_RQMF_HAS_PRIORITY | RSSL_RQMF_HAS_BATCH;
	}
	else
	{
		msg.flags = RSSL_RQMF_HAS_QOS | RSSL_RQMF_STREAMING | RSSL_RQMF_HAS_PRIORITY | RSSL_RQMF_HAS_BATCH;
	}
	if((loginInfo->SupportViewRequests == RSSL_TRUE) && (viewRequest == RSSL_TRUE))
	{
		msg.flags |= RSSL_RQMF_HAS_VIEW;
	}
	if (isPrivateStream)
	{
		msg.flags |= RSSL_RQMF_PRIVATE_STREAM;
	}
	msg.priorityClass = 1;
	msg.priorityCount = 1;

	/* copy the QoS information */
	rsslCopyQos(&(msg.qos), &(srcDirRespInfo->ServiceGeneralInfo.QoS[0]));
	
	/* specify msgKey members */
	msg.msgBase.msgKey.flags = RSSL_MKF_HAS_NAME_TYPE | RSSL_MKF_HAS_SERVICE_ID;
	msg.msgBase.msgKey.nameType = RDM_INSTRUMENT_NAME_TYPE_RIC;
	msg.msgBase.msgKey.serviceId = (RsslUInt16)getServiceId();
	
	/* encode message */
	if((ret = rsslSetEncodeIteratorBuffer(&encodeIter, msgBuf)) < RSSL_RET_SUCCESS)
	{
		printf("rsslSetEncodeIteratorBuffer() failed with return code: %d\n", ret);
		return ret;
	}
	rsslSetEncodeIteratorRWFVersion(&encodeIter, chnl->majorVersion, chnl->minorVersion);
	/* start the request message encoding */
	if ((ret = rsslEncodeMsgInit(&encodeIter, (RsslMsg*)&msg, 0)) < RSSL_RET_SUCCESS)
	{
		printf("rsslEncodeMsg() failed with return code: %d\n", ret);
		return ret;
	}

	/* For Batch requests, the message has a payload of an element list that contains an array of the requested items */

	eList.flags = RSSL_ELF_HAS_STANDARD_DATA;
	if((ret = rsslEncodeElementListInit(&encodeIter, &eList, 0, 0)) < RSSL_RET_SUCCESS)
	{
		printf("rsslEncodeElementListInit() failed with return code: %d\n", ret);
		return ret;
	}

	eEntry.name = RSSL_ENAME_BATCH_ITEM_LIST;
	eEntry.dataType = RSSL_DT_ARRAY;
	if((ret = rsslEncodeElementEntryInit(&encodeIter, &eEntry, 0)) < RSSL_RET_SUCCESS)
	{
		printf("rsslEncodeElementEntryInit() failed with return code: %d\n", ret);
		return ret;
	}

	/* Encode the array of requested item names */
	elementArray.primitiveType = RSSL_DT_ASCII_STRING;
	elementArray.itemLength = 0;
	if((ret = rsslEncodeArrayInit(&encodeIter, &elementArray)) < RSSL_RET_SUCCESS)
	{
		printf("rsslEncodeArrayInit() failed with return code: %d\n", ret);
		return ret;
	}

	if (!isPrivateStream) /* non-private stream */
	{
		for(i = 0; i < itemCount; i++)
		{
			itemName.data = marketPriceItemInfoList[i].itemname;
			itemName.length = marketPriceItemInfoList[i].nameLength;
			marketPriceItemInfoList[i].streamId = ++streamId;
			if((ret = rsslEncodeArrayEntry(&encodeIter, &itemName, 0)) < RSSL_RET_SUCCESS)
			{
				printf("rsslEncodeArrayEntry() failed with return code: %d\n", ret);
				return ret;
			}
		}
	}
	else /* private stream */
	{
		for(i = 0; i < privateStreamItemCount; i++)
		{
			itemName.data = marketPricePSItemInfoList[i].itemname;
			itemName.length = marketPricePSItemInfoList[i].nameLength;
			marketPricePSItemInfoList[i].streamId = ++streamId;
			if((ret = rsslEncodeArrayEntry(&encodeIter, &itemName, 0)) < RSSL_RET_SUCCESS)
			{
				printf("rsslEncodeArrayEntry() failed with return code: %d\n", ret);
				return ret;
			}
		}
	}

	if((ret = rsslEncodeArrayComplete(&encodeIter, RSSL_TRUE)) < RSSL_RET_SUCCESS)
	{
		printf("rsslEncodeArrayComplete() failed with return code: %d\n", ret);
		return ret;
	}

	if((ret = rsslEncodeElementEntryComplete(&encodeIter, RSSL_TRUE)) < RSSL_RET_SUCCESS)
	{
		printf("rsslEncodeElementEntryComplete() failed with return code: %d\n", ret);
		return ret;
	}

	/* 
	 *	Encode a view request into the list.
	 */
	if((loginInfo->SupportViewRequests == RSSL_TRUE) && (viewRequest == RSSL_TRUE) )
		encodeViewElementRequest(&encodeIter);


	if((ret = rsslEncodeElementListComplete(&encodeIter, RSSL_TRUE)) < RSSL_RET_SUCCESS)
	{
		printf("rsslEncodeElementListComplete() failed with return code: %d\n", ret);
		return ret;
	}

	if((ret = rsslEncodeMsgComplete(&encodeIter, RSSL_TRUE)) < RSSL_RET_SUCCESS)
	{
		printf("rsslEncodeMessageComplete() failed with return code: %d\n", ret);
		return ret;
	}

	msgBuf->length = rsslGetEncodedBufferLength(&encodeIter);

	return RSSL_RET_SUCCESS;
}
/*
 * Encodes the item request.  Returns success if
 * encoding succeeds or failure if encoding fails.
 * chnl - The channel to send an item request to
 * msgBuf - The message buffer to encode the item request into
 * streamId - The stream id of the item request
 * isPrivateStream - Flag for private stream request
 *
 * This function is only used within the Market Price Handler
 * and each handler has its own implementation, although much is similar
 */
static RsslRet encodeItemRequest(RsslChannel* chnl, RsslBuffer* msgBuf, RsslInt32 streamId, RsslBool isPrivateStream)
{
	RsslRet ret = 0;
	RsslRequestMsg msg = RSSL_INIT_REQUEST_MSG;
	RsslEncodeIterator encodeIter;
	RsslElementList eList = RSSL_INIT_ELEMENT_LIST;
	RsslLoginResponseInfo* loginInfo = getLoginResponseInfo();
	RsslSourceDirectoryResponseInfo* srcDirRespInfo = 0;
	RsslUInt32	listIndex;

	if (getSourceDirectoryResponseInfo(getServiceId(), &srcDirRespInfo) != RSSL_RET_SUCCESS)
		return RSSL_RET_FAILURE;

	/* clear encode iterator */
	rsslClearEncodeIterator(&encodeIter);

	/* set-up message */
	msg.msgBase.msgClass = RSSL_MC_REQUEST;
	msg.msgBase.streamId = streamId;
	msg.msgBase.domainType = RSSL_DMT_MARKET_PRICE;
	if((viewRequest == RSSL_TRUE) && (loginInfo->SupportViewRequests == RSSL_TRUE))
		msg.msgBase.containerType = RSSL_DT_ELEMENT_LIST;
	else
		msg.msgBase.containerType = RSSL_DT_NO_DATA;
	if (snapshotRequest)
	{
		msg.flags = RSSL_RQMF_HAS_QOS | RSSL_RQMF_HAS_PRIORITY;
	}
	else
	{
		msg.flags = RSSL_RQMF_HAS_QOS | RSSL_RQMF_STREAMING | RSSL_RQMF_HAS_PRIORITY;
	}
	if (isPrivateStream)
	{
		msg.flags |= RSSL_RQMF_PRIVATE_STREAM;
	}
	if((loginInfo->SupportViewRequests == RSSL_TRUE)  && (viewRequest == RSSL_TRUE))
		msg.flags |= RSSL_RQMF_HAS_VIEW;
	msg.priorityClass = 1;
	msg.priorityCount = 1;

	/* copy the QoS information */
	rsslCopyQos(&(msg.qos), &(srcDirRespInfo->ServiceGeneralInfo.QoS[0]));
	
	/* specify msgKey members */
	msg.msgBase.msgKey.flags = RSSL_MKF_HAS_NAME_TYPE | RSSL_MKF_HAS_NAME | RSSL_MKF_HAS_SERVICE_ID;
	msg.msgBase.msgKey.nameType = RDM_INSTRUMENT_NAME_TYPE_RIC;
	if (!isPrivateStream) /* non-private stream */
	{
		listIndex = streamId - MARKETPRICE_STREAM_ID_START;
		msg.msgBase.msgKey.name.data = marketPriceItemInfoList[listIndex].itemname;
		msg.msgBase.msgKey.name.length = marketPriceItemInfoList[listIndex].nameLength;
	}
	else /* private stream */
	{
		listIndex = streamId - MARKETPRICE_PRIVATE_STREAM_ID_START;
		msg.msgBase.msgKey.name.data = marketPricePSItemInfoList[listIndex].itemname;
		msg.msgBase.msgKey.name.length = marketPricePSItemInfoList[listIndex].nameLength;
	}
	msg.msgBase.msgKey.serviceId = (RsslUInt16)getServiceId();
	
	/* encode message */
	if((ret = rsslSetEncodeIteratorBuffer(&encodeIter, msgBuf)) < RSSL_RET_SUCCESS)
	{
		printf("rsslSetEncodeIteratorBuffer() failed with return code: %d\n", ret);
		return ret;
	}
	rsslSetEncodeIteratorRWFVersion(&encodeIter, chnl->majorVersion, chnl->minorVersion);
	if ((ret = rsslEncodeMsgInit(&encodeIter, (RsslMsg*)&msg, 0)) < RSSL_RET_SUCCESS)
	{
		printf("rsslEncodeMsgInit() failed with return code: %d\n", ret);
		return ret;
	}

	if(viewRequest == RSSL_TRUE) 
	{
		if (loginInfo->SupportViewRequests == RSSL_TRUE)
		{
			eList.flags = RSSL_ELF_HAS_STANDARD_DATA;
			if ((ret = rsslEncodeElementListInit(&encodeIter, &eList, 0, 0)) < RSSL_RET_SUCCESS)
			{
				printf("rsslEncodeElementListInit() failed with return code: %d\n", ret);
				return ret;
			}

			encodeViewElementRequest(&encodeIter);

			if ((ret = rsslEncodeElementListComplete(&encodeIter, RSSL_TRUE)) < RSSL_RET_SUCCESS)
			{
				printf("rsslEncodeElementListComplete() failed with return code: %d\n", ret);
				return ret;
			}
		}
		else
		{
			printf("\nConnected Provider does not support Dynamic View requests.  Disabling View functionality.\n");
			viewRequest = RSSL_FALSE;
		}
	}

	if ((ret = rsslEncodeMsgComplete(&encodeIter, RSSL_TRUE)) < RSSL_RET_SUCCESS)
	{
		printf("rsslEncodeMsgComplete() failed with return code: %d\n", ret);
		return ret;
	}

	msgBuf->length = rsslGetEncodedBufferLength(&encodeIter);


	if (!isPrivateStream) 
		marketPriceItemInfoList[listIndex].streamId = streamId;
	else
		marketPricePSItemInfoList[listIndex].streamId = streamId;

	return RSSL_RET_SUCCESS;
}
/*
 * Sends a source directory response to a channel.  This consists
 * of getting a message buffer, setting the source directory response
 * information, encoding the source directory response, and sending
 * the source directory response to the server.
 * chnl - The channel to send a source directory response to
 */
RsslRet sendSourceDirectoryResponse(RsslChannel* chnl)
{
	RsslError error;
	RsslBuffer* msgBuf = 0;
	RsslSourceDirectoryResponseInfo srcDirRespInfo;
	RsslUInt16 refreshFlags = 0;
	RsslMsgKey key = RSSL_INIT_MSG_KEY;

	/* initialize source directory response info */
	initSourceDirRespInfo(&srcDirRespInfo);

	/* get a buffer for the source directory response */
	msgBuf = rsslGetBuffer(chnl, MAX_MSG_SIZE, RSSL_FALSE, &error);

	if (msgBuf != NULL)
	{
		/* provide source directory response information */
		/* set refresh flags */
		refreshFlags = RSSL_RFMF_HAS_MSG_KEY | RSSL_RFMF_REFRESH_COMPLETE | RSSL_RFMF_CLEAR_CACHE;
		/* set filter flags */
		key.filter = RDM_DIRECTORY_SERVICE_INFO_FILTER | \
					RDM_DIRECTORY_SERVICE_STATE_FILTER| \
					/*RDM_DIRECTORY_SERVICE_GROUP_FILTER | \ not applicable for refresh message - here for reference*/
					RDM_DIRECTORY_SERVICE_LOAD_FILTER | \
					/*RDM_DIRECTORY_SERVICE_DATA_FILTER | \ not applicable for non-ANSI Page based provider - here for reference*/
					RDM_DIRECTORY_SERVICE_LINK_FILTER;
		/* StreamId */
		srcDirRespInfo.StreamId = SRCDIR_STREAM_ID;
		/* ServiceId */
		srcDirRespInfo.ServiceId = getServiceId();
		/* ServiceName */
		snprintf(srcDirRespInfo.ServiceGeneralInfo.ServiceName, 256, "%s", serviceName);
		/* Vendor */
		snprintf(srcDirRespInfo.ServiceGeneralInfo.Vendor, 256, "%s", vendorName);
		/* Capabilities */
		srcDirRespInfo.ServiceGeneralInfo.Capabilities[0] = RSSL_DMT_DICTIONARY;
		srcDirRespInfo.ServiceGeneralInfo.Capabilities[1] = RSSL_DMT_MARKET_PRICE;
		srcDirRespInfo.ServiceGeneralInfo.Capabilities[2] = RSSL_DMT_MARKET_BY_ORDER;
		/* DictionariesProvided */
		snprintf(srcDirRespInfo.ServiceGeneralInfo.DictionariesProvided[0], 256, "%s", fieldDictionaryName);
		snprintf(srcDirRespInfo.ServiceGeneralInfo.DictionariesProvided[1], 256, "%s", enumTypeDictionaryName);
		/* DictionariesUsed */
		snprintf(srcDirRespInfo.ServiceGeneralInfo.DictionariesUsed[0], 256, "%s", fieldDictionaryName);
		snprintf(srcDirRespInfo.ServiceGeneralInfo.DictionariesUsed[1], 256, "%s", enumTypeDictionaryName);
		/* Qos */
		srcDirRespInfo.ServiceGeneralInfo.QoS[0].dynamic = RSSL_FALSE;
		srcDirRespInfo.ServiceGeneralInfo.QoS[0].rate = RSSL_QOS_RATE_TICK_BY_TICK;
		srcDirRespInfo.ServiceGeneralInfo.QoS[0].timeliness = RSSL_QOS_TIME_REALTIME;
		/* ItemList */
		snprintf(srcDirRespInfo.ServiceGeneralInfo.ItemList, 256, "");
		/* Service StateInfo Status */
		srcDirRespInfo.ServiceStateInfo.Status.streamState = RSSL_STREAM_OPEN;
		srcDirRespInfo.ServiceStateInfo.Status.dataState = RSSL_DATA_OK;
		srcDirRespInfo.ServiceStateInfo.Status.code = RSSL_SC_NONE;
		srcDirRespInfo.ServiceStateInfo.Status.text.data = (char *)"OK";
		srcDirRespInfo.ServiceStateInfo.Status.text.length = (RsslUInt32)strlen("OK");
		/* OpenLimit */
		srcDirRespInfo.ServiceLoadInfo.OpenLimit = OPEN_LIMIT;
		srcDirRespInfo.ServiceLoadInfo.OpenWindow = 0;	 /* Don't send OpenWindow. */
		/* Link Name */
		snprintf(srcDirRespInfo.ServiceLinkInfo[0].LinkName, 256, "%s", linkName);
		/* Link Text */
		snprintf(srcDirRespInfo.ServiceLinkInfo[0].Text, 256, "Link state is up");
		/* keep default values for all others */

		/* encode source directory response */
		if (encodeSourceDirectoryResponse(chnl, &srcDirRespInfo, &key, msgBuf, refreshFlags) != RSSL_RET_SUCCESS)
		{
			rsslReleaseBuffer(msgBuf, &error); 
			printf("\nencodeSourceDirectoryResponse() failed\n");
			return RSSL_RET_FAILURE;
		}

		/* send source directory response */
		if (sendMessage(chnl, msgBuf) != RSSL_RET_SUCCESS)
			return RSSL_RET_FAILURE;
	}
	else
	{
		printf("rsslGetBuffer(): Failed <%s>\n", error.text);
		return RSSL_RET_FAILURE;
	}

	return RSSL_RET_SUCCESS;
}