+ eDVBChannelID chid;
+ serviceRef->getChannelID(chid);
+ chids.push_back(chid);
+ sids.push_back(serviceRef->getServiceID().get());
+ }
+ submitEventData(sids, chids, start, duration, title, short_summary, long_description, event_type, EPG_IMPORT);
+}
+
+void eEPGCache::submitEventData(const std::vector<int>& sids, const std::vector<eDVBChannelID>& chids, long start,
+ long duration, const char* title, const char* short_summary,
+ const char* long_description, char event_type, int source)
+{
+ if (!title)
+ return;
+ if (sids.size() != chids.size())
+ return;
+ static const int EIT_LENGTH = 4108;
+ static const uint8_t codePage = 0x15; // UTF-8 encoding
+ uint8_t data[EIT_LENGTH];
+
+ eit_t *packet = (eit_t *) data;
+ packet->table_id = 0x50;
+ packet->section_syntax_indicator = 1;
+
+ packet->version_number = 0; // eEPGCache::sectionRead() will dig this for the moment
+ packet->current_next_indicator = 0;
+ packet->section_number = 0; // eEPGCache::sectionRead() will dig this for the moment
+ packet->last_section_number = 0; // eEPGCache::sectionRead() will dig this for the moment
+
+ packet->segment_last_section_number = 0; // eEPGCache::sectionRead() will dig this for the moment
+ packet->segment_last_table_id = 0x50;
+
+ eit_event_t *evt_struct = (eit_event_t*) (data + EIT_SIZE);
+
+ uint16_t eventId = start & 0xFFFF;
+ evt_struct->setEventId(eventId);
+
+ //6 bytes start time, 3 bytes duration
+ fill_eit_start(evt_struct, start);
+ fill_eit_duration(evt_struct, duration);
+
+ evt_struct->running_status = 0;
+ evt_struct->free_CA_mode = 0;
+
+ //no support for different code pages, only DVB's latin1 character set
+ //TODO: convert text to correct character set (data is probably passed in as UTF-8)
+ uint8_t *x = (uint8_t *) evt_struct;
+ x += EIT_LOOP_SIZE;
+ int nameLength = strnlen(title, 246);
+ int descLength = short_summary ? strnlen(short_summary, 246 - nameLength) : 0;
+
+ eit_short_event_descriptor_struct *short_evt = (eit_short_event_descriptor_struct*) x;
+ short_evt->descriptor_tag = SHORT_EVENT_DESCRIPTOR;
+ short_evt->descriptor_length = EIT_SHORT_EVENT_DESCRIPTOR_SIZE + nameLength + descLength + 1 - 2; //+1 for length of short description, -2 for tag and length
+ if (nameLength) ++short_evt->descriptor_length; // +1 for codepage byte
+ if (descLength) ++short_evt->descriptor_length;
+ short_evt->language_code_1 = 'e';
+ short_evt->language_code_2 = 'n';
+ short_evt->language_code_3 = 'g';
+ short_evt->event_name_length = nameLength ? nameLength + 1 : 0;
+ x = (uint8_t *) short_evt;
+ x += EIT_SHORT_EVENT_DESCRIPTOR_SIZE;
+ *x = codePage;
+ ++x;
+ memcpy(x, title, nameLength);
+ x += nameLength;
+ if (descLength)
+ {
+ *x = descLength + 1;
+ ++x;
+ *x = codePage;
+ ++x;
+ memcpy(x, short_summary, descLength);
+ x += descLength;
+ }
+ else
+ {
+ *x = 0;
+ ++x;
+ }
+
+ //Content type
+ if (event_type != 0)
+ {
+ x[0] = 0x54;
+ x[1] = 2;
+ x[2] = event_type;
+ x[3] = 0;
+ x += 4;
+ }
+
+ //Long description
+ int currentLoopLength = x - (uint8_t*)short_evt;
+ static const int overheadPerDescriptor = 9; //increase if codepages are added!!!
+ static const int MAX_LEN = 256 - overheadPerDescriptor;
+
+ int textLength = long_description ? strnlen(long_description, EIT_LENGTH) : 0;//EIT_LENGTH is a bit too much, but it's only here as a reasonable end point
+ int lastDescriptorNumber = (textLength + MAX_LEN-1) / MAX_LEN - 1;
+ int remainingTextLength = textLength - lastDescriptorNumber * MAX_LEN;
+
+ //if long description is too long, just try to fill as many descriptors as possible
+ while ( (lastDescriptorNumber+1) * 256 + currentLoopLength > EIT_LENGTH - EIT_LOOP_SIZE)
+ {
+ lastDescriptorNumber--;
+ remainingTextLength = MAX_LEN;
+ }
+
+ for (int descrIndex = 0; descrIndex <= lastDescriptorNumber; ++descrIndex)
+ {
+ eit_extended_descriptor_struct *ext_evt = (eit_extended_descriptor_struct*) x;
+ ext_evt->descriptor_tag = EIT_EXTENDED_EVENT_DESCRIPOR;
+ //descriptor header length is 6, including the 2 tag and length bytes
+ //so the length field must be: stringlength + 1 (2 4-bits numbers) + 3 (lang code) + 2 bytes for item info length field and text length field
+ int currentTextLength = descrIndex < lastDescriptorNumber ? MAX_LEN : remainingTextLength;
+ ext_evt->descriptor_length = 6 + currentTextLength + 1;
+
+ ext_evt->descriptor_number = descrIndex;
+ ext_evt->last_descriptor_number = lastDescriptorNumber;
+ ext_evt->iso_639_2_language_code_1 = 'e';
+ ext_evt->iso_639_2_language_code_2 = 'n';
+ ext_evt->iso_639_2_language_code_3 = 'g';
+
+ x[6] = 0; //item information (car, year, director, etc. Unsupported for now)
+ x[7] = currentTextLength + 1; //length of description string (part in this message)
+ x[8] = codePage;
+ memcpy(x + 9, &long_description[descrIndex*MAX_LEN], currentTextLength);
+
+ x += 2 + ext_evt->descriptor_length;
+ }
+
+ //TODO: add age and more
+ int desc_loop_length = x - ((uint8_t*)evt_struct + EIT_LOOP_SIZE);
+ evt_struct->setDescriptorsLoopLength(desc_loop_length);
+
+ int packet_length = (x - data) - 3; //should add 1 for crc....
+ packet->setSectionLength(packet_length);
+ // Add channelrefs and submit data.
+ for (unsigned int i = 0; i < chids.size(); i++)
+ {
+ packet->setServiceId(sids[i]);
+ packet->setTransportStreamId(chids[i].transport_stream_id.get());
+ packet->setOriginalNetworkId(chids[i].original_network_id.get());
+ sectionRead(data, source, 0);
+ }
+}
+
+void eEPGCache::setEpgHistorySeconds(time_t seconds)
+{
+ historySeconds = seconds;
+}
+
+void eEPGCache::setEpgSources(unsigned int mask)
+{
+ enabledSources = mask;
+}
+
+unsigned int eEPGCache::getEpgSources()
+{
+ return enabledSources;
+}
+
+static const char* getStringFromPython(ePyObject obj)
+{
+ char *result = 0;
+ if (PyString_Check(obj))
+ {
+ result = PyString_AS_STRING(obj);
+ }
+ return result;
+}
+
+void eEPGCache::importEvent(ePyObject serviceReference, ePyObject list)
+{
+ importEvents(serviceReference, list);
+}
+
+//here we get a python tuple of tuples ;)
+// consider it an array of objects with the following data
+// 1. start time (long)
+// 2. duration (int)
+// 3. event title (string)
+// 4. short description (string)
+// 5. extended description (string)
+// 6. event type (byte)
+void eEPGCache::importEvents(ePyObject serviceReferences, ePyObject list)
+{
+ std::vector<eServiceReferenceDVB> refs;
+
+ if (PyString_Check(serviceReferences))
+ {
+ char *refstr;
+ refstr = PyString_AS_STRING(serviceReferences);
+ if (!refstr)