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