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