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