Bug Summary

File:channels.c
Location:line 556, column 9
Description:Value stored to 'q' is never read

Annotated Source Code

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