mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
833 lines
22 KiB
C
833 lines
22 KiB
C
/*
|
|
* config.c: Configuration file handling
|
|
*
|
|
* See the main source file 'vdr.c' for copyright information and
|
|
* how to reach the author.
|
|
*
|
|
* $Id: config.c 1.43 2001/02/24 13:20:18 kls Exp $
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include <ctype.h>
|
|
#include <stdlib.h>
|
|
#include "dvbapi.h"
|
|
#include "i18n.h"
|
|
#include "interface.h"
|
|
|
|
// -- cKeys ------------------------------------------------------------------
|
|
|
|
tKey keyTable[] = { // "Up" and "Down" must be the first two keys!
|
|
{ kUp, "Up", 0 },
|
|
{ kDown, "Down", 0 },
|
|
{ kMenu, "Menu", 0 },
|
|
{ kOk, "Ok", 0 },
|
|
{ kBack, "Back", 0 },
|
|
{ kLeft, "Left", 0 },
|
|
{ kRight, "Right", 0 },
|
|
{ kRed, "Red", 0 },
|
|
{ kGreen, "Green", 0 },
|
|
{ kYellow, "Yellow", 0 },
|
|
{ kBlue, "Blue", 0 },
|
|
{ k0, "0", 0 },
|
|
{ k1, "1", 0 },
|
|
{ k2, "2", 0 },
|
|
{ k3, "3", 0 },
|
|
{ k4, "4", 0 },
|
|
{ k5, "5", 0 },
|
|
{ k6, "6", 0 },
|
|
{ k7, "7", 0 },
|
|
{ k8, "8", 0 },
|
|
{ k9, "9", 0 },
|
|
{ kNone, "", 0 },
|
|
};
|
|
|
|
cKeys::cKeys(void)
|
|
{
|
|
fileName = NULL;
|
|
code = 0;
|
|
address = 0;
|
|
keys = keyTable;
|
|
}
|
|
|
|
void cKeys::Clear(void)
|
|
{
|
|
for (tKey *k = keys; k->type != kNone; k++)
|
|
k->code = 0;
|
|
}
|
|
|
|
void cKeys::SetDummyValues(void)
|
|
{
|
|
for (tKey *k = keys; k->type != kNone; k++)
|
|
k->code = k->type + 1; // '+1' to avoid 0
|
|
}
|
|
|
|
bool cKeys::Load(const char *FileName)
|
|
{
|
|
isyslog(LOG_INFO, "loading %s", FileName);
|
|
bool result = false;
|
|
if (FileName)
|
|
fileName = strdup(FileName);
|
|
if (fileName) {
|
|
FILE *f = fopen(fileName, "r");
|
|
if (f) {
|
|
int line = 0;
|
|
char buffer[MaxBuffer];
|
|
result = true;
|
|
while (fgets(buffer, sizeof(buffer), f) > 0) {
|
|
line++;
|
|
char *Name = buffer;
|
|
char *p = strpbrk(Name, " \t");
|
|
if (p) {
|
|
*p = 0; // terminates 'Name'
|
|
while (*++p && isspace(*p))
|
|
;
|
|
if (*p) {
|
|
if (strcasecmp(Name, "Code") == 0)
|
|
code = *p;
|
|
else if (strcasecmp(Name, "Address") == 0)
|
|
address = strtol(p, NULL, 16);
|
|
else {
|
|
for (tKey *k = keys; k->type != kNone; k++) {
|
|
if (strcasecmp(Name, k->name) == 0) {
|
|
k->code = strtol(p, NULL, 16);
|
|
Name = NULL; // to indicate that we found it
|
|
break;
|
|
}
|
|
}
|
|
if (Name) {
|
|
esyslog(LOG_ERR, "unknown key in %s, line %d\n", fileName, line);
|
|
result = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line);
|
|
result = false;
|
|
break;
|
|
}
|
|
fclose(f);
|
|
}
|
|
else
|
|
esyslog(LOG_ERR, "can't open '%s'\n", fileName);
|
|
}
|
|
else
|
|
esyslog(LOG_ERR, "no key configuration file name supplied!\n");
|
|
return result;
|
|
}
|
|
|
|
bool cKeys::Save(void)
|
|
{
|
|
bool result = true;
|
|
cSafeFile f(fileName);
|
|
if (f.Open()) {
|
|
if (fprintf(f, "Code\t%c\nAddress\t%04X\n", code, address) > 0) {
|
|
for (tKey *k = keys; k->type != kNone; k++) {
|
|
if (fprintf(f, "%s\t%08X\n", k->name, k->code) <= 0) {
|
|
result = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
result = false;
|
|
f.Close();
|
|
}
|
|
else
|
|
result = false;
|
|
return result;
|
|
}
|
|
|
|
eKeys cKeys::Get(unsigned int Code)
|
|
{
|
|
if (Code != 0) {
|
|
tKey *k;
|
|
for (k = keys; k->type != kNone; k++) {
|
|
if (k->code == Code)
|
|
break;
|
|
}
|
|
return k->type;
|
|
}
|
|
return kNone;
|
|
}
|
|
|
|
eKeys cKeys::Translate(const char *Command)
|
|
{
|
|
if (Command) {
|
|
const tKey *k = keys;
|
|
while ((k->type != kNone) && strcasecmp(k->name, Command) != 0)
|
|
k++;
|
|
return k->type;
|
|
}
|
|
return kNone;
|
|
}
|
|
|
|
unsigned int cKeys::Encode(const char *Command)
|
|
{
|
|
eKeys k = Translate(Command);
|
|
if (k != kNone)
|
|
return keys[k].code;
|
|
return 0;
|
|
}
|
|
|
|
void cKeys::Set(eKeys Key, unsigned int Code)
|
|
{
|
|
for (tKey *k = keys; k->type != kNone; k++) {
|
|
if (k->type == Key) {
|
|
k->code = Code;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// -- cChannel ---------------------------------------------------------------
|
|
|
|
char *cChannel::buffer = NULL;
|
|
|
|
cChannel::cChannel(void)
|
|
{
|
|
*name = 0;
|
|
}
|
|
|
|
cChannel::cChannel(const cChannel *Channel)
|
|
{
|
|
strcpy(name, Channel ? Channel->name : "Pro7");
|
|
frequency = Channel ? Channel->frequency : 12480;
|
|
polarization = Channel ? Channel->polarization : 'v';
|
|
diseqc = Channel ? Channel->diseqc : 0;
|
|
srate = Channel ? Channel->srate : 27500;
|
|
vpid = Channel ? Channel->vpid : 255;
|
|
apid = Channel ? Channel->apid : 256;
|
|
tpid = Channel ? Channel->tpid : 32;
|
|
ca = Channel ? Channel->ca : 0;
|
|
pnr = Channel ? Channel->pnr : 0;
|
|
groupSep = Channel ? Channel->groupSep : false;
|
|
}
|
|
|
|
const char *cChannel::ToText(cChannel *Channel)
|
|
{
|
|
char buf[MaxChannelName * 2];
|
|
char *s = Channel->name;
|
|
if (strchr(s, ':')) {
|
|
s = strcpy(buf, s);
|
|
strreplace(s, ':', '|');
|
|
}
|
|
delete buffer;
|
|
if (Channel->groupSep)
|
|
asprintf(&buffer, ":%s\n", s);
|
|
else
|
|
asprintf(&buffer, "%s:%d:%c:%d:%d:%d:%d:%d:%d:%d\n", s, Channel->frequency, Channel->polarization, Channel->diseqc, Channel->srate, Channel->vpid, Channel->apid, Channel->tpid, Channel->ca, Channel->pnr);
|
|
return buffer;
|
|
}
|
|
|
|
const char *cChannel::ToText(void)
|
|
{
|
|
return ToText(this);
|
|
}
|
|
|
|
bool cChannel::Parse(const char *s)
|
|
{
|
|
char *buffer = NULL;
|
|
if (*s == ':') {
|
|
if (*++s) {
|
|
strn0cpy(name, s, MaxChannelName);
|
|
name[strlen(name) - 1] = 0; // strip the '\n'
|
|
groupSep = true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
else {
|
|
groupSep = false;
|
|
//XXX
|
|
int fields = sscanf(s, "%a[^:]:%d:%c:%d:%d:%d:%d:%d:%d:%d", &buffer, &frequency, &polarization, &diseqc, &srate, &vpid, &apid, &tpid, &ca, &pnr);
|
|
if (fields >= 9) {
|
|
if (fields == 9) {
|
|
// allow reading of old format
|
|
pnr = ca;
|
|
ca = tpid;
|
|
tpid = 0;
|
|
}
|
|
strn0cpy(name, buffer, MaxChannelName);
|
|
delete buffer;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
strreplace(name, '|', ':');
|
|
return true;
|
|
}
|
|
|
|
bool cChannel::Save(FILE *f)
|
|
{
|
|
return fprintf(f, ToText()) > 0;
|
|
}
|
|
|
|
bool cChannel::Switch(cDvbApi *DvbApi, bool Log)
|
|
{
|
|
if (!DvbApi)
|
|
DvbApi = cDvbApi::PrimaryDvbApi;
|
|
if (!DvbApi->Recording() && !groupSep) {
|
|
if (Log) {
|
|
isyslog(LOG_INFO, "switching to channel %d", number);
|
|
}
|
|
for (int i = 3; i--;) {
|
|
if (DvbApi->SetChannel(number, frequency, polarization, diseqc, srate, vpid, apid, tpid, ca, pnr))
|
|
return true;
|
|
esyslog(LOG_ERR, "retrying");
|
|
}
|
|
return false;
|
|
}
|
|
if (DvbApi->Recording())
|
|
Interface->Info(tr("Channel locked (recording)!"));
|
|
return false;
|
|
}
|
|
|
|
// -- cTimer -----------------------------------------------------------------
|
|
|
|
char *cTimer::buffer = NULL;
|
|
|
|
cTimer::cTimer(bool Instant)
|
|
{
|
|
startTime = stopTime = 0;
|
|
recording = false;
|
|
active = Instant;
|
|
cChannel *ch = Channels.GetByNumber(cDvbApi::CurrentChannel());
|
|
channel = ch ? ch->number : 0;
|
|
time_t t = time(NULL);
|
|
struct tm *now = localtime(&t);
|
|
day = now->tm_mday;
|
|
start = now->tm_hour * 100 + now->tm_min;
|
|
stop = start + 200; // "instant recording" records 2 hours by default
|
|
if (stop >= 2400)
|
|
stop -= 2400;
|
|
//TODO VPS???
|
|
priority = DEFAULTPRIORITY;
|
|
lifetime = DEFAULTLIFETIME;
|
|
*file = 0;
|
|
summary = NULL;
|
|
if (Instant && ch)
|
|
snprintf(file, sizeof(file), "%s%s", Setup.MarkInstantRecord ? "@" : "", ch->name);
|
|
}
|
|
|
|
cTimer::cTimer(const cEventInfo *EventInfo)
|
|
{
|
|
startTime = stopTime = 0;
|
|
recording = false;
|
|
active = true;
|
|
cChannel *ch = Channels.GetByServiceID(EventInfo->GetServiceID());
|
|
channel = ch ? ch->number : 0;
|
|
time_t tstart = EventInfo->GetTime();
|
|
time_t tstop = tstart + EventInfo->GetDuration() + Setup.MarginStop * 60;
|
|
tstart -= Setup.MarginStart * 60;
|
|
struct tm *time = localtime(&tstart);
|
|
day = time->tm_mday;
|
|
start = time->tm_hour * 100 + time->tm_min;
|
|
time = localtime(&tstop);
|
|
stop = time->tm_hour * 100 + time->tm_min;
|
|
if (stop >= 2400)
|
|
stop -= 2400;
|
|
priority = DEFAULTPRIORITY;
|
|
lifetime = DEFAULTLIFETIME;
|
|
*file = 0;
|
|
const char *Title = EventInfo->GetTitle();
|
|
if (!isempty(Title))
|
|
strn0cpy(file, EventInfo->GetTitle(), sizeof(file));
|
|
summary = NULL;
|
|
const char *Subtitle = EventInfo->GetSubtitle();
|
|
if (isempty(Subtitle))
|
|
Subtitle = "";
|
|
const char *Summary = EventInfo->GetExtendedDescription();
|
|
if (isempty(Summary))
|
|
Summary = "";
|
|
if (*Subtitle || *Summary) {
|
|
asprintf(&summary, "%s%s%s", Subtitle, (*Subtitle && *Summary) ? "\n\n" : "", Summary);
|
|
char *p = summary;
|
|
while (*p) {
|
|
if (*p == '\n')
|
|
*p = '|';
|
|
p++;
|
|
}
|
|
}
|
|
}
|
|
|
|
cTimer::~cTimer()
|
|
{
|
|
delete summary;
|
|
}
|
|
|
|
cTimer& cTimer::operator= (const cTimer &Timer)
|
|
{
|
|
memcpy(this, &Timer, sizeof(*this));
|
|
if (summary)
|
|
summary = strdup(summary);
|
|
return *this;
|
|
}
|
|
|
|
const char *cTimer::ToText(cTimer *Timer)
|
|
{
|
|
delete buffer;
|
|
strreplace(Timer->file, ':', '|');
|
|
strreplace(Timer->summary, '\n', '|');
|
|
asprintf(&buffer, "%d:%d:%s:%04d:%04d:%d:%d:%s:%s\n", Timer->active, Timer->channel, PrintDay(Timer->day), Timer->start, Timer->stop, Timer->priority, Timer->lifetime, Timer->file, Timer->summary ? Timer->summary : "");
|
|
strreplace(Timer->summary, '|', '\n');
|
|
strreplace(Timer->file, '|', ':');
|
|
return buffer;
|
|
}
|
|
|
|
const char *cTimer::ToText(void)
|
|
{
|
|
return ToText(this);
|
|
}
|
|
|
|
int cTimer::TimeToInt(int t)
|
|
{
|
|
return (t / 100 * 60 + t % 100) * 60;
|
|
}
|
|
|
|
time_t cTimer::Day(time_t t)
|
|
{
|
|
struct tm d = *localtime(&t);
|
|
d.tm_hour = d.tm_min = d.tm_sec = 0;
|
|
return mktime(&d);
|
|
}
|
|
|
|
int cTimer::ParseDay(const char *s)
|
|
{
|
|
char *tail;
|
|
int d = strtol(s, &tail, 10);
|
|
if (tail && *tail) {
|
|
d = 0;
|
|
if (tail == s) {
|
|
if (strlen(s) == 7) {
|
|
for (const char *p = s + 6; p >= s; p--) {
|
|
d <<= 1;
|
|
d |= (*p != '-');
|
|
}
|
|
d |= 0x80000000;
|
|
}
|
|
}
|
|
}
|
|
else if (d < 1 || d > 31)
|
|
d = 0;
|
|
return d;
|
|
}
|
|
|
|
const char *cTimer::PrintDay(int d)
|
|
{
|
|
static char buffer[8];
|
|
if ((d & 0x80000000) != 0) {
|
|
char *b = buffer;
|
|
const char *w = tr("MTWTFSS");
|
|
*b = 0;
|
|
while (*w) {
|
|
*b++ = (d & 1) ? *w : '-';
|
|
d >>= 1;
|
|
w++;
|
|
}
|
|
}
|
|
else
|
|
sprintf(buffer, "%d", d);
|
|
return buffer;
|
|
}
|
|
|
|
bool cTimer::Parse(const char *s)
|
|
{
|
|
char *buffer1 = NULL;
|
|
char *buffer2 = NULL;
|
|
delete summary;
|
|
summary = NULL;
|
|
//XXX Apparently sscanf() doesn't work correctly if the last %a argument
|
|
//XXX results in an empty string (this first occured when the EIT gathering
|
|
//XXX was put into a separate thread - don't know why this happens...
|
|
//XXX As a cure we copy the original string and add a blank.
|
|
//XXX If anybody can shed some light on why sscanf() failes here, I'd love
|
|
//XXX to hear about that!
|
|
char *s2 = NULL;
|
|
int l2 = strlen(s);
|
|
while (l2 > 0 && isspace(s[l2 - 1]))
|
|
l2--;
|
|
if (s[l2 - 1] == ':') {
|
|
s2 = (char *)malloc(l2 + 3);
|
|
strcat(strn0cpy(s2, s, l2 + 1), " \n");
|
|
s = s2;
|
|
}
|
|
if (8 <= sscanf(s, "%d:%d:%a[^:]:%d:%d:%d:%d:%a[^:\n]:%a[^\n]", &active, &channel, &buffer1, &start, &stop, &priority, &lifetime, &buffer2, &summary)) {
|
|
if (summary && !*skipspace(summary)) {
|
|
delete summary;
|
|
summary = NULL;
|
|
}
|
|
//TODO add more plausibility checks
|
|
day = ParseDay(buffer1);
|
|
strn0cpy(file, buffer2, MaxFileName);
|
|
strreplace(file, '|', ':');
|
|
strreplace(summary, '|', '\n');
|
|
delete buffer1;
|
|
delete buffer2;
|
|
delete s2;
|
|
return day != 0;
|
|
}
|
|
delete s2;
|
|
return false;
|
|
}
|
|
|
|
bool cTimer::Save(FILE *f)
|
|
{
|
|
return fprintf(f, ToText()) > 0;
|
|
}
|
|
|
|
bool cTimer::IsSingleEvent(void)
|
|
{
|
|
return (day & 0x80000000) == 0;
|
|
}
|
|
|
|
bool cTimer::Matches(time_t t)
|
|
{
|
|
if (active) {
|
|
if (t == 0)
|
|
t = time(NULL);
|
|
struct tm now = *localtime(&t);
|
|
int weekday = now.tm_wday == 0 ? 6 : now.tm_wday - 1; // we start with monday==0!
|
|
int begin = TimeToInt(start);
|
|
int end = TimeToInt(stop);
|
|
bool twoDays = (end < begin);
|
|
|
|
bool todayMatches = false, yesterdayMatches = false;
|
|
if ((day & 0x80000000) != 0) {
|
|
if ((day & (1 << weekday)) != 0)
|
|
todayMatches = true;
|
|
else if (twoDays) {
|
|
int yesterday = weekday == 0 ? 6 : weekday - 1;
|
|
if ((day & (1 << yesterday)) != 0)
|
|
yesterdayMatches = true;
|
|
}
|
|
}
|
|
else if (day == now.tm_mday)
|
|
todayMatches = true;
|
|
else if (twoDays) {
|
|
time_t ty = t - SECSINDAY;
|
|
if (day == localtime(&ty)->tm_mday)
|
|
yesterdayMatches = true;
|
|
}
|
|
if (todayMatches || (twoDays && yesterdayMatches)) {
|
|
startTime = Day(t - (yesterdayMatches ? SECSINDAY : 0)) + begin;
|
|
stopTime = startTime + (twoDays ? SECSINDAY - begin + end : end - begin);
|
|
}
|
|
else
|
|
startTime = stopTime = 0;
|
|
return startTime <= t && t <= stopTime;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
time_t cTimer::StartTime(void)
|
|
{
|
|
if (!startTime)
|
|
Matches();
|
|
return startTime;
|
|
}
|
|
|
|
time_t cTimer::StopTime(void)
|
|
{
|
|
if (!stopTime)
|
|
Matches();
|
|
return stopTime;
|
|
}
|
|
|
|
void cTimer::SetRecording(bool Recording)
|
|
{
|
|
recording = Recording;
|
|
isyslog(LOG_INFO, "timer %d %s", Index() + 1, recording ? "start" : "stop");
|
|
}
|
|
|
|
cTimer *cTimer::GetMatch(void)
|
|
{
|
|
time_t t = time(NULL); // all timers must be checked against the exact same time to correctly handle Priority!
|
|
cTimer *t0 = NULL;
|
|
cTimer *ti = (cTimer *)Timers.First();
|
|
while (ti) {
|
|
if (!ti->recording && ti->Matches(t)) {
|
|
if (!t0 || ti->priority > t0->priority)
|
|
t0 = ti;
|
|
}
|
|
ti = (cTimer *)ti->Next();
|
|
}
|
|
return t0;
|
|
}
|
|
|
|
// --- cCommand -------------------------------------------------------------
|
|
|
|
char *cCommand::result = NULL;
|
|
|
|
cCommand::cCommand(void)
|
|
{
|
|
title = command = NULL;
|
|
}
|
|
|
|
cCommand::~cCommand()
|
|
{
|
|
delete title;
|
|
delete command;
|
|
}
|
|
|
|
bool cCommand::Parse(const char *s)
|
|
{
|
|
const char *p = strchr(s, ':');
|
|
if (p) {
|
|
int l = p - s;
|
|
if (l > 0) {
|
|
title = new char[l + 1];
|
|
strn0cpy(title, s, l + 1);
|
|
if (!isempty(title)) {
|
|
command = stripspace(strdup(skipspace(p + 1)));
|
|
return !isempty(command);
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
const char *cCommand::Execute(void)
|
|
{
|
|
dsyslog(LOG_INFO, "executing command '%s'", command);
|
|
delete result;
|
|
result = NULL;
|
|
FILE *p = popen(command, "r");
|
|
if (p) {
|
|
int l = 0;
|
|
int c;
|
|
while ((c = fgetc(p)) != EOF) {
|
|
if (l % 20 == 0)
|
|
result = (char *)realloc(result, l + 21);
|
|
result[l++] = c;
|
|
}
|
|
if (result)
|
|
result[l] = 0;
|
|
pclose(p);
|
|
}
|
|
else
|
|
esyslog(LOG_ERR, "ERROR: can't open pipe for command '%s'", command);
|
|
return result;
|
|
}
|
|
|
|
// -- cKeys ------------------------------------------------------------------
|
|
|
|
cKeys Keys;
|
|
|
|
// -- cCommands --------------------------------------------------------------
|
|
|
|
cCommands Commands;
|
|
|
|
// -- cChannels --------------------------------------------------------------
|
|
|
|
int CurrentGroup = -1;
|
|
|
|
cChannels Channels;
|
|
|
|
bool cChannels::Load(const char *FileName)
|
|
{
|
|
if (cConfig<cChannel>::Load(FileName)) {
|
|
ReNumber();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int cChannels::GetNextGroup(int Idx)
|
|
{
|
|
cChannel *channel = Get(++Idx);
|
|
while (channel && !channel->groupSep)
|
|
channel = Get(++Idx);
|
|
return channel ? Idx : -1;
|
|
}
|
|
|
|
int cChannels::GetPrevGroup(int Idx)
|
|
{
|
|
cChannel *channel = Get(--Idx);
|
|
while (channel && !channel->groupSep)
|
|
channel = Get(--Idx);
|
|
return channel ? Idx : -1;
|
|
}
|
|
|
|
int cChannels::GetNextNormal(int Idx)
|
|
{
|
|
cChannel *channel = Get(++Idx);
|
|
while (channel && channel->groupSep)
|
|
channel = Get(++Idx);
|
|
return channel ? Idx : -1;
|
|
}
|
|
|
|
void cChannels::ReNumber( void )
|
|
{
|
|
int Number = 0;
|
|
cChannel *ch = (cChannel *)First();
|
|
while (ch) {
|
|
if (!ch->groupSep)
|
|
ch->number = ++Number;
|
|
ch = (cChannel *)ch->Next();
|
|
}
|
|
maxNumber = Number;
|
|
}
|
|
|
|
cChannel *cChannels::GetByNumber(int Number)
|
|
{
|
|
cChannel *channel = (cChannel *)First();
|
|
while (channel) {
|
|
if (channel->number == Number)
|
|
return channel;
|
|
channel = (cChannel *)channel->Next();
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
cChannel *cChannels::GetByServiceID(unsigned short ServiceId)
|
|
{
|
|
cChannel *channel = (cChannel *)First();
|
|
while (channel) {
|
|
if (channel->pnr == ServiceId)
|
|
return channel;
|
|
channel = (cChannel *)channel->Next();
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
bool cChannels::SwitchTo(int Number, cDvbApi *DvbApi)
|
|
{
|
|
cChannel *channel = GetByNumber(Number);
|
|
return channel && channel->Switch(DvbApi);
|
|
}
|
|
|
|
const char *cChannels::GetChannelNameByNumber(int Number)
|
|
{
|
|
cChannel *channel = GetByNumber(Number);
|
|
return channel ? channel->name : NULL;
|
|
}
|
|
|
|
// -- cTimers ----------------------------------------------------------------
|
|
|
|
cTimers Timers;
|
|
|
|
cTimer *cTimers::GetTimer(cTimer *Timer)
|
|
{
|
|
cTimer *ti = (cTimer *)First();
|
|
while (ti) {
|
|
if (ti->channel == Timer->channel && ti->day == Timer->day && ti->start == Timer->start && ti->stop == Timer->stop)
|
|
return ti;
|
|
ti = (cTimer *)ti->Next();
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// -- cSetup -----------------------------------------------------------------
|
|
|
|
cSetup Setup;
|
|
|
|
char *cSetup::fileName = NULL;
|
|
|
|
cSetup::cSetup(void)
|
|
{
|
|
OSDLanguage = 0;
|
|
PrimaryDVB = 1;
|
|
ShowInfoOnChSwitch = 1;
|
|
MenuScrollPage = 1;
|
|
MarkInstantRecord = 1;
|
|
LnbFrequLo = 9750;
|
|
LnbFrequHi = 10600;
|
|
SetSystemTime = 0;
|
|
MarginStart = 2;
|
|
MarginStop = 10;
|
|
EPGScanTimeout = 5;
|
|
SVDRPTimeout = 300;
|
|
PrimaryLimit = 0;
|
|
CurrentChannel = -1;
|
|
}
|
|
|
|
bool cSetup::Parse(char *s)
|
|
{
|
|
const char *Delimiters = " \t\n=";
|
|
char *Name = strtok(s, Delimiters);
|
|
char *Value = strtok(NULL, Delimiters);
|
|
if (Name && Value) {
|
|
if (!strcasecmp(Name, "OSDLanguage")) OSDLanguage = atoi(Value);
|
|
else if (!strcasecmp(Name, "PrimaryDVB")) PrimaryDVB = atoi(Value);
|
|
else if (!strcasecmp(Name, "ShowInfoOnChSwitch")) ShowInfoOnChSwitch = atoi(Value);
|
|
else if (!strcasecmp(Name, "MenuScrollPage")) MenuScrollPage = atoi(Value);
|
|
else if (!strcasecmp(Name, "MarkInstantRecord")) MarkInstantRecord = atoi(Value);
|
|
else if (!strcasecmp(Name, "LnbFrequLo")) LnbFrequLo = atoi(Value);
|
|
else if (!strcasecmp(Name, "LnbFrequHi")) LnbFrequHi = atoi(Value);
|
|
else if (!strcasecmp(Name, "SetSystemTime")) SetSystemTime = atoi(Value);
|
|
else if (!strcasecmp(Name, "MarginStart")) MarginStart = atoi(Value);
|
|
else if (!strcasecmp(Name, "MarginStop")) MarginStop = atoi(Value);
|
|
else if (!strcasecmp(Name, "EPGScanTimeout")) EPGScanTimeout = atoi(Value);
|
|
else if (!strcasecmp(Name, "SVDRPTimeout")) SVDRPTimeout = atoi(Value);
|
|
else if (!strcasecmp(Name, "PrimaryLimit")) PrimaryLimit = atoi(Value);
|
|
else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value);
|
|
else
|
|
return false;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool cSetup::Load(const char *FileName)
|
|
{
|
|
isyslog(LOG_INFO, "loading %s", FileName);
|
|
delete fileName;
|
|
fileName = strdup(FileName);
|
|
FILE *f = fopen(fileName, "r");
|
|
if (f) {
|
|
int line = 0;
|
|
char buffer[MaxBuffer];
|
|
bool result = true;
|
|
while (fgets(buffer, sizeof(buffer), f) > 0) {
|
|
line++;
|
|
if (*buffer != '#' && !Parse(buffer)) {
|
|
esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line);
|
|
result = false;
|
|
break;
|
|
}
|
|
}
|
|
fclose(f);
|
|
return result;
|
|
}
|
|
else
|
|
LOG_ERROR_STR(FileName);
|
|
return false;
|
|
}
|
|
|
|
bool cSetup::Save(const char *FileName)
|
|
{
|
|
if (!FileName)
|
|
FileName = fileName;
|
|
if (FileName) {
|
|
cSafeFile f(FileName);
|
|
if (f.Open()) {
|
|
fprintf(f, "# VDR Setup\n");
|
|
fprintf(f, "OSDLanguage = %d\n", OSDLanguage);
|
|
fprintf(f, "PrimaryDVB = %d\n", PrimaryDVB);
|
|
fprintf(f, "ShowInfoOnChSwitch = %d\n", ShowInfoOnChSwitch);
|
|
fprintf(f, "MenuScrollPage = %d\n", MenuScrollPage);
|
|
fprintf(f, "MarkInstantRecord = %d\n", MarkInstantRecord);
|
|
fprintf(f, "LnbFrequLo = %d\n", LnbFrequLo);
|
|
fprintf(f, "LnbFrequHi = %d\n", LnbFrequHi);
|
|
fprintf(f, "SetSystemTime = %d\n", SetSystemTime);
|
|
fprintf(f, "MarginStart = %d\n", MarginStart);
|
|
fprintf(f, "MarginStop = %d\n", MarginStop);
|
|
fprintf(f, "EPGScanTimeout = %d\n", EPGScanTimeout);
|
|
fprintf(f, "SVDRPTimeout = %d\n", SVDRPTimeout);
|
|
fprintf(f, "PrimaryLimit = %d\n", PrimaryLimit);
|
|
fprintf(f, "CurrentChannel = %d\n", CurrentChannel);
|
|
f.Close();
|
|
isyslog(LOG_INFO, "saved setup to %s", FileName);
|
|
return true;
|
|
}
|
|
else
|
|
LOG_ERROR_STR(FileName);
|
|
}
|
|
else
|
|
esyslog(LOG_ERR, "attempt to save setup without file name");
|
|
return false;
|
|
}
|
|
|