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