vdr  2.7.6
channels.c
Go to the documentation of this file.
1 /*
2  * channels.c: Channel handling
3  *
4  * See the main source file 'vdr.c' for copyright information and
5  * how to reach the author.
6  *
7  * $Id: channels.c 5.4 2025/03/02 11:03:35 kls Exp $
8  */
9 
10 #include "channels.h"
11 #include <ctype.h>
12 #include "device.h"
13 #include "dvbdevice.h"
14 #include "libsi/si.h"
15 
16 // IMPORTANT NOTE: in the 'sscanf()' calls there is a blank after the '%d'
17 // format characters in order to allow any number of blanks after a numeric
18 // value!
19 
20 // --- tChannelID ------------------------------------------------------------
21 
23 
25 {
26  char *sourcebuf = NULL;
27  int nid;
28  int tid;
29  int sid;
30  int rid = 0;
31  int fields = sscanf(s, "%m[^-]-%d-%d-%d-%d", &sourcebuf, &nid, &tid, &sid, &rid);
32  if (fields == 4 || fields == 5) {
33  int source = cSource::FromString(sourcebuf);
34  free(sourcebuf);
35  if (source >= 0)
36  return tChannelID(source, nid, tid, sid, rid);
37  }
38  return tChannelID::InvalidID;
39 }
40 
42 {
43  char buffer[256];
44  snprintf(buffer, sizeof(buffer), rid ? "%s-%d-%d-%d-%d" : "%s-%d-%d-%d", *cSource::ToString(source), nid, tid, sid, rid);
45  return buffer;
46 }
47 
49 {
50  while (tid > 100000)
51  tid -= 100000;
52  return *this;
53 }
54 
55 // --- cChannel --------------------------------------------------------------
56 
58 {
59  name = strdup("");
60  shortName = strdup("");
61  provider = strdup("");
62  portalName = strdup("");
63  memset(&__BeginData__, 0, (char *)&__EndData__ - (char *)&__BeginData__);
64  parameters = "";
66  seen = 0;
67  schedule = NULL;
68  linkChannels = NULL;
69  refChannel = NULL;
70 }
71 
73 {
74  name = NULL;
75  shortName = NULL;
76  provider = NULL;
77  portalName = NULL;
78  schedule = NULL;
79  linkChannels = NULL;
80  refChannel = NULL;
81  seen = 0;
82  *this = Channel;
83 }
84 
86 {
87  delete linkChannels; // any links from other channels pointing to this one have been deleted in cChannels::Del()
88  free(name);
89  free(shortName);
90  free(provider);
91  free(portalName);
92 }
93 
95 {
96  name = strcpyrealloc(name, Channel.name);
100  memcpy(&__BeginData__, &Channel.__BeginData__, (char *)&Channel.__EndData__ - (char *)&Channel.__BeginData__);
102  parameters = Channel.parameters;
103  return *this;
104 }
105 
107 {
109  nameSource = NULL;
110  shortNameSource = NULL;
111  return;
112  }
113 
116  else
118 
120 }
121 
122 const char *cChannel::Name(void) const
123 {
125  if (!isempty(nameSource))
126  return nameSource;
127  }
128  return name;
129 }
130 
131 const char *cChannel::ShortName(bool OrName) const
132 {
133  if (OrName && isempty(shortName))
134  return Name();
136  if (!isempty(shortNameSource))
137  return shortNameSource;
138  }
139  return shortName;
140 }
141 
142 int cChannel::Transponder(int Frequency, char Polarization)
143 {
144  // some satellites have transponders at the same frequency, just with different polarization:
145  switch (toupper(Polarization)) {
146  case 'H': Frequency += 100000; break;
147  case 'V': Frequency += 200000; break;
148  case 'L': Frequency += 300000; break;
149  case 'R': Frequency += 400000; break;
150  default: esyslog("ERROR: invalid value for Polarization '%c'", Polarization);
151  }
152  return Frequency;
153 }
154 
155 int cChannel::Transponder(void) const
156 {
157  if (!transponder) {
158  int tf = frequency;
159  while (tf > 20000)
160  tf /= 1000;
161  if (IsSat()) {
162  const char *p = strpbrk(parameters, "HVLRhvlr"); // lowercase for backwards compatibility
163  if (p)
164  tf = Transponder(tf, *p);
165  }
166  transponder = tf;
167  }
168  return transponder;
169 }
170 
171 int cChannel::Modification(int Mask) const
172 {
173  int Result = modification & Mask;
175  return Result;
176 }
177 
179 {
180  if (Channel) {
181  frequency = Channel->frequency;
182  transponder = Channel->transponder;
183  source = Channel->source;
184  srate = Channel->srate;
185  parameters = Channel->parameters;
186  }
187 }
188 
189 bool cChannel::SetTransponderData(int Source, int Frequency, int Srate, const char *Parameters, bool Quiet)
190 {
191  if (strchr(Parameters, ':')) {
192  esyslog("ERROR: parameter string '%s' contains ':'", Parameters);
193  return false;
194  }
195  // Workarounds for broadcaster stupidity:
196  // Some providers broadcast the transponder frequency of their channels with two different
197  // values (like 12551 and 12552), so we need to allow for a little tolerance here
198  if (abs(frequency - Frequency) <= 1)
200  // Sometimes the transponder frequency is set to 0, which is just wrong
201  if (Frequency == 0)
202  return false;
203  // Sometimes the symbol rate is off by one
204  if (abs(srate - Srate) <= 1)
205  Srate = srate;
206 
207  if (source != Source || frequency != Frequency || srate != Srate || strcmp(parameters, Parameters)) {
208  cString OldTransponderData = TransponderDataToString();
209  source = Source;
211  transponder = 0;
212  srate = Srate;
214  schedule = NULL;
216  if (Number() && !Quiet) {
217  dsyslog("changing transponder data of channel %d (%s) from %s to %s", Number(), name, *OldTransponderData, *TransponderDataToString());
219  }
220  return true;
221  }
222  return false;
223 }
224 
225 bool cChannel::SetSource(int Source)
226 {
227  if (source != Source) {
228  if (Number()) {
229  dsyslog("changing source of channel %d (%s) from %s to %s", Number(), name, *cSource::ToString(source), *cSource::ToString(Source));
231  }
232  source = Source;
233  return true;
234  }
235  return false;
236 }
237 
238 bool cChannel::SetId(cChannels *Channels, int Nid, int Tid, int Sid, int Rid)
239 {
240  if (nid != Nid || tid != Tid || sid != Sid || rid != Rid) {
241  if (Channels && Number()) {
242  dsyslog("changing id of channel %d (%s) from %d-%d-%d-%d to %d-%d-%d-%d", Number(), name, nid, tid, sid, rid, Nid, Tid, Sid, Rid);
244  Channels->UnhashChannel(this);
245  }
246  nid = Nid;
247  tid = Tid;
248  sid = Sid;
249  rid = Rid;
250  if (Channels)
251  Channels->HashChannel(this);
252  schedule = NULL;
253  return true;
254  }
255  return false;
256 }
257 
258 bool cChannel::SetLcn(int Lcn)
259 {
260  if (lcn != Lcn) {
261  if (Number())
262  dsyslog("changing lcn of channel %d (%s) from %d to %d\n", Number(), name, lcn, Lcn);
263  lcn = Lcn;
264  return true;
265  }
266  return false;
267 }
268 
269 bool cChannel::SetName(const char *Name, const char *ShortName, const char *Provider)
270 {
271  if (!isempty(Name)) {
272  bool nn = strcmp(name, Name) != 0;
273  bool ns = strcmp(shortName, ShortName) != 0;
274  bool np = strcmp(provider, Provider) != 0;
275  if (nn || ns || np) {
276  if (Number()) {
277  dsyslog("changing name of channel %d from '%s,%s;%s' to '%s,%s;%s'", Number(), name, shortName, provider, Name, ShortName, Provider);
279  }
280  if (nn)
282  if (ns)
284  if (nn || ns)
286  if (np)
288  return true;
289  }
290  }
291  return false;
292 }
293 
294 bool cChannel::SetPortalName(const char *PortalName)
295 {
296  if (!isempty(PortalName) && strcmp(portalName, PortalName) != 0) {
297  if (Number()) {
298  dsyslog("changing portal name of channel %d (%s) from '%s' to '%s'", Number(), name, portalName, PortalName);
300  }
302  return true;
303  }
304  return false;
305 }
306 
307 #define STRDIFF 0x01
308 #define VALDIFF 0x02
309 
310 static int IntArraysDiffer(const int *a, const int *b, const char na[][MAXLANGCODE2] = NULL, const char nb[][MAXLANGCODE2] = NULL)
311 {
312  int result = 0;
313  for (int i = 0; a[i] || b[i]; i++) {
314  if (!a[i] || !b[i]) {
315  result |= VALDIFF;
316  break;
317  }
318  if (na && nb && strcmp(na[i], nb[i]) != 0)
319  result |= STRDIFF;
320  if (a[i] != b[i])
321  result |= VALDIFF;
322  }
323  return result;
324 }
325 
326 static int IntArrayToString(char *s, const int *a, int Base = 10, const char n[][MAXLANGCODE2] = NULL, const int *t = NULL)
327 {
328  char *q = s;
329  int i = 0;
330  while (a[i] || i == 0) {
331  q += sprintf(q, Base == 16 ? "%s%X" : "%s%d", i ? "," : "", a[i]);
332  const char *Delim = "=";
333  if (a[i]) {
334  if (n && *n[i]) {
335  q += sprintf(q, "%s%s", Delim, n[i]);
336  Delim = "";
337  }
338  if (t && t[i])
339  q += sprintf(q, "%s@%d", Delim, t[i]);
340  }
341  if (!a[i])
342  break;
343  i++;
344  }
345  *q = 0;
346  return q - s;
347 }
348 
349 bool cChannel::SetPids(int Vpid, int Ppid, int Vtype, int *Apids, int *Atypes, char ALangs[][MAXLANGCODE2], int *Dpids, int *Dtypes, char DLangs[][MAXLANGCODE2], int *Spids, char SLangs[][MAXLANGCODE2], int Tpid)
350 {
351  int mod = CHANNELMOD_NONE;
352  if (vpid != Vpid || ppid != Ppid || vtype != Vtype)
353  mod |= CHANNELMOD_PIDS;
354  if (tpid != Tpid)
355  mod |= CHANNELMOD_AUX;
356  int m = IntArraysDiffer(apids, Apids, alangs, ALangs) | IntArraysDiffer(atypes, Atypes) | IntArraysDiffer(dpids, Dpids, dlangs, DLangs) | IntArraysDiffer(dtypes, Dtypes) | IntArraysDiffer(spids, Spids, slangs, SLangs);
357  if (m & STRDIFF)
358  mod |= CHANNELMOD_LANGS;
359  if (m & VALDIFF)
360  mod |= CHANNELMOD_PIDS;
361  if (mod) {
362  const int BufferSize = (MAXAPIDS + MAXDPIDS) * (5 + 1 + MAXLANGCODE2 + 5) + 10; // 5 digits plus delimiting ',' or ';' plus optional '=cod+cod@type', +10: paranoia
363  char OldApidsBuf[BufferSize];
364  char NewApidsBuf[BufferSize];
365  char *q = OldApidsBuf;
366  q += IntArrayToString(q, apids, 10, alangs, atypes);
367  if (dpids[0]) {
368  *q++ = ';';
369  q += IntArrayToString(q, dpids, 10, dlangs, dtypes);
370  }
371  *q = 0;
372  q = NewApidsBuf;
373  q += IntArrayToString(q, Apids, 10, ALangs, Atypes);
374  if (Dpids[0]) {
375  *q++ = ';';
376  q += IntArrayToString(q, Dpids, 10, DLangs, Dtypes);
377  }
378  *q = 0;
379  const int SBufferSize = MAXSPIDS * (5 + 1 + MAXLANGCODE2) + 10; // 5 digits plus delimiting ',' or ';' plus optional '=cod', +10: paranoia
380  char OldSpidsBuf[SBufferSize];
381  char NewSpidsBuf[SBufferSize];
382  q = OldSpidsBuf;
383  q += IntArrayToString(q, spids, 10, slangs);
384  *q = 0;
385  q = NewSpidsBuf;
386  q += IntArrayToString(q, Spids, 10, SLangs);
387  *q = 0;
388  if (Number())
389  dsyslog("changing pids of channel %d (%s) from %d+%d=%d:%s:%s:%d to %d+%d=%d:%s:%s:%d", Number(), name, vpid, ppid, vtype, OldApidsBuf, OldSpidsBuf, tpid, Vpid, Ppid, Vtype, NewApidsBuf, NewSpidsBuf, Tpid);
390  vpid = Vpid;
391  ppid = Ppid;
392  vtype = Vtype;
393  for (int i = 0; i < MAXAPIDS; i++) {
394  apids[i] = Apids[i];
395  atypes[i] = Atypes[i];
396  strn0cpy(alangs[i], ALangs[i], MAXLANGCODE2);
397  }
398  apids[MAXAPIDS] = 0;
399  for (int i = 0; i < MAXDPIDS; i++) {
400  dpids[i] = Dpids[i];
401  dtypes[i] = Dtypes[i];
402  strn0cpy(dlangs[i], DLangs[i], MAXLANGCODE2);
403  }
404  dpids[MAXDPIDS] = 0;
405  for (int i = 0; i < MAXSPIDS; i++) {
406  spids[i] = Spids[i];
407  strn0cpy(slangs[i], SLangs[i], MAXLANGCODE2);
408  }
409  spids[MAXSPIDS] = 0;
410  tpid = Tpid;
411  modification |= mod;
412  return true;
413  }
414  return false;
415 }
416 
417 bool cChannel::SetSubtitlingDescriptors(uchar *SubtitlingTypes, uint16_t *CompositionPageIds, uint16_t *AncillaryPageIds)
418 {
419  bool Modified = false;
420  if (SubtitlingTypes) {
421  for (int i = 0; i < MAXSPIDS; i++) {
422  Modified = subtitlingTypes[i] != SubtitlingTypes[i];
423  subtitlingTypes[i] = SubtitlingTypes[i];
424  }
425  }
426  if (CompositionPageIds) {
427  for (int i = 0; i < MAXSPIDS; i++) {
428  Modified = compositionPageIds[i] != CompositionPageIds[i];
429  compositionPageIds[i] = CompositionPageIds[i];
430  }
431  }
432  if (AncillaryPageIds) {
433  for (int i = 0; i < MAXSPIDS; i++) {
434  Modified = ancillaryPageIds[i] != AncillaryPageIds[i];
435  ancillaryPageIds[i] = AncillaryPageIds[i];
436  }
437  }
438  return Modified;
439 }
440 
442 {
443  seen = time(NULL);
444 }
445 
447 {
448  if (linkChannels) {
449  for (cLinkChannel *lc = linkChannels->First(); lc; lc = linkChannels->Next(lc)) {
450  if (lc->Channel() == LinkChannel) {
451  linkChannels->Del(lc);
452  break;
453  }
454  }
455  if (linkChannels->Count() == 0) {
456  delete linkChannels;
457  linkChannels = NULL;
458  }
459  }
460 }
461 
462 bool cChannel::SetCaIds(const int *CaIds)
463 {
464  if (caids[0] && caids[0] <= CA_USER_MAX)
465  return false; // special values will not be overwritten
466  if (IntArraysDiffer(caids, CaIds)) {
467  char OldCaIdsBuf[MAXCAIDS * 5 + 10]; // 5: 4 digits plus delimiting ',', 10: paranoia
468  char NewCaIdsBuf[MAXCAIDS * 5 + 10];
469  IntArrayToString(OldCaIdsBuf, caids, 16);
470  IntArrayToString(NewCaIdsBuf, CaIds, 16);
471  if (Number())
472  dsyslog("changing caids of channel %d (%s) from %s to %s", Number(), name, OldCaIdsBuf, NewCaIdsBuf);
473  for (int i = 0; i <= MAXCAIDS; i++) { // <= to copy the terminating 0
474  caids[i] = CaIds[i];
475  if (!CaIds[i])
476  break;
477  }
479  return true;
480  }
481  return false;
482 }
483 
485 {
486  if (Level > 0) {
488  if (Number() && Level > 1)
489  dsyslog("changing ca descriptors of channel %d (%s)", Number(), name);
490  return true;
491  }
492  return false;
493 }
494 
496 {
497  if (!linkChannels && !LinkChannels)
498  return false;
499  if (linkChannels && LinkChannels) {
500  cLinkChannel *lca = linkChannels->First();
501  cLinkChannel *lcb = LinkChannels->First();
502  while (lca && lcb) {
503  if (lca->Channel() != lcb->Channel()) {
504  lca = NULL;
505  break;
506  }
507  lca = linkChannels->Next(lca);
508  lcb = LinkChannels->Next(lcb);
509  }
510  if (!lca && !lcb) {
511  delete LinkChannels;
512  return false; // linkage has not changed
513  }
514  }
515  char buffer[((linkChannels ? linkChannels->Count() : 0) + (LinkChannels ? LinkChannels->Count() : 0)) * 6 + 256]; // 6: 5 digit channel number plus blank, 256: other texts (see below) plus reserve
516  char *q = buffer;
517  q += sprintf(q, "linking channel %d (%s) from", Number(), name);
518  if (linkChannels) {
519  for (cLinkChannel *lc = linkChannels->First(); lc; lc = linkChannels->Next(lc)) {
520  lc->Channel()->SetRefChannel(NULL);
521  q += sprintf(q, " %d", lc->Channel()->Number());
522  }
523  delete linkChannels;
524  }
525  else
526  q += sprintf(q, " none");
527  q += sprintf(q, " to");
529  if (linkChannels) {
530  for (cLinkChannel *lc = linkChannels->First(); lc; lc = linkChannels->Next(lc)) {
531  lc->Channel()->SetRefChannel(this);
532  q += sprintf(q, " %d", lc->Channel()->Number());
533  //dsyslog("link %4d -> %4d: %s", Number(), lc->Channel()->Number(), lc->Channel()->Name());
534  }
535  }
536  else
537  q += sprintf(q, " none");
538  if (Number())
539  dsyslog("%s", buffer);
540  return true;
541 }
542 
544 {
546 }
547 
549 {
550  if (cSource::IsTerr(source))
552  return cString::sprintf("%d:%s:%s:%d", frequency, *parameters, *cSource::ToString(source), srate);
553 }
554 
556 {
557  char FullName[strlen(Channel->name) + 1 + strlen(Channel->shortName) + 1 + strlen(Channel->provider) + 1 + 10]; // +10: paranoia
558  char *q = FullName;
559  q += sprintf(q, "%s", Channel->name);
560  if (!Channel->groupSep) {
561  if (!isempty(Channel->shortName))
562  q += sprintf(q, ",%s", Channel->shortName);
563  else if (strchr(Channel->name, ','))
564  q += sprintf(q, ",");
565  if (!isempty(Channel->provider))
566  q += sprintf(q, ";%s", Channel->provider);
567  }
568  *q = 0;
569  strreplace(FullName, ':', '|');
570  cString buffer;
571  if (Channel->groupSep) {
572  if (Channel->number)
573  buffer = cString::sprintf(":@%d %s", Channel->number, FullName);
574  else
575  buffer = cString::sprintf(":%s", FullName);
576  }
577  else {
578  char vpidbuf[32];
579  char *q = vpidbuf;
580  q += snprintf(q, sizeof(vpidbuf), "%d", Channel->vpid);
581  if (Channel->ppid && Channel->ppid != Channel->vpid)
582  q += snprintf(q, sizeof(vpidbuf) - (q - vpidbuf), "+%d", Channel->ppid);
583  if (Channel->vpid && Channel->vtype)
584  q += snprintf(q, sizeof(vpidbuf) - (q - vpidbuf), "=%d", Channel->vtype);
585  *q = 0;
586  const int ABufferSize = (MAXAPIDS + MAXDPIDS) * (5 + 1 + MAXLANGCODE2 + 5) + 10; // 5 digits plus delimiting ',' or ';' plus optional '=cod+cod@type', +10: paranoia
587  char apidbuf[ABufferSize];
588  q = apidbuf;
589  q += IntArrayToString(q, Channel->apids, 10, Channel->alangs, Channel->atypes);
590  if (Channel->dpids[0]) {
591  *q++ = ';';
592  q += IntArrayToString(q, Channel->dpids, 10, Channel->dlangs, Channel->dtypes);
593  }
594  *q = 0;
595  const int TBufferSize = MAXSPIDS * (5 + 1 + MAXLANGCODE2) + 10; // 5 digits plus delimiting ',' or ';' plus optional '=cod+cod', +10: paranoia and tpid
596  char tpidbuf[TBufferSize];
597  q = tpidbuf;
598  q += snprintf(q, sizeof(tpidbuf), "%d", Channel->tpid);
599  if (Channel->spids[0]) {
600  *q++ = ';';
601  q += IntArrayToString(q, Channel->spids, 10, Channel->slangs);
602  }
603  char caidbuf[MAXCAIDS * 5 + 10]; // 5: 4 digits plus delimiting ',', 10: paranoia
604  q = caidbuf;
605  q += IntArrayToString(q, Channel->caids, 16);
606  *q = 0;
607  buffer = cString::sprintf("%s:%d:%s:%s:%d:%s:%s:%s:%s:%d:%d:%d:%d", FullName, Channel->frequency, *Channel->parameters, *cSource::ToString(Channel->source), Channel->srate, vpidbuf, apidbuf, tpidbuf, caidbuf, Channel->sid, Channel->nid, Channel->tid, Channel->rid);
608  }
609  return buffer;
610 }
611 
613 {
614  return ToText(this);
615 }
616 
617 bool cChannel::Parse(const char *s)
618 {
619  bool ok = true;
620  if (*s == ':') {
621  groupSep = true;
622  if (*++s == '@' && *++s) {
623  char *p = NULL;
624  errno = 0;
625  int n = strtol(s, &p, 10);
626  if (!errno && p != s && n > 0) {
627  number = n;
628  s = p;
629  }
630  }
632  strreplace(name, '|', ':');
633  }
634  else {
635  groupSep = false;
636  char *namebuf = NULL;
637  char *sourcebuf = NULL;
638  char *parambuf = NULL;
639  char *vpidbuf = NULL;
640  char *apidbuf = NULL;
641  char *tpidbuf = NULL;
642  char *caidbuf = NULL;
643  int fields = sscanf(s, "%m[^:]:%d :%m[^:]:%m[^:] :%d :%m[^:]:%m[^:]:%m[^:]:%m[^:]:%d :%d :%d :%d ", &namebuf, &frequency, &parambuf, &sourcebuf, &srate, &vpidbuf, &apidbuf, &tpidbuf, &caidbuf, &sid, &nid, &tid, &rid);
644  if (fields >= 9) {
645  if (fields == 9) {
646  // allow reading of old format
647  sid = atoi(caidbuf);
648  delete caidbuf;
649  caidbuf = NULL;
650  if (sscanf(tpidbuf, "%d", &tpid) != 1)
651  return false;
652  caids[0] = tpid;
653  caids[1] = 0;
654  tpid = 0;
655  }
656  vpid = ppid = 0;
657  vtype = 0;
658  apids[0] = 0;
659  atypes[0] = 0;
660  dpids[0] = 0;
661  dtypes[0] = 0;
662  spids[0] = 0;
663  ok = false;
664  if (parambuf && sourcebuf && vpidbuf && apidbuf) {
665  parameters = parambuf;
666  ok = (source = cSource::FromString(sourcebuf)) >= 0;
667  transponder = 0;
668 
669  char *p;
670  if ((p = strchr(vpidbuf, '=')) != NULL) {
671  *p++ = 0;
672  if (sscanf(p, "%d", &vtype) != 1)
673  return false;
674  }
675  if ((p = strchr(vpidbuf, '+')) != NULL) {
676  *p++ = 0;
677  if (sscanf(p, "%d", &ppid) != 1)
678  return false;
679  }
680  if (sscanf(vpidbuf, "%d", &vpid) != 1)
681  return false;
682  if (!ppid)
683  ppid = vpid;
684  if (vpid && !vtype)
685  vtype = 2; // default is MPEG-2
686 
687  char *dpidbuf = strchr(apidbuf, ';');
688  if (dpidbuf)
689  *dpidbuf++ = 0;
690  p = apidbuf;
691  char *q;
692  int NumApids = 0;
693  char *strtok_next;
694  while ((q = strtok_r(p, ",", &strtok_next)) != NULL) {
695  if (NumApids < MAXAPIDS) {
696  atypes[NumApids] = 4; // backwards compatibility
697  char *l = strchr(q, '=');
698  if (l) {
699  *l++ = 0;
700  char *t = strchr(l, '@');
701  if (t) {
702  *t++ = 0;
703  atypes[NumApids] = strtol(t, NULL, 10);
704  }
705  strn0cpy(alangs[NumApids], l, MAXLANGCODE2);
706  }
707  else
708  *alangs[NumApids] = 0;
709  if ((apids[NumApids] = strtol(q, NULL, 10)) != 0)
710  NumApids++;
711  }
712  else
713  esyslog("ERROR: too many APIDs!"); // no need to set ok to 'false'
714  p = NULL;
715  }
716  apids[NumApids] = 0;
717  atypes[NumApids] = 0;
718  if (dpidbuf) {
719  char *p = dpidbuf;
720  char *q;
721  int NumDpids = 0;
722  char *strtok_next;
723  while ((q = strtok_r(p, ",", &strtok_next)) != NULL) {
724  if (NumDpids < MAXDPIDS) {
725  dtypes[NumDpids] = SI::AC3DescriptorTag; // backwards compatibility
726  char *l = strchr(q, '=');
727  if (l) {
728  *l++ = 0;
729  char *t = strchr(l, '@');
730  if (t) {
731  *t++ = 0;
732  dtypes[NumDpids] = strtol(t, NULL, 10);
733  }
734  strn0cpy(dlangs[NumDpids], l, MAXLANGCODE2);
735  }
736  else
737  *dlangs[NumDpids] = 0;
738  if ((dpids[NumDpids] = strtol(q, NULL, 10)) != 0)
739  NumDpids++;
740  }
741  else
742  esyslog("ERROR: too many DPIDs!"); // no need to set ok to 'false'
743  p = NULL;
744  }
745  dpids[NumDpids] = 0;
746  dtypes[NumDpids] = 0;
747  }
748  int NumSpids = 0;
749  if ((p = strchr(tpidbuf, ';')) != NULL) {
750  *p++ = 0;
751  char *q;
752  char *strtok_next;
753  while ((q = strtok_r(p, ",", &strtok_next)) != NULL) {
754  if (NumSpids < MAXSPIDS) {
755  char *l = strchr(q, '=');
756  if (l) {
757  *l++ = 0;
758  strn0cpy(slangs[NumSpids], l, MAXLANGCODE2);
759  }
760  else
761  *slangs[NumSpids] = 0;
762  spids[NumSpids++] = strtol(q, NULL, 10);
763  }
764  else
765  esyslog("ERROR: too many SPIDs!"); // no need to set ok to 'false'
766  p = NULL;
767  }
768  spids[NumSpids] = 0;
769  }
770  if (sscanf(tpidbuf, "%d", &tpid) != 1)
771  return false;
772  if (caidbuf) {
773  char *p = caidbuf;
774  char *q;
775  int NumCaIds = 0;
776  char *strtok_next;
777  while ((q = strtok_r(p, ",", &strtok_next)) != NULL) {
778  if (NumCaIds < MAXCAIDS) {
779  caids[NumCaIds++] = strtol(q, NULL, 16) & 0xFFFF;
780  if (NumCaIds == 1 && caids[0] <= CA_USER_MAX)
781  break;
782  }
783  else
784  esyslog("ERROR: too many CA ids!"); // no need to set ok to 'false'
785  p = NULL;
786  }
787  caids[NumCaIds] = 0;
788  }
789  }
790  strreplace(namebuf, '|', ':');
791 
792  char *p = strchr(namebuf, ';');
793  if (p) {
794  *p++ = 0;
796  }
797  p = strrchr(namebuf, ','); // long name might contain a ',', so search for the rightmost one
798  if (p) {
799  *p++ = 0;
801  }
802  name = strcpyrealloc(name, namebuf);
803 
804  free(parambuf);
805  free(sourcebuf);
806  free(vpidbuf);
807  free(apidbuf);
808  free(tpidbuf);
809  free(caidbuf);
810  free(namebuf);
812  if (!GetChannelID().Valid()) {
813  esyslog("ERROR: channel data results in invalid ID!");
814  return false;
815  }
816  }
817  else
818  return false;
819  }
820  return ok;
821 }
822 
823 bool cChannel::Save(FILE *f)
824 {
825  return fprintf(f, "%s\n", *ToText()) > 0;
826 }
827 
828 // --- cChannelSorter --------------------------------------------------------
829 
830 class cChannelSorter : public cListObject {
831 public:
835  channel = Channel;
837  }
838  virtual int Compare(const cListObject &ListObject) const override {
839  cChannelSorter *cs = (cChannelSorter *)&ListObject;
840  return memcmp(&channelID, &cs->channelID, sizeof(channelID));
841  }
842  };
843 
844 // --- cChannels -------------------------------------------------------------
845 
847 int cChannels::maxNumber = 0;
850 
852 :cConfig<cChannel>("2 Channels")
853 {
854  modifiedByUser = 0;
855 }
856 
857 const cChannels *cChannels::GetChannelsRead(cStateKey &StateKey, int TimeoutMs)
858 {
859  return channels.Lock(StateKey, false, TimeoutMs) ? &channels : NULL;
860 }
861 
863 {
864  return channels.Lock(StateKey, true, TimeoutMs) ? &channels : NULL;
865 }
866 
868 {
869  cList<cChannelSorter> ChannelSorter;
870  for (cChannel *Channel = First(); Channel; Channel = Next(Channel)) {
871  if (!Channel->GroupSep())
872  ChannelSorter.Add(new cChannelSorter(Channel));
873  }
874  ChannelSorter.Sort();
875  cChannelSorter *cs = ChannelSorter.First();
876  while (cs) {
877  cChannelSorter *Next = ChannelSorter.Next(cs);
878  if (Next && cs->channelID == Next->channelID) {
879  dsyslog("deleting duplicate channel %s", *Next->channel->ToText());
880  Del(Next->channel);
881  }
882  cs = Next;
883  }
884 }
885 
886 bool cChannels::Load(const char *FileName, bool AllowComments, bool MustExist)
887 {
889  if (channels.cConfig<cChannel>::Load(FileName, AllowComments, MustExist)) {
891  channels.ReNumber();
892  return true;
893  }
894  return false;
895 }
896 
898 {
899  channelsHashSid.Add(Channel, Channel->Sid());
900 }
901 
903 {
904  channelsHashSid.Del(Channel, Channel->Sid());
905 }
906 
907 int cChannels::GetNextGroup(int Idx) const
908 {
909  const cChannel *Channel = Get(++Idx);
910  while (Channel && !(Channel->GroupSep() && *Channel->Name()))
911  Channel = Get(++Idx);
912  return Channel ? Idx : -1;
913 }
914 
915 int cChannels::GetPrevGroup(int Idx) const
916 {
917  const cChannel *Channel = Get(--Idx);
918  while (Channel && !(Channel->GroupSep() && *Channel->Name()))
919  Channel = Get(--Idx);
920  return Channel ? Idx : -1;
921 }
922 
923 int cChannels::GetNextNormal(int Idx) const
924 {
925  const cChannel *Channel = Get(++Idx);
926  while (Channel && Channel->GroupSep())
927  Channel = Get(++Idx);
928  return Channel ? Idx : -1;
929 }
930 
931 int cChannels::GetPrevNormal(int Idx) const
932 {
933  const cChannel *Channel = Get(--Idx);
934  while (Channel && Channel->GroupSep())
935  Channel = Get(--Idx);
936  return Channel ? Idx : -1;
937 }
938 
940 {
942  maxNumber = 0;
943  int Number = 1;
945  cVector<int> FoundLcn(Count());
946  int Overflow = LCN_OVERFLOW_OFFSET;
947  for (cChannel *Channel = First(); Channel; Channel = Next(Channel)) {
948  if (!Channel->GroupSep()) {
949  cDvbTransponderParameters dtp(Channel->Parameters());
950  HashChannel(Channel);
951  Number = dtp.Lcn();
952  if (Number > 0) {
953  bool Clash = false;
954  for (int i = 0; i < FoundLcn.Size(); ++i) {
955  if (FoundLcn[i] == Number) {
956  Number = Overflow++;
957  Clash = true;
958  break;
959  }
960  }
961  if (!Clash)
962  FoundLcn.Append(Number);
963  if (Number > maxNumber)
964  maxNumber = Number;
965  Channel->SetNumber(Number);
966  }
967  else {
968  maxNumber = Overflow;
969  Channel->SetNumber(Overflow++);
970  }
971  }
972  }
973  }
974  else {
975  for (cChannel *channel = First(); channel; channel = Next(channel)) {
976  if (channel->GroupSep()) {
977  if (channel->Number() > Number)
978  Number = channel->Number();
979  }
980  else {
981  HashChannel(channel);
982  maxNumber = Number;
983  channel->SetNumber(Number++);
984  }
985  }
986  }
987 }
988 
990 {
991  int Number = From->Number();
992  if (Number < To->Number()) {
993  for (cChannel *Channel = Next(From); Channel; Channel = Next(Channel)) {
994  if (Channel == To)
995  break;
996  if (Channel->GroupSep()) {
997  if (Channel->Number() > Number)
998  Number = Channel->Number();
999  }
1000  else
1001  Number++;
1002  }
1003  return Number == To->Number();
1004  }
1005  return false;
1006 }
1007 
1008 void cChannels::Del(cChannel *Channel)
1009 {
1010  UnhashChannel(Channel);
1011  for (cChannel *ch = First(); ch; ch = Next(ch))
1012  ch->DelLinkChannel(Channel);
1013  cList<cChannel>::Del(Channel);
1014 }
1015 
1016 const cChannel *cChannels::GetByNumber(int Number, int SkipGap) const
1017 {
1018  const cChannel *Previous = NULL;
1019  for (const cChannel *Channel = First(); Channel; Channel = Next(Channel)) {
1020  if (!Channel->GroupSep()) {
1021  if (Channel->Number() == Number)
1022  return Channel;
1023  else if (SkipGap && Channel->Number() > Number)
1024  return SkipGap > 0 ? Channel : Previous;
1025  Previous = Channel;
1026  }
1027  }
1028  return NULL;
1029 }
1030 
1031 const cChannel *cChannels::GetByServiceID(int Source, int Transponder, unsigned short ServiceID) const
1032 {
1033  cList<cHashObject> *list = channelsHashSid.GetList(ServiceID);
1034  if (list) {
1035  for (cHashObject *hobj = list->First(); hobj; hobj = list->Next(hobj)) {
1036  cChannel *Channel = (cChannel *)hobj->Object();
1037  if (Channel->Sid() == ServiceID && Channel->Source() == Source && ISTRANSPONDER(Channel->Transponder(), Transponder))
1038  return Channel;
1039  }
1040  }
1041  return NULL;
1042 }
1043 
1044 const cChannel *cChannels::GetByChannelID(tChannelID ChannelID, bool TryWithoutRid, bool TryWithoutPolarization) const
1045 {
1046  int sid = ChannelID.Sid();
1048  if (list) {
1049  for (cHashObject *hobj = list->First(); hobj; hobj = list->Next(hobj)) {
1050  cChannel *Channel = (cChannel *)hobj->Object();
1051  if (Channel->Sid() == sid && Channel->GetChannelID() == ChannelID)
1052  return Channel;
1053  }
1054  if (TryWithoutRid) {
1055  ChannelID.ClrRid();
1056  for (cHashObject *hobj = list->First(); hobj; hobj = list->Next(hobj)) {
1057  cChannel *Channel = (cChannel *)hobj->Object();
1058  if (Channel->Sid() == sid && Channel->GetChannelID().ClrRid() == ChannelID)
1059  return Channel;
1060  }
1061  }
1062  if (TryWithoutPolarization) {
1063  ChannelID.ClrPolarization();
1064  for (cHashObject *hobj = list->First(); hobj; hobj = list->Next(hobj)) {
1065  cChannel *Channel = (cChannel *)hobj->Object();
1066  if (Channel->Sid() == sid && Channel->GetChannelID().ClrPolarization() == ChannelID)
1067  return Channel;
1068  }
1069  }
1070  }
1071  return NULL;
1072 }
1073 
1075 {
1076  int source = ChannelID.Source();
1077  int nid = ChannelID.Nid();
1078  int tid = ChannelID.Tid();
1079  for (const cChannel *Channel = First(); Channel; Channel = Next(Channel)) {
1080  if (Channel->Tid() == tid && Channel->Nid() == nid && Channel->Source() == source)
1081  return Channel;
1082  }
1083  return NULL;
1084 }
1085 
1086 bool cChannels::HasUniqueChannelID(const cChannel *NewChannel, const cChannel *OldChannel) const
1087 {
1088  tChannelID NewChannelID = NewChannel->GetChannelID();
1089  for (const cChannel *Channel = First(); Channel; Channel = Next(Channel)) {
1090  if (!Channel->GroupSep() && Channel != OldChannel && Channel->GetChannelID() == NewChannelID)
1091  return false;
1092  }
1093  return true;
1094 }
1095 
1096 bool cChannels::SwitchTo(int Number) const
1097 {
1098  const cChannel *Channel = GetByNumber(Number);
1099  return Channel && cDevice::PrimaryDevice()->SwitchChannel(Channel, true);
1100 }
1101 
1103 {
1104  if (!maxChannelNameLength) {
1106  for (const cChannel *Channel = Channels->First(); Channel; Channel = Channels->Next(Channel)) {
1107  if (!Channel->GroupSep())
1109  }
1110  }
1111  return maxChannelNameLength;
1112 }
1113 
1115 {
1118  for (const cChannel *Channel = Channels->First(); Channel; Channel = Channels->Next(Channel)) {
1119  if (!Channel->GroupSep())
1120  maxShortChannelNameLength = max(Utf8StrLen(Channel->ShortName(true)), maxShortChannelNameLength);
1121  }
1122  }
1124 }
1125 
1127 {
1128  modifiedByUser++;
1130 }
1131 
1132 bool cChannels::ModifiedByUser(int &State) const
1133 {
1134  int Result = State != modifiedByUser;
1135  State = modifiedByUser;
1136  return Result;
1137 }
1138 
1139 cChannel *cChannels::NewChannel(const cChannel *Transponder, const char *Name, const char *ShortName, const char *Provider, int Nid, int Tid, int Sid, int Rid)
1140 {
1141  if (Transponder) {
1142  dsyslog("creating new channel '%s,%s;%s' on %s transponder %d with id %d-%d-%d-%d", Name, ShortName, Provider, *cSource::ToString(Transponder->Source()), Transponder->Transponder(), Nid, Tid, Sid, Rid);
1143  cChannel *NewChannel = new cChannel;
1144  NewChannel->CopyTransponderData(Transponder);
1145  NewChannel->SetId(this, Nid, Tid, Sid, Rid);
1146  NewChannel->SetName(Name, ShortName, Provider);
1147  NewChannel->SetSeen();
1148  Add(NewChannel);
1149  ReNumber();
1150  return NewChannel;
1151  }
1152  return NULL;
1153 }
1154 
1155 #define CHANNELMARKOBSOLETE "OBSOLETE"
1156 #define CHANNELTIMEOBSOLETE 3600 // seconds to wait before declaring a channel obsolete (in case it has actually been seen before)
1157 
1158 bool cChannels::MarkObsoleteChannels(int Source, int Nid, int Tid)
1159 {
1160  bool ChannelsModified = false;
1161  for (cChannel *Channel = First(); Channel; Channel = Next(Channel)) {
1162  if (time(NULL) - Channel->Seen() > CHANNELTIMEOBSOLETE && Channel->Source() == Source && Channel->Nid() == Nid && Channel->Tid() == Tid && Channel->Rid() == 0) {
1163  int OldShowChannelNamesWithSource = Setup.ShowChannelNamesWithSource;
1165  if (!endswith(Channel->Name(), CHANNELMARKOBSOLETE))
1166  ChannelsModified |= Channel->SetName(cString::sprintf("%s %s", Channel->Name(), CHANNELMARKOBSOLETE), Channel->ShortName(), cString::sprintf("%s %s", CHANNELMARKOBSOLETE, Channel->Provider()));
1167  Setup.ShowChannelNamesWithSource = OldShowChannelNamesWithSource;
1168  }
1169  }
1170  return ChannelsModified;
1171 }
1172 
1173 cString ChannelString(const cChannel *Channel, int Number)
1174 {
1175  char buffer[256];
1176  if (Channel) {
1177  if (Channel->GroupSep())
1178  snprintf(buffer, sizeof(buffer), "%s", Channel->Name());
1179  else
1180  snprintf(buffer, sizeof(buffer), "%d%s %s", Channel->Number(), Number ? "-" : "", Channel->Name());
1181  }
1182  else if (Number)
1183  snprintf(buffer, sizeof(buffer), "%d-", Number);
1184  else
1185  snprintf(buffer, sizeof(buffer), "%s", tr("*** Invalid Channel ***"));
1186  return buffer;
1187 }
1188 
1189 // --- cChannel cont. --------------------------------------------------------
1190 
1192 {
1193  bool ChannelsModified = false;
1194  if (time(NULL) - Seen() <= CHANNELTIMEOBSOLETE && endswith(name, CHANNELMARKOBSOLETE)) {
1195  int mlen = strlen(CHANNELMARKOBSOLETE);
1196  int e = strlen(name) - mlen - 1;
1197  name[e] = '\0';
1198  cString clrname = cString::sprintf("%s", name);
1199  name[e] = ' ';
1200 
1201  int OldShowChannelNamesWithSource = Setup.ShowChannelNamesWithSource;
1203  ChannelsModified |= SetName(clrname, shortName, provider + mlen + 1);
1204  Setup.ShowChannelNamesWithSource = OldShowChannelNamesWithSource;
1205  }
1206  return ChannelsModified;
1207 }
#define VALDIFF
Definition: channels.c:308
#define CHANNELMARKOBSOLETE
Definition: channels.c:1155
static int IntArrayToString(char *s, const int *a, int Base=10, const char n[][MAXLANGCODE2]=NULL, const int *t=NULL)
Definition: channels.c:326
#define STRDIFF
Definition: channels.c:307
#define CHANNELTIMEOBSOLETE
Definition: channels.c:1156
static int IntArraysDiffer(const int *a, const int *b, const char na[][MAXLANGCODE2]=NULL, const char nb[][MAXLANGCODE2]=NULL)
Definition: channels.c:310
cString ChannelString(const cChannel *Channel, int Number)
Definition: channels.c:1173
#define LCN_OVERFLOW_OFFSET
Definition: channels.h:47
#define MAXLANGCODE2
Definition: channels.h:37
#define MAXDPIDS
Definition: channels.h:32
#define CHANNELMOD_LANGS
Definition: channels.h:28
#define CHANNELMOD_NAME
Definition: channels.h:22
#define CHANNELMOD_CA
Definition: channels.h:26
#define CHANNELMOD_NONE
Definition: channels.h:20
#define CHANNELMOD_AUX
Definition: channels.h:25
#define MAXAPIDS
Definition: channels.h:31
#define CHANNELMOD_ID
Definition: channels.h:24
#define MAXSPIDS
Definition: channels.h:33
#define CHANNELMOD_TRANSP
Definition: channels.h:27
#define CHANNELMOD_PIDS
Definition: channels.h:23
#define LOCK_CHANNELS_READ
Definition: channels.h:273
#define MAXCAIDS
Definition: channels.h:34
#define ISTRANSPONDER(f1, f2)
Definition: channels.h:18
#define CA_USER_MAX
Definition: channels.h:43
#define LOCK_CHANNELS_WRITE
Definition: channels.h:274
cChannelSorter(cChannel *Channel)
Definition: channels.c:834
virtual int Compare(const cListObject &ListObject) const override
Must return 0 if this object is equal to ListObject, a positive value if it is "greater",...
Definition: channels.c:838
cChannel * channel
Definition: channels.c:832
tChannelID channelID
Definition: channels.c:833
int ppid
Definition: channels.h:106
time_t Seen(void) const
Definition: channels.h:196
int transponder
Definition: channels.h:102
bool Parse(const char *s)
Definition: channels.c:617
int tpid
Definition: channels.h:119
int source
Definition: channels.h:103
char * shortName
Definition: channels.h:97
int number
Definition: channels.h:126
int vpid
Definition: channels.h:105
int frequency
Definition: channels.h:101
const cChannel * RefChannel(void) const
Definition: channels.h:188
const int * Dpids(void) const
Definition: channels.h:160
int rid
Definition: channels.h:124
int Nid(void) const
Definition: channels.h:176
int Lcn(void) const
Definition: channels.h:180
static cString ToText(const cChannel *Channel)
Definition: channels.c:555
int Tpid(void) const
Definition: channels.h:173
int caids[MAXCAIDS+1]
Definition: channels.h:120
int nid
Definition: channels.h:121
cString parameters
Definition: channels.h:131
int Vpid(void) const
Definition: channels.h:156
cChannel * refChannel
Definition: channels.h:136
cString TransponderDataToString(void) const
Definition: channels.c:548
bool SetCaIds(const int *CaIds)
Definition: channels.c:462
cString nameSource
Definition: channels.h:129
bool SetName(const char *Name, const char *ShortName, const char *Provider)
Definition: channels.c:269
cString ToText(void) const
Definition: channels.c:612
int __BeginData__
Definition: channels.h:100
int Tid(void) const
Definition: channels.h:177
bool SetPortalName(const char *PortalName)
Definition: channels.c:294
bool SetLinkChannels(cLinkChannels *LinkChannels)
Definition: channels.c:495
int Source(void) const
Definition: channels.h:154
int Number(void) const
Definition: channels.h:181
const char * Name(void) const
Definition: channels.c:122
char * name
Definition: channels.h:96
int Vtype(void) const
Definition: channels.h:158
int srate
Definition: channels.h:104
tChannelID GetChannelID(void) const
Definition: channels.h:194
int Rid(void) const
Definition: channels.h:179
bool SetPids(int Vpid, int Ppid, int Vtype, int *Apids, int *Atypes, char ALangs[][MAXLANGCODE2], int *Dpids, int *Dtypes, char DLangs[][MAXLANGCODE2], int *Spids, char SLangs[][MAXLANGCODE2], int Tpid)
Definition: channels.c:349
int sid
Definition: channels.h:123
int lcn
Definition: channels.h:125
~cChannel()
Definition: channels.c:85
const cSchedule * schedule
Definition: channels.h:134
char alangs[MAXAPIDS][MAXLANGCODE2]
Definition: channels.h:110
char dlangs[MAXDPIDS][MAXLANGCODE2]
Definition: channels.h:113
bool GroupSep(void) const
Definition: channels.h:183
int Ppid(void) const
Definition: channels.h:157
bool SetLcn(int Lcn)
Definition: channels.c:258
void CopyTransponderData(const cChannel *Channel)
Definition: channels.c:178
time_t seen
Definition: channels.h:133
int dpids[MAXDPIDS+1]
Definition: channels.h:111
int Frequency(void) const
Returns the actual frequency, as given in 'channels.conf'.
Definition: channels.h:151
bool IsSat(void) const
Definition: channels.h:191
void SetRefChannel(cChannel *RefChannel)
Definition: channels.c:543
bool ClearObsoleteChannel(void)
Definition: channels.c:1191
const char * ShortName(bool OrName=false) const
Definition: channels.c:131
bool SetTransponderData(int Source, int Frequency, int Srate, const char *Parameters, bool Quiet=false)
Definition: channels.c:189
int tid
Definition: channels.h:122
bool Save(FILE *f)
Definition: channels.c:823
char slangs[MAXSPIDS][MAXLANGCODE2]
Definition: channels.h:115
int spids[MAXSPIDS+1]
Definition: channels.h:114
cString shortNameSource
Definition: channels.h:130
int dtypes[MAXDPIDS+1]
Definition: channels.h:112
uchar subtitlingTypes[MAXSPIDS]
Definition: channels.h:116
int atypes[MAXAPIDS+1]
Definition: channels.h:109
int apids[MAXAPIDS+1]
Definition: channels.h:108
const char * Parameters(void) const
Definition: channels.h:185
bool SetSource(int Source)
Definition: channels.c:225
void SetSeen(void)
Definition: channels.c:441
const int * Spids(void) const
Definition: channels.h:161
bool SetId(cChannels *Channels, int Nid, int Tid, int Sid, int Rid=0)
Definition: channels.c:238
int Modification(int Mask=CHANNELMOD_ALL) const
Definition: channels.c:171
bool SetCaDescriptors(int Level)
Definition: channels.c:484
cLinkChannels * linkChannels
Definition: channels.h:135
int Transponder(void) const
Returns the transponder frequency in MHz, plus the polarization in case of sat.
Definition: channels.c:155
uint16_t ancillaryPageIds[MAXSPIDS]
Definition: channels.h:118
int __EndData__
Definition: channels.h:128
int Srate(void) const
Definition: channels.h:155
int Sid(void) const
Definition: channels.h:178
const int * Apids(void) const
Definition: channels.h:159
void DelLinkChannel(cChannel *LinkChannel)
Definition: channels.c:446
bool groupSep
Definition: channels.h:127
char * portalName
Definition: channels.h:99
const cLinkChannels * LinkChannels(void) const
Definition: channels.h:187
bool SetSubtitlingDescriptors(uchar *SubtitlingTypes, uint16_t *CompositionPageIds, uint16_t *AncillaryPageIds)
Definition: channels.c:417
const char * PortalName(void) const
Definition: channels.h:150
int vtype
Definition: channels.h:107
int modification
Definition: channels.h:132
void UpdateNameSource(void)
Definition: channels.c:106
const char * Provider(void) const
Definition: channels.h:149
cChannel(void)
Definition: channels.c:57
uint16_t compositionPageIds[MAXSPIDS]
Definition: channels.h:117
char * provider
Definition: channels.h:98
cChannel & operator=(const cChannel &Channel)
Definition: channels.c:94
static cChannels * GetChannelsWrite(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of channels for write access.
Definition: channels.c:862
void UnhashChannel(cChannel *Channel)
Definition: channels.c:902
static int MaxChannelNameLength(void)
Definition: channels.c:1102
int GetNextGroup(int Idx) const
Get next channel group.
Definition: channels.c:907
bool HasUniqueChannelID(const cChannel *NewChannel, const cChannel *OldChannel=NULL) const
Definition: channels.c:1086
cChannels(void)
Definition: channels.c:851
bool MoveNeedsDecrement(cChannel *From, cChannel *To)
Definition: channels.c:989
int GetPrevNormal(int Idx) const
Get previous normal channel (not group)
Definition: channels.c:931
static int maxChannelNameLength
Definition: channels.h:219
const cChannel * GetByServiceID(int Source, int Transponder, unsigned short ServiceID) const
Definition: channels.c:1031
bool ModifiedByUser(int &State) const
Returns true if the channels have been modified by the user since the last call to this function with...
Definition: channels.c:1132
static int MaxShortChannelNameLength(void)
Definition: channels.c:1114
static int maxNumber
Definition: channels.h:218
static int maxShortChannelNameLength
Definition: channels.h:220
void HashChannel(cChannel *Channel)
Definition: channels.c:897
static const cChannels * GetChannelsRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of channels for read access.
Definition: channels.c:857
cHash< cChannel > channelsHashSid
Definition: channels.h:222
void ReNumber(void)
Recalculate 'number' based on channel type.
Definition: channels.c:939
const cChannel * GetByNumber(int Number, int SkipGap=0) const
Definition: channels.c:1016
void SetModifiedByUser(void)
Definition: channels.c:1126
static cChannels channels
Definition: channels.h:217
cChannel * NewChannel(const cChannel *Transponder, const char *Name, const char *ShortName, const char *Provider, int Nid, int Tid, int Sid, int Rid=0)
Definition: channels.c:1139
const cChannel * GetByTransponderID(tChannelID ChannelID) const
Definition: channels.c:1074
bool MarkObsoleteChannels(int Source, int Nid, int Tid)
Definition: channels.c:1158
const cChannel * GetByChannelID(tChannelID ChannelID, bool TryWithoutRid=false, bool TryWithoutPolarization=false) const
Definition: channels.c:1044
bool SwitchTo(int Number) const
Definition: channels.c:1096
void DeleteDuplicateChannels(void)
Definition: channels.c:867
int GetPrevGroup(int Idx) const
Get previous channel group.
Definition: channels.c:915
static bool Load(const char *FileName, bool AllowComments=false, bool MustExist=false)
Definition: channels.c:886
void Del(cChannel *Channel)
Delete the given Channel from the list.
Definition: channels.c:1008
int GetNextNormal(int Idx) const
Get next normal channel (not group)
Definition: channels.c:923
int modifiedByUser
Definition: channels.h:221
const char * FileName(void)
Definition: config.h:134
bool SwitchChannel(const cChannel *Channel, bool LiveView)
Switches the device to the given Channel, initiating transfer mode if necessary.
Definition: device.c:825
static cDevice * PrimaryDevice(void)
Returns the primary device.
Definition: device.h:148
int Lcn(void) const
Definition: dvbdevice.h:143
void Del(cListObject *Object, unsigned int Id)
Definition: tools.c:2384
cList< cHashObject > * GetList(unsigned int Id) const
Definition: tools.c:2424
void Clear(void)
Definition: tools.c:2397
void Add(cListObject *Object, unsigned int Id)
Definition: tools.c:2376
cChannel * Channel(void)
Definition: channels.h:80
void Del(cListObject *Object, bool DeleteObject=true)
Definition: tools.c:2209
bool Lock(cStateKey &StateKey, bool Write=false, int TimeoutMs=0) const
Tries to get a lock on this list and returns true if successful.
Definition: tools.c:2168
int Count(void) const
Definition: tools.h:627
void Add(cListObject *Object, cListObject *After=NULL)
Definition: tools.c:2177
void Sort(void)
Definition: tools.c:2301
cListObject * Next(void) const
Definition: tools.h:547
Definition: tools.h:631
const T * Next(const T *Object) const
< Returns the element immediately before Object in this list, or NULL if Object is the first element ...
Definition: tools.h:650
const T * First(void) const
Returns the first element in this list, or NULL if the list is empty.
Definition: tools.h:643
const cChannel * Get(int Index) const
Returns the list element at the given Index, or NULL if no such element exists.
Definition: tools.h:640
int StandardCompliance
Definition: config.h:298
int ShowChannelNamesWithSource
Definition: config.h:381
static int FromString(const char *s)
Definition: sources.c:65
static bool IsTerr(int Code)
Definition: sources.h:58
static cString ToString(int Code)
Definition: sources.c:52
static char ToChar(int Code)
Definition: sources.h:51
Definition: tools.h:178
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition: tools.c:1195
int Size(void) const
Definition: tools.h:754
virtual void Append(T Data)
Definition: tools.h:774
cSetup Setup
Definition: config.c:372
#define STANDARD_NORDIG
Definition: config.h:81
#define tr(s)
Definition: i18n.h:85
@ AC3DescriptorTag
Definition: si.h:119
tChannelID(void)
Definition: channels.h:57
tChannelID & ClrRid(void)
Definition: channels.h:61
int tid
Definition: channels.h:53
static const tChannelID InvalidID
Definition: channels.h:70
int Sid(void) const
Definition: channels.h:66
int nid
actually the "original" network id
Definition: channels.h:52
int Nid(void) const
Definition: channels.h:64
static tChannelID FromString(const char *s)
Definition: channels.c:24
cString ToString(void) const
Definition: channels.c:41
int Source(void) const
Definition: channels.h:63
int source
Definition: channels.h:51
int rid
Definition: channels.h:55
tChannelID & ClrPolarization(void)
Definition: channels.c:48
int sid
Definition: channels.h:54
int Tid(void) const
Definition: channels.h:65
char * strcpyrealloc(char *dest, const char *src)
Definition: tools.c:114
bool isempty(const char *s)
Definition: tools.c:357
int Utf8StrLen(const char *s)
Returns the number of UTF-8 symbols formed by the given string of character bytes.
Definition: tools.c:903
char * strreplace(char *s, char c1, char c2)
Definition: tools.c:142
char * strn0cpy(char *dest, const char *src, size_t n)
Definition: tools.c:131
bool endswith(const char *s, const char *p)
Definition: tools.c:346
char * skipspace(const char *s)
Definition: tools.h:244
unsigned char uchar
Definition: tools.h:31
#define dsyslog(a...)
Definition: tools.h:37
T max(T a, T b)
Definition: tools.h:64
#define esyslog(a...)
Definition: tools.h:35