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