check if e2 is currently recording before entering the positioner plugin (and prevent...
[enigma2.git] / lib / dvb / db.cpp
1 #include <errno.h>
2 #include <lib/dvb/db.h>
3 #include <lib/dvb/dvb.h>
4 #include <lib/dvb/frontend.h>
5 #include <lib/dvb/epgcache.h>
6 #include <lib/base/eerror.h>
7 #include <lib/base/estring.h>
8 #include <dvbsi++/service_description_section.h>
9 #include <dvbsi++/descriptor_tag.h>
10 #include <dvbsi++/service_descriptor.h>
11 #include <dvbsi++/satellite_delivery_system_descriptor.h>
12
13 DEFINE_REF(eDVBService);
14
15 RESULT eBouquet::addService(const eServiceReference &ref)
16 {
17         list::iterator it =
18                 std::find(m_services.begin(), m_services.end(), ref);
19         if ( it != m_services.end() )
20                 return -1;
21         m_services.push_back(ref);
22         return 0;
23 }
24
25 RESULT eBouquet::removeService(const eServiceReference &ref)
26 {
27         list::iterator it =
28                 std::find(m_services.begin(), m_services.end(), ref);
29         if ( it == m_services.end() )
30                 return -1;
31         m_services.erase(it);
32         return 0;
33 }
34
35 RESULT eBouquet::moveService(const eServiceReference &ref, unsigned int pos)
36 {
37         if ( pos < 0 || pos >= m_services.size() )
38                 return -1;
39         ++pos;
40         list::iterator source=m_services.end();
41         list::iterator dest=m_services.end();
42         bool forward = false;
43         for (list::iterator it(m_services.begin()); it != m_services.end(); ++it)
44         {
45                 if (dest == m_services.end() && !--pos)
46                         dest = it;
47                 if (*it == ref)
48                 {
49                         source = it;
50                         forward = pos>0;
51                 }
52                 if (dest != m_services.end() && source != m_services.end())
53                         break;
54         }
55         if (dest == m_services.end() || source == m_services.end() || source == dest)
56                 return -1;
57         while (source != dest)
58         {
59                 if (forward)
60                         std::iter_swap(source++, source);
61                 else
62                         std::iter_swap(source--, source);
63         }
64         return 0;
65 }
66
67 RESULT eBouquet::flushChanges()
68 {
69         FILE *f=fopen((CONFIGDIR"/enigma2/"+m_filename).c_str(), "w");
70         if (!f)
71                 return -1;
72         if ( fprintf(f, "#NAME %s\r\n", m_bouquet_name.c_str()) < 0 )
73                 goto err;
74         for (list::iterator i(m_services.begin()); i != m_services.end(); ++i)
75         {
76                 eServiceReference tmp = *i;
77                 std::string str = tmp.path;
78                 if ( (i->flags&eServiceReference::flagDirectory) == eServiceReference::flagDirectory )
79                 {
80                         unsigned int p1 = str.find("FROM BOUQUET \"");
81                         if (p1 == std::string::npos)
82                         {
83                                 eDebug("doof... kaputt");
84                                 continue;
85                         }
86                         str.erase(0, p1+14);
87                         p1 = str.find("\"");
88                         if (p1 == std::string::npos)
89                         {
90                                 eDebug("doof2... kaputt");
91                                 continue;
92                         }
93                         str.erase(p1);
94                         tmp.path=str;
95                 }
96                 if ( fprintf(f, "#SERVICE %s\r\n", tmp.toString().c_str()) < 0 )
97                         goto err;
98                 if ( i->name.length() )
99                         if ( fprintf(f, "#DESCRIPTION %s\r\n", i->name.c_str()) < 0 )
100                                 goto err;
101         }
102         fclose(f);
103         return 0;
104 err:
105         fclose(f);
106         eDebug("couldn't write file %s", m_filename.c_str());
107         return -1;
108 }
109
110 RESULT eBouquet::setListName(const std::string &name)
111 {
112         m_bouquet_name = name;
113         return 0;
114 }
115
116 eDVBService::eDVBService()
117         :m_flags(0)
118 {
119 }
120
121 eDVBService::~eDVBService()
122 {
123 }
124
125 eDVBService &eDVBService::operator=(const eDVBService &s)
126 {
127         m_service_name = s.m_service_name;
128         m_service_name_sort = s.m_service_name_sort;
129         m_provider_name = s.m_provider_name;
130         m_flags = s.m_flags;
131         m_ca = s.m_ca;
132         m_cache = s.m_cache;
133         return *this;
134 }
135
136 void eDVBService::genSortName()
137 {
138         m_service_name_sort = removeDVBChars(m_service_name);
139         makeUpper(m_service_name_sort);
140         while ((!m_service_name_sort.empty()) && m_service_name_sort[0] == ' ')
141                 m_service_name_sort.erase(0, 1);
142
143                 /* put unnamed services at the end, not at the beginning. */
144         if (m_service_name_sort.empty())
145                 m_service_name_sort = "\xFF";
146 }
147
148 RESULT eDVBService::getName(const eServiceReference &ref, std::string &name)
149 {
150         if (!ref.name.empty())
151                 name = ref.name; // use renamed service name..
152         else if (!m_service_name.empty())
153                 name = m_service_name;
154         else
155                 name = "(...)";
156         return 0;
157 }
158
159 RESULT eDVBService::getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &ptr, time_t start_time)
160 {
161         return eEPGCache::getInstance()->lookupEventTime(ref, start_time, ptr);
162 }
163
164 bool eDVBService::isPlayable(const eServiceReference &ref, const eServiceReference &ignore)
165 {
166         ePtr<eDVBResourceManager> res_mgr;
167         if ( eDVBResourceManager::getInstance( res_mgr ) )
168                 eDebug("isPlayble... no res manager!!");
169         else
170         {
171                 eDVBChannelID chid, chid_ignore;
172                 ((const eServiceReferenceDVB&)ref).getChannelID(chid);
173                 ((const eServiceReferenceDVB&)ignore).getChannelID(chid_ignore);
174                 return res_mgr->canAllocateChannel(chid, chid_ignore);
175         }
176         return false;
177 }
178
179 int eDVBService::checkFilter(const eServiceReferenceDVB &ref, const eDVBChannelQuery &query)
180 {
181         int res = 0;
182         switch (query.m_type)
183         {
184         case eDVBChannelQuery::tName:
185                 res = m_service_name_sort.find(query.m_string) != std::string::npos;
186                 break;
187         case eDVBChannelQuery::tProvider:
188                 res = m_provider_name.find(query.m_string) != std::string::npos;
189                 break;
190         case eDVBChannelQuery::tType:
191                 res = ref.getServiceType() == query.m_int;
192                 break;
193         case eDVBChannelQuery::tBouquet:
194                 res = 0;
195                 break;
196         case eDVBChannelQuery::tSatellitePosition:
197                 res = ((unsigned int)ref.getDVBNamespace().get())>>16 == query.m_int;
198                 break;
199         case eDVBChannelQuery::tChannelID:
200         {
201                 eDVBChannelID chid;
202                 ref.getChannelID(chid);
203                 res = chid == query.m_channelid;
204                 break;
205         }
206         case eDVBChannelQuery::tAND:
207                 res = checkFilter(ref, *query.m_p1) && checkFilter(ref, *query.m_p2);
208                 break;
209         case eDVBChannelQuery::tOR:
210                 res = checkFilter(ref, *query.m_p1) || checkFilter(ref, *query.m_p2);
211                 break;
212         case eDVBChannelQuery::tAny:
213                 res = 1;
214                 break;
215         }
216
217         if (query.m_inverse)
218                 return !res;
219         else
220                 return res;
221 }
222
223 int eDVBService::getCachePID(cacheID id)
224 {
225         std::map<int, int>::iterator it = m_cache.find(id);
226         if ( it != m_cache.end() )
227                 return it->second;
228         return -1;
229 }
230
231 void eDVBService::setCachePID(cacheID id, int pid)
232 {
233         if (pid == -1)
234                 m_cache.erase(id);
235         else
236                 m_cache[id] = pid;
237 }
238
239 DEFINE_REF(eDVBDB);
240
241         /* THIS CODE IS BAD. it should be replaced by somethine better. */
242 void eDVBDB::reloadServicelist()
243 {
244         eDebug("---- opening lame channel db");
245         FILE *f=fopen(CONFIGDIR"/enigma2/lamedb", "rt");
246         if (!f)
247         {
248                 struct stat s;
249                 if ( !stat("lamedb", &s) )
250                 {
251                         if ( !stat(CONFIGDIR"/enigma2", &s) )
252                         {
253                                 rename("lamedb", CONFIGDIR"/enigma2/lamedb" );
254                                 reloadServicelist();
255                         }
256                 }
257                 return;
258         }
259         char line[256];
260         if ((!fgets(line, 256, f)) || strncmp(line, "eDVB services", 13))
261         {
262                 eDebug("not a servicefile");
263                 fclose(f);
264                 return;
265         }
266         eDebug("reading services");
267         if ((!fgets(line, 256, f)) || strcmp(line, "transponders\n"))
268         {
269                 eDebug("services invalid, no transponders");
270                 fclose(f);
271                 return;
272         }
273
274         // clear all transponders
275
276         while (!feof(f))
277         {
278                 if (!fgets(line, 256, f))
279                         break;
280                 if (!strcmp(line, "end\n"))
281                         break;
282                 int dvb_namespace=-1, transport_stream_id=-1, original_network_id=-1;
283                 sscanf(line, "%x:%x:%x", &dvb_namespace, &transport_stream_id, &original_network_id);
284                 if (original_network_id == -1)
285                         continue;
286                 eDVBChannelID channelid = eDVBChannelID(
287                         eDVBNamespace(dvb_namespace),
288                         eTransportStreamID(transport_stream_id),
289                         eOriginalNetworkID(original_network_id));
290
291                 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
292                 while (!feof(f))
293                 {
294                         fgets(line, 256, f);
295                         if (!strcmp(line, "/\n"))
296                                 break;
297                         if (line[1]=='s')
298                         {
299                                 eDVBFrontendParametersSatellite sat;
300                                 int frequency, symbol_rate, polarisation, fec, orbital_position, inversion;
301                                 sscanf(line+2, "%d:%d:%d:%d:%d:%d", &frequency, &symbol_rate, &polarisation, &fec, &orbital_position, &inversion);
302                                 sat.frequency = frequency;
303                                 sat.symbol_rate = symbol_rate;
304                                 sat.polarisation = polarisation;
305                                 sat.fec = fec;
306                                 sat.orbital_position =
307                                         orbital_position < 0 ? orbital_position + 3600 : orbital_position;
308                                 sat.inversion = inversion;
309                                 feparm->setDVBS(sat);
310                         } else if (line[1]=='t')
311                         {
312                                 eDVBFrontendParametersTerrestrial ter;
313                                 int frequency, bandwidth, code_rate_HP, code_rate_LP, modulation, transmission_mode, guard_interval, hierarchy, inversion;
314                                 sscanf(line+2, "%d:%d:%d:%d:%d:%d:%d:%d:%d", &frequency, &bandwidth, &code_rate_HP, &code_rate_LP, &modulation, &transmission_mode, &guard_interval, &hierarchy, &inversion);
315                                 ter.frequency = frequency;
316                                 ter.bandwidth = bandwidth;
317                                 ter.code_rate_HP = code_rate_HP;
318                                 ter.code_rate_LP = code_rate_LP;
319                                 ter.modulation = modulation;
320                                 ter.transmission_mode = transmission_mode;
321                                 ter.guard_interval = guard_interval;
322                                 ter.hierarchy = hierarchy;
323                                 ter.inversion = inversion;
324                                 feparm->setDVBT(ter);
325                         } else if (line[1]=='c')
326                         {
327                                 eDVBFrontendParametersCable cab;
328                                 int frequency, symbol_rate,
329                                         inversion=eDVBFrontendParametersCable::Inversion::Unknown,
330                                         modulation=eDVBFrontendParametersCable::Modulation::Auto,
331                                         fec_inner=eDVBFrontendParametersCable::FEC::fAuto;
332                                 sscanf(line+2, "%d:%d:%d:%d:%d", &frequency, &symbol_rate, &inversion, &modulation, &fec_inner);
333                                 cab.frequency = frequency;
334                                 cab.fec_inner = fec_inner;
335                                 cab.inversion = inversion;
336                                 cab.symbol_rate = symbol_rate;
337                                 cab.modulation = modulation;
338                                 feparm->setDVBC(cab);
339                         }
340                 }
341                 addChannelToList(channelid, feparm);
342         }
343
344         if ((!fgets(line, 256, f)) || strcmp(line, "services\n"))
345         {
346                 eDebug("services invalid, no services");
347                 return;
348         }
349
350         // clear all services
351
352         int count=0;
353
354         while (!feof(f))
355         {
356                 if (!fgets(line, 256, f))
357                         break;
358                 if (!strcmp(line, "end\n"))
359                         break;
360
361                 int service_id=-1, dvb_namespace, transport_stream_id=-1, original_network_id=-1, service_type=-1, service_number=-1;
362                 sscanf(line, "%x:%x:%x:%x:%d:%d", &service_id, &dvb_namespace, &transport_stream_id, &original_network_id, &service_type, &service_number);
363                 if (service_number == -1)
364                         continue;
365                 ePtr<eDVBService> s = new eDVBService;
366                 eServiceReferenceDVB ref =
367                                                 eServiceReferenceDVB(
368                                                 eDVBNamespace(dvb_namespace),
369                                                 eTransportStreamID(transport_stream_id),
370                                                 eOriginalNetworkID(original_network_id),
371                                                 eServiceID(service_id),
372                                                 service_type);
373                 count++;
374                 fgets(line, 256, f);
375                 if (strlen(line))
376                         line[strlen(line)-1]=0;
377
378                 s->m_service_name = line;
379                 s->genSortName();
380
381                 fgets(line, 256, f);
382                 if (strlen(line))
383                         line[strlen(line)-1]=0;
384                 std::string str=line;
385
386                 if (str[1]!=':')        // old ... (only service_provider)
387                 {
388                         s->m_provider_name=line;
389                 } else
390                         while ((!str.empty()) && str[1]==':') // new: p:, f:, c:%02d...
391                         {
392                                 unsigned int c=str.find(',');
393                                 char p=str[0];
394                                 std::string v;
395                                 if (c == std::string::npos)
396                                 {
397                                         v=str.substr(2);
398                                         str="";
399                                 } else
400                                 {
401                                         v=str.substr(2, c-2);
402                                         str=str.substr(c+1);
403                                 }
404 //                              eDebug("%c ... %s", p, v.c_str());
405                                 if (p == 'p')
406                                         s->m_provider_name=v;
407                                 else if (p == 'f')
408                                 {
409                                         sscanf(v.c_str(), "%x", &s->m_flags);
410                                 } else if (p == 'c')
411                                 {
412                                         int cid, val;
413                                         sscanf(v.c_str(), "%02d%04x", &cid, &val);
414                                         s->m_cache[cid]=val;
415                                 } else if (p == 'C')
416                                 {
417                                         int val;
418                                         sscanf(v.c_str(), "%04x", &val);
419                                         s->m_ca.insert(val);
420                                 }
421                         }
422                 addService(ref, s);
423         }
424
425         eDebug("loaded %d services", count);
426
427         fclose(f);
428 }
429
430 void eDVBDB::saveServicelist()
431 {
432         eDebug("---- saving lame channel db");
433         FILE *f=fopen(CONFIGDIR"/enigma2/lamedb", "w");
434         int channels=0, services=0;
435         if (!f)
436                 eFatal("couldn't save lame channel db!");
437         fprintf(f, "eDVB services /3/\n");
438         fprintf(f, "transponders\n");
439         for (std::map<eDVBChannelID, channel>::const_iterator i(m_channels.begin());
440                         i != m_channels.end(); ++i)
441         {
442                 const eDVBChannelID &chid = i->first;
443                 const channel &ch = i->second;
444
445                 fprintf(f, "%08x:%04x:%04x\n", chid.dvbnamespace.get(),
446                                 chid.transport_stream_id.get(), chid.original_network_id.get());
447                 eDVBFrontendParametersSatellite sat;
448                 eDVBFrontendParametersTerrestrial ter;
449                 eDVBFrontendParametersCable cab;
450                 if (!ch.m_frontendParameters->getDVBS(sat))
451                 {
452                         fprintf(f, "\ts %d:%d:%d:%d:%d:%d\n",
453                                 sat.frequency, sat.symbol_rate,
454                                 sat.polarisation, sat.fec,
455                                 sat.orbital_position > 1800 ? sat.orbital_position - 3600 : sat.orbital_position,
456                                 sat.inversion);
457                 }
458                 if (!ch.m_frontendParameters->getDVBT(ter))
459                 {
460                         fprintf(f, "\tt %d:%d:%d:%d:%d:%d:%d:%d:%d\n",
461                                 ter.frequency, ter.bandwidth, ter.code_rate_HP,
462                                 ter.code_rate_LP, ter.modulation, ter.transmission_mode,
463                                 ter.guard_interval, ter.hierarchy, ter.inversion);
464                 }
465                 if (!ch.m_frontendParameters->getDVBC(cab))
466                 {
467                         fprintf(f, "\tc %d:%d:%d:%d:%d\n",
468                                 cab.frequency, cab.symbol_rate, cab.inversion, cab.modulation, cab.fec_inner);
469                 }
470                 fprintf(f, "/\n");
471                 channels++;
472         }
473         fprintf(f, "end\nservices\n");
474
475         for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator i(m_services.begin());
476                 i != m_services.end(); ++i)
477         {
478                 const eServiceReferenceDVB &s = i->first;
479                 fprintf(f, "%04x:%08x:%04x:%04x:%d:%d\n",
480                                 s.getServiceID().get(), s.getDVBNamespace().get(),
481                                 s.getTransportStreamID().get(),s.getOriginalNetworkID().get(),
482                                 s.getServiceType(),
483                                 0);
484
485                 fprintf(f, "%s\n", i->second->m_service_name.c_str());
486
487                 fprintf(f, "p:%s", i->second->m_provider_name.c_str());
488
489                 // write cached pids
490                 for (std::map<int,int>::const_iterator ca(i->second->m_cache.begin());
491                         ca != i->second->m_cache.end(); ++ca)
492                         fprintf(f, ",c:%02d%04x", ca->first, ca->second);
493
494                 // write cached ca pids
495                 for (std::set<int>::const_iterator ca(i->second->m_ca.begin());
496                         ca != i->second->m_ca.end(); ++ca)
497                         fprintf(f, ",C:%04x", *ca);
498
499                 if (i->second->m_flags)
500                         fprintf(f, ",f:%x", i->second->m_flags);
501
502                 fprintf(f, "\n");
503                 services++;
504         }
505         fprintf(f, "end\nHave a lot of bugs!\n");
506         eDebug("saved %d channels and %d services!", channels, services);
507         fclose(f);
508 }
509
510 void eDVBDB::loadBouquet(const char *path)
511 {
512         std::string bouquet_name = path;
513         if (!bouquet_name.length())
514         {
515                 eDebug("Bouquet load failed.. no path given..");
516                 return;
517         }
518         unsigned int pos = bouquet_name.rfind('/');
519         if ( pos != std::string::npos )
520                 bouquet_name.erase(0, pos+1);
521         if (bouquet_name.empty())
522         {
523                 eDebug("Bouquet load failed.. no filename given..");
524                 return;
525         }
526         eBouquet &bouquet = m_bouquets[bouquet_name];
527         bouquet.m_filename = bouquet_name;
528         std::list<eServiceReference> &list = bouquet.m_services;
529         list.clear();
530
531         std::string p = CONFIGDIR"/enigma2/";
532         p+=path;
533         eDebug("loading bouquet... %s", p.c_str());
534         FILE *fp=fopen(p.c_str(), "rt");
535         int entries=0;
536         if (!fp)
537         {
538                 struct stat s;
539                 if ( !stat(path, &s) )
540                 {
541                         rename(path, p.c_str() );
542                         loadBouquet(path);
543                         return;
544                 }
545                 eDebug("failed to open.");
546                 if ( strstr(path, "bouquets.tv") )
547                 {
548                         eDebug("recreate bouquets.tv");
549                         bouquet.m_bouquet_name="Bouquets (TV)";
550                         bouquet.flushChanges();
551                 }
552                 else if ( strstr(path, "bouquets.radio") )
553                 {
554                         eDebug("recreate bouquets.radio");
555                         bouquet.m_bouquet_name="Bouquets (Radio)";
556                         bouquet.flushChanges();
557                 }
558                 return;
559         }
560         char line[256];
561         bool read_descr=false;
562         eServiceReference *e = NULL;
563         while (1)
564         {
565                 if (!fgets(line, 256, fp))
566                         break;
567                 line[strlen(line)-1]=0;
568                 if (strlen(line) && line[strlen(line)-1]=='\r')
569                         line[strlen(line)-1]=0;
570                 if (!line[0])
571                         break;
572                 if (line[0]=='#')
573                 {
574                         if (!strncmp(line, "#SERVICE ", 9) || !strncmp(line, "#SERVICE: ", 10))
575                         {
576                                 int offs = line[8] == ':' ? 10 : 9;
577                                 eServiceReference tmp(line+offs);
578                                 if (tmp.type != eServiceReference::idDVB)
579                                 {
580                                         eDebug("only DVB Bouquets supported");
581                                         continue;
582                                 }
583                                 if ( (tmp.flags&eServiceReference::flagDirectory) == eServiceReference::flagDirectory )
584                                 {
585                                         unsigned int pos = tmp.path.rfind('/');
586                                         if ( pos != std::string::npos )
587                                                 tmp.path.erase(0, pos+1);
588                                         if (tmp.path.empty())
589                                         {
590                                                 eDebug("Bouquet load failed.. no filename given..");
591                                                 continue;
592                                         }
593                                         loadBouquet(tmp.path.c_str());
594                                         char buf[256];
595                                         snprintf(buf, 256, "(type == %d) FROM BOUQUET \"%s\" ORDER BY bouquet", tmp.data[0], tmp.path.c_str());
596                                         tmp.path = buf;
597                                 }
598                                 list.push_back(tmp);
599                                 e = &list.back();
600                                 read_descr=true;
601                                 ++entries;
602                         }
603                         else if (read_descr && !strncmp(line, "#DESCRIPTION ", 13))
604                         {
605                                 e->name = line+13;
606                                 read_descr=false;
607                         }
608                         else if (!strncmp(line, "#NAME ", 6))
609                                 bouquet.m_bouquet_name=line+6;
610                         continue;
611                 }
612         }
613         fclose(fp);
614         eDebug("%d entries in Bouquet %s", entries, bouquet_name.c_str());
615 }
616
617 void eDVBDB::reloadBouquets()
618 {
619         m_bouquets.clear();
620         loadBouquet("bouquets.tv");
621         loadBouquet("bouquets.radio");
622 // create default bouquets when missing
623         if ( m_bouquets.find("userbouquet.favourites.tv") == m_bouquets.end() )
624         {
625                 eBouquet &b = m_bouquets["userbouquet.favourites.tv"];
626                 b.m_filename = "userbouquet.favourites.tv";
627                 b.m_bouquet_name = "Favourites (TV)";
628                 b.flushChanges();
629                 eServiceReference ref;
630                 memset(ref.data, 0, sizeof(ref.data));
631                 ref.type=1;
632                 ref.flags=7;
633                 ref.data[0]=1;
634                 ref.path="(type == 1) FROM BOUQUET \"userbouquet.favourites.tv\" ORDER BY bouquet";
635                 eBouquet &parent = m_bouquets["bouquets.tv"];
636                 parent.m_services.push_back(ref);
637                 parent.flushChanges();
638         }
639         if ( m_bouquets.find("userbouquet.favourites.radio") == m_bouquets.end() )
640         {
641                 eBouquet &b = m_bouquets["userbouquet.favourites.radio"];
642                 b.m_filename = "userbouquet.favourites.radio";
643                 b.m_bouquet_name = "Favourites (Radio)";
644                 b.flushChanges();
645                 eServiceReference ref;
646                 memset(ref.data, 0, sizeof(ref.data));
647                 ref.type=1;
648                 ref.flags=7;
649                 ref.data[0]=2;
650                 ref.path="(type == 2) FROM BOUQUET \"userbouquet.favourites.radio\" ORDER BY bouquet";
651                 eBouquet &parent = m_bouquets["bouquets.radio"];
652                 parent.m_services.push_back(ref);
653                 parent.flushChanges();
654         }
655 }
656
657 eDVBDB *eDVBDB::instance;
658
659 eDVBDB::eDVBDB()
660 {
661         instance = this;
662         reloadServicelist();
663 }
664
665 eDVBDB::~eDVBDB()
666 {
667         instance=NULL;
668 }
669
670 RESULT eDVBDB::addChannelToList(const eDVBChannelID &id, iDVBFrontendParameters *feparm)
671 {
672         channel ch;
673         assert(feparm);
674         ch.m_frontendParameters = feparm;
675         m_channels.insert(std::pair<eDVBChannelID, channel>(id, ch));
676         return 0;
677 }
678
679 RESULT eDVBDB::removeChannel(const eDVBChannelID &id)
680 {
681         m_channels.erase(id);
682         return 0;
683 }
684
685 RESULT eDVBDB::getChannelFrontendData(const eDVBChannelID &id, ePtr<iDVBFrontendParameters> &parm)
686 {
687         std::map<eDVBChannelID, channel>::iterator i = m_channels.find(id);
688         if (i == m_channels.end())
689         {
690                 parm = 0;
691                 return -ENOENT;
692         }
693         parm = i->second.m_frontendParameters;
694         return 0;
695 }
696
697 RESULT eDVBDB::addService(const eServiceReferenceDVB &serviceref, eDVBService *service)
698 {
699         m_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(serviceref, service));
700         return 0;
701 }
702
703 RESULT eDVBDB::getService(const eServiceReferenceDVB &reference, ePtr<eDVBService> &service)
704 {
705         std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator i;
706         i = m_services.find(reference);
707         if (i == m_services.end())
708         {
709                 service = 0;
710                 return -ENOENT;
711         }
712         service = i->second;
713         return 0;
714 }
715
716 RESULT eDVBDB::flush()
717 {
718         saveServicelist();
719         return 0;
720 }
721
722 RESULT eDVBDB::getBouquet(const eServiceReference &ref, eBouquet* &bouquet)
723 {
724         std::string str = ref.path;
725         if (str.empty())
726         {
727                 eDebug("getBouquet failed.. no path given!");
728                 return -1;
729         }
730         unsigned int pos = str.find("FROM BOUQUET \"");
731         if ( pos != std::string::npos )
732         {
733                 str.erase(0, pos+14);
734                 pos = str.find('"');
735                 if ( pos != std::string::npos )
736                         str.erase(pos);
737                 else
738                         str.clear();
739         }
740         if (str.empty())
741         {
742                 eDebug("getBouquet failed.. couldn't parse bouquet name");
743                 return -1;
744         }
745         std::map<std::string, eBouquet>::iterator i =
746                 m_bouquets.find(str);
747         if (i == m_bouquets.end())
748         {
749                 bouquet = 0;
750                 return -ENOENT;
751         }
752         bouquet = &i->second;
753         return 0;
754 }
755
756 RESULT eDVBDB::startQuery(ePtr<iDVBChannelListQuery> &query, eDVBChannelQuery *q, const eServiceReference &source)
757 {
758         if ( source.path.find("FROM") != std::string::npos )
759         {
760                 if ( source.path.find("BOUQUET") != std::string::npos )
761                         query = new eDVBDBBouquetQuery(this, source, q);
762                 else if ( source.path.find("SATELLITES") != std::string::npos )
763                         query = new eDVBDBSatellitesQuery(this, source, q);
764                 else if ( source.path.find("PROVIDERS") != std::string::npos )
765                         query = new eDVBDBProvidersQuery(this, source, q);
766                 else
767                         eFatal("invalid query %s", source.toString().c_str());
768         }
769         else
770                 query = new eDVBDBQuery(this, source, q);
771         return 0;
772 }
773
774 eServiceReference eDVBDB::searchReference(int tsid, int onid, int sid)
775 {
776         eServiceID Sid(sid);
777         eTransportStreamID Tsid(tsid);
778         eOriginalNetworkID Onid(onid);
779         for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator sit(m_services.begin());
780                 sit != m_services.end(); ++sit)
781         {
782                 if (sit->first.getTransportStreamID() == Tsid &&
783                         sit->first.getOriginalNetworkID() == Onid &&
784                         sit->first.getServiceID() == Sid)
785                         return sit->first;
786         }
787         return eServiceReference();
788 }
789
790 DEFINE_REF(eDVBDBQueryBase);
791
792 eDVBDBQueryBase::eDVBDBQueryBase(eDVBDB *db, const eServiceReference &source, eDVBChannelQuery *query)
793         :m_db(db), m_query(query), m_source(source)
794 {
795 }
796
797 int eDVBDBQueryBase::compareLessEqual(const eServiceReferenceDVB &a, const eServiceReferenceDVB &b)
798 {
799         ePtr<eDVBService> a_service, b_service;
800         
801         int sortmode = m_query ? m_query->m_sort : eDVBChannelQuery::tName;
802         
803         if ((sortmode == eDVBChannelQuery::tName) || (sortmode == eDVBChannelQuery::tProvider))
804         {
805                 if (m_db->getService(a, a_service))
806                         return 1;
807                 if (m_db->getService(b, b_service))
808                         return 1;
809         }
810         
811         switch (sortmode)
812         {
813         case eDVBChannelQuery::tName:
814                 return a_service->m_service_name_sort < b_service->m_service_name_sort;
815         case eDVBChannelQuery::tProvider:
816                 return a_service->m_provider_name < b_service->m_provider_name;
817         case eDVBChannelQuery::tType:
818                 return a.getServiceType() < b.getServiceType();
819         case eDVBChannelQuery::tBouquet:
820                 return 0;
821         case eDVBChannelQuery::tSatellitePosition:
822                 return (a.getDVBNamespace().get() >> 16) < (b.getDVBNamespace().get() >> 16);
823         default:
824                 return 1;
825         }
826         return 0;
827 }
828
829 eDVBDBQuery::eDVBDBQuery(eDVBDB *db, const eServiceReference &source, eDVBChannelQuery *query)
830         :eDVBDBQueryBase(db, source, query)
831 {
832         m_cursor = m_db->m_services.begin();
833 }
834
835 RESULT eDVBDBQuery::getNextResult(eServiceReferenceDVB &ref)
836 {
837         while (m_cursor != m_db->m_services.end())
838         {
839                 ref = m_cursor->first;
840
841                 int res = (!m_query) || m_cursor->second->checkFilter(ref, *m_query);
842
843                 ++m_cursor;
844
845                 if (res)
846                         return 0;
847         }
848
849         ref.type = eServiceReference::idInvalid;
850
851         return 1;
852 }
853
854 eDVBDBBouquetQuery::eDVBDBBouquetQuery(eDVBDB *db, const eServiceReference &source, eDVBChannelQuery *query)
855         :eDVBDBQueryBase(db, source, query), m_cursor(db->m_bouquets[query->m_bouquet_name].m_services.begin())
856 {
857 }
858
859 RESULT eDVBDBBouquetQuery::getNextResult(eServiceReferenceDVB &ref)
860 {
861         eBouquet &bouquet = m_db->m_bouquets[m_query->m_bouquet_name];
862         std::list<eServiceReference> &list = bouquet.m_services;
863         while (m_cursor != list.end())
864         {
865                 ref = *((eServiceReferenceDVB*)&(*m_cursor));
866
867                 std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator it =
868                         m_db->m_services.find(ref);
869
870                 int res = (!m_query) || it == m_db->m_services.end() || it->second->checkFilter(ref, *m_query);
871
872                 ++m_cursor;
873
874                 if (res)
875                         return 0;
876         }
877
878         ref.type = eServiceReference::idInvalid;
879
880         return 1;
881 }
882
883 eDVBDBListQuery::eDVBDBListQuery(eDVBDB *db, const eServiceReference &source, eDVBChannelQuery *query)
884         :eDVBDBQueryBase(db, source, query), m_cursor(m_list.end())
885 {
886 }
887
888 RESULT eDVBDBListQuery::getNextResult(eServiceReferenceDVB &ref)
889 {
890         if (m_cursor != m_list.end())
891         {
892                 ref = *m_cursor++;
893                 return 0;
894         }
895         ref.type = eServiceReference::idInvalid;
896         return 1;
897 }
898
899 int eDVBDBListQuery::compareLessEqual(const eServiceReferenceDVB &a, const eServiceReferenceDVB &b)
900 {
901         if ( m_query->m_sort == eDVBChannelQuery::tSatellitePosition )
902         {
903                 int x = (a.getDVBNamespace().get() >> 16);
904                 int y = (b.getDVBNamespace().get() >> 16);
905                 if ( x > 1800 )
906                         x -= 3600;
907                 if ( y > 1800 )
908                         y -= 3600;
909                 return x < y;
910         }
911         return a.name < b.name;
912 }
913
914 eDVBDBSatellitesQuery::eDVBDBSatellitesQuery(eDVBDB *db, const eServiceReference &source, eDVBChannelQuery *query)
915         :eDVBDBListQuery(db, source, query)
916 {
917         for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator it(m_db->m_services.begin());
918                 it != m_db->m_services.end(); ++it)
919         {
920                 int res = it->second->checkFilter(it->first, *query);
921                 if (res)
922                 {
923                         unsigned int dvbnamespace = it->first.getDVBNamespace().get()&0xFFFF0000;
924                         bool found=0;
925                         for (std::list<eServiceReferenceDVB>::iterator i(m_list.begin()); i != m_list.end(); ++i)
926                                 if ( (i->getDVBNamespace().get()&0xFFFF0000) == dvbnamespace )
927                                 {
928                                         found=true;
929                                         break;
930                                 }
931                         if (!found)
932                         {
933                                 eServiceReferenceDVB ref;
934                                 ref.setDVBNamespace(dvbnamespace);
935                                 ref.flags=eServiceReference::flagDirectory;
936                                 char buf[64];
937                                 snprintf(buf, 64, "(satellitePosition == %d) && ", dvbnamespace>>16);
938
939                                 ref.path=buf+source.path;
940                                 unsigned int pos=ref.path.find("FROM");
941                                 ref.path.erase(pos);
942                                 ref.path+="ORDER BY name";
943 //                              eDebug("ref.path now %s", ref.path.c_str());
944                                 m_list.push_back(ref);
945
946                                 ref.path=buf+source.path;
947                                 pos=ref.path.find("FROM");
948                                 ref.path.erase(pos+5);
949                                 ref.path+="PROVIDERS ORDER BY name";
950 //                              eDebug("ref.path now %s", ref.path.c_str());
951                                 m_list.push_back(ref);
952                         }
953                 }
954         }
955         m_cursor=m_list.begin();
956 }
957
958 eDVBDBProvidersQuery::eDVBDBProvidersQuery(eDVBDB *db, const eServiceReference &source, eDVBChannelQuery *query)
959         :eDVBDBListQuery(db, source, query)
960 {
961         for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator it(m_db->m_services.begin());
962                 it != m_db->m_services.end(); ++it)
963         {
964                 int res = it->second->checkFilter(it->first, *query);
965                 if (res)
966                 {
967                         bool found=0;
968
969                         const char *provider_name = it->second->m_provider_name.length() ?
970                                 it->second->m_provider_name.c_str() :
971                                 "Unknown";
972
973                         for (std::list<eServiceReferenceDVB>::iterator i(m_list.begin()); i != m_list.end(); ++i)
974                                 if (i->name == provider_name)
975                                 {
976                                         found=true;
977                                         break;
978                                 }
979                         if (!found)
980                         {
981                                 eServiceReferenceDVB ref;
982                                 char buf[64];
983                                 ref.name=provider_name;
984                                 snprintf(buf, 64, "(provider == \"%s\") && ", provider_name);
985                                 ref.path=buf+source.path;
986                                 unsigned int pos = ref.path.find("FROM");
987                                 ref.flags=eServiceReference::flagDirectory;
988                                 ref.path.erase(pos);
989                                 ref.path+="ORDER BY name";
990 //                              eDebug("ref.path now %s", ref.path.c_str());
991                                 m_list.push_back(ref);
992                         }
993                 }
994         }
995         m_cursor=m_list.begin();
996 }
997
998 /* (<name|provider|type|bouquet|satpos|chid> <==|...> <"string"|int>)[||,&& (..)] */
999
1000 static int decodeType(const std::string &type)
1001 {
1002         if (type == "name")
1003                 return eDVBChannelQuery::tName;
1004         else if (type == "provider")
1005                 return eDVBChannelQuery::tProvider;
1006         else if (type == "type")
1007                 return eDVBChannelQuery::tType;
1008         else if (type == "bouquet")
1009                 return eDVBChannelQuery::tBouquet;
1010         else if (type == "satellitePosition")
1011                 return eDVBChannelQuery::tSatellitePosition;
1012         else if (type == "channelID")
1013                 return eDVBChannelQuery::tChannelID;
1014         else
1015                 return -1;
1016 }
1017
1018         /* never, NEVER write a parser in C++! */
1019 RESULT parseExpression(ePtr<eDVBChannelQuery> &res, std::list<std::string>::const_iterator begin, std::list<std::string>::const_iterator end)
1020 {
1021         std::list<std::string>::const_iterator end_of_exp;
1022         
1023         if (begin == end)
1024         {
1025                 eDebug("empty expression!");
1026                 return 0;
1027         }
1028         
1029         if (*begin == "(")
1030         {
1031                 end_of_exp = begin;
1032                 while (end_of_exp != end)
1033                         if (*end_of_exp == ")")
1034                                 break;
1035                         else
1036                                 ++end_of_exp;
1037         
1038                 if (end_of_exp == end)
1039                 {
1040                         eDebug("expression parse: end of expression while searching for closing brace");
1041                         return -1;
1042                 }
1043                 
1044                 ++begin;
1045                 // begin..end_of_exp
1046                 int r = parseExpression(res, begin, end_of_exp);
1047                 if (r)
1048                         return r;
1049                 ++end_of_exp;
1050                 
1051                         /* we had only one sub expression */
1052                 if (end_of_exp == end)
1053                 {
1054 //                      eDebug("only one sub expression");
1055                         return 0;
1056                 }
1057                 
1058                         /* otherwise we have an operator here.. */
1059                 
1060                 ePtr<eDVBChannelQuery> r2 = res;
1061                 res = new eDVBChannelQuery();
1062                 res->m_sort = 0;
1063                 res->m_p1 = r2;
1064                 res->m_inverse = 0;
1065                 r2 = 0;
1066                 
1067                 if (*end_of_exp == "||")
1068                         res->m_type = eDVBChannelQuery::tOR;
1069                 else if (*end_of_exp == "&&")
1070                         res->m_type = eDVBChannelQuery::tAND;
1071                 else
1072                 {
1073                         eDebug("found operator %s, but only && and || are allowed!", end_of_exp->c_str());
1074                         res = 0;
1075                         return 1;
1076                 }
1077                 
1078                 ++end_of_exp;
1079                 
1080                 return parseExpression(res->m_p2, end_of_exp, end);
1081         }
1082         
1083         // "begin" <op> "end"
1084         std::string type, op, val;
1085         
1086         res = new eDVBChannelQuery();
1087         res->m_sort = 0;
1088         
1089         int cnt = 0;
1090         while (begin != end)
1091         {
1092                 switch (cnt)
1093                 {
1094                 case 0:
1095                         type = *begin;
1096                         break;
1097                 case 1:
1098                         op = *begin;
1099                         break;
1100                 case 2:
1101                         val = *begin;
1102                         break;
1103                 case 3:
1104                         eDebug("malformed query: got '%s', but expected only <type> <op> <val>", begin->c_str());
1105                         return 1;
1106                 }
1107                 ++begin;
1108                 ++cnt;
1109         }
1110         
1111         if (cnt != 3)
1112         {
1113                 eDebug("malformed query: missing stuff");
1114                 res = 0;
1115                 return 1;
1116         }
1117         
1118         res->m_type = decodeType(type);
1119         
1120         if (res->m_type == -1)
1121         {
1122                 eDebug("malformed query: invalid type %s", type.c_str());
1123                 res = 0;
1124                 return 1;
1125         }
1126         
1127         if (op == "==")
1128                 res->m_inverse = 0;
1129         else if (op == "!=")
1130                 res->m_inverse = 1;
1131         else
1132         {
1133                 eDebug("invalid operator %s", op.c_str());
1134                 res = 0;
1135                 return 1;
1136         }
1137         
1138         res->m_string = val;
1139         res->m_int = atoi(val.c_str());
1140 //      res->m_channelid = eDVBChannelID(val);
1141         
1142         return 0;
1143 }
1144
1145 RESULT eDVBChannelQuery::compile(ePtr<eDVBChannelQuery> &res, std::string query)
1146 {
1147         std::list<std::string> tokens;
1148         
1149         std::string current_token;
1150         std::string bouquet_name;
1151
1152 //      eDebug("splitting %s....", query.c_str());
1153         unsigned int i = 0;
1154         const char *splitchars="()";
1155         int quotemode = 0, lastsplit = 0, lastalnum = 0;
1156         while (i <= query.size())
1157         {
1158                 int c = (i < query.size()) ? query[i] : ' ';
1159                 ++i;
1160                 
1161                 int issplit = !!strchr(splitchars, c);
1162                 int isaln = isalnum(c);
1163                 int iswhite = c == ' ';
1164                 int isquot = c == '\"';
1165                 
1166                 if (quotemode)
1167                 {
1168                         iswhite = issplit = 0;
1169                         isaln = lastalnum;
1170                 }
1171                 
1172                 if (issplit || iswhite || isquot || lastsplit || (lastalnum != isaln))
1173                 {
1174                         if (current_token.size())
1175                                 tokens.push_back(current_token);
1176                         current_token.clear();
1177                 }
1178                 
1179                 if (!(iswhite || isquot))
1180                         current_token += c;
1181                 
1182                 if (isquot)
1183                         quotemode = !quotemode;
1184                 lastsplit = issplit;
1185                 lastalnum = isaln;
1186         }
1187         
1188 //      for (std::list<std::string>::const_iterator a(tokens.begin()); a != tokens.end(); ++a)
1189 //      {
1190 //              printf("%s\n", a->c_str());
1191 //      }
1192
1193         int sort = eDVBChannelQuery::tName;
1194                 /* check for "ORDER BY ..." */
1195
1196         std::list<std::string>::iterator it = tokens.begin();
1197         while (it != tokens.end())
1198         {
1199                 if (*it == "ORDER")
1200                 {
1201                         tokens.erase(it++);
1202                         if (it != tokens.end() && *it == "BY")
1203                         {
1204                                 tokens.erase(it++);
1205                                 sort = decodeType(*it);
1206                                 tokens.erase(it++);
1207                         } else
1208                                 sort = -1;
1209                 }
1210                 else if (*it == "FROM")
1211                 {
1212                         tokens.erase(it++);
1213                         if (it != tokens.end() && *it == "BOUQUET")
1214                         {
1215                                 tokens.erase(it++);
1216                                 bouquet_name = *it;
1217                                 tokens.erase(it++);
1218                         }
1219                         else if (it != tokens.end() && *it == "SATELLITES")
1220                                 tokens.erase(it++);
1221                         else if (it != tokens.end() && *it == "PROVIDERS")
1222                                 tokens.erase(it++);
1223                         else
1224                         {
1225                                 eDebug("FROM unknown %s", (*it).c_str());
1226                                 tokens.erase(it++);
1227                         }
1228                 }
1229                 else
1230                         ++it;
1231         }
1232
1233         if (sort == -1)
1234         {
1235                 eWarning("ORDER BY .. string invalid.");
1236                 res = 0;
1237                 return -1;
1238         }
1239         
1240 //      eDebug("sort by %d", sort);
1241         
1242                 /* now we recursivly parse that. */
1243         int r = parseExpression(res, tokens.begin(), tokens.end());
1244         
1245                 /* we have an empty (but valid!) expression */
1246         if (!r && !res)
1247         {
1248                 res = new eDVBChannelQuery();
1249                 res->m_inverse = 0;
1250                 res->m_type = eDVBChannelQuery::tAny;
1251         }
1252         
1253         if (res)
1254         {
1255                 res->m_sort = sort;
1256                 res->m_bouquet_name = bouquet_name;
1257         }
1258
1259 //      eDebug("return: %d", r);
1260         return r;
1261 }
1262
1263 DEFINE_REF(eDVBChannelQuery);