/*
 * 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.161 2008/02/17 13:39:00 kls Exp $
 */

#include "config.h"
#include <ctype.h>
#include <stdlib.h>
#include "device.h"
#include "i18n.h"
#include "interface.h"
#include "plugin.h"
#include "recording.h"
#ifdef USE_SOURCECAPS
#include "sources.h"
#endif /* SOURCECAPS */

// IMPORTANT NOTE: in the 'sscanf()' calls there is a blank after the '%d'
// format characters in order to allow any number of blanks after a numeric
// value!

// --- cCommand --------------------------------------------------------------

char *cCommand::result = NULL;

cCommand::cCommand(void)
{
  title = command = NULL;
  confirm = false;
#ifdef USE_CMDSUBMENU
  nIndent = 0;
  childs = NULL;
#endif /* CMDSUBMENU */
}

cCommand::~cCommand()
{
  free(title);
  free(command);
#ifdef USE_CMDSUBMENU
  delete childs;
#endif /* CMDSUBMENU */
}

bool cCommand::Parse(const char *s)
{
  const char *p = strchr(s, ':');
  if (p) {
#ifdef USE_CMDSUBMENU
     nIndent = 0;
     while (*s == '-') {
           nIndent++;
           s++;
           }
#endif /* CMDSUBMENU */
     int l = p - s;
     if (l > 0) {
        title = MALLOC(char, l + 1);
        stripspace(strn0cpy(title, s, l + 1));
        if (!isempty(title)) {
           int l = strlen(title);
           if (l > 1 && title[l - 1] == '?') {
              confirm = true;
              title[l - 1] = 0;
              }
           command = stripspace(strdup(skipspace(p + 1)));
           return !isempty(command);
           }
        }
     }
  return false;
}

const char *cCommand::Execute(const char *Parameters)
{
  free(result);
  result = NULL;
  cString cmdbuf;
  if (Parameters)
     cmdbuf = cString::sprintf("%s %s", command, Parameters);
  const char *cmd = *cmdbuf ? *cmdbuf : command;
  dsyslog("executing command '%s'", cmd);
  cPipe p;
  if (p.Open(cmd, "r")) {
     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;
     p.Close();
     }
  else
     esyslog("ERROR: can't open pipe for command '%s'", cmd);
  return result;
}

#ifdef USE_CMDSUBMENU
int cCommand::getChildCount(void)
{
  return childs ? childs->Count() : 0;
}

void cCommand::addChild(cCommand *newChild)
{
  if (!childs)
     childs = new cCommands();
  childs->AddConfig(newChild);
}
#endif /* CMDSUBMENU */

// --- cSVDRPhost ------------------------------------------------------------

cSVDRPhost::cSVDRPhost(void)
{
  addr.s_addr = 0;
  mask = 0;
}

bool cSVDRPhost::Parse(const char *s)
{
  mask = 0xFFFFFFFF;
  const char *p = strchr(s, '/');
  if (p) {
     char *error = NULL;
     int m = strtoul(p + 1, &error, 10);
     if (error && *error && !isspace(*error) || m > 32)
        return false;
     *(char *)p = 0; // yes, we know it's 'const' - will be restored!
     if (m == 0)
        mask = 0;
     else {
        mask <<= (32 - m);
        mask = htonl(mask);
        }
     }
  int result = inet_aton(s, &addr);
  if (p)
     *(char *)p = '/'; // there it is again
  return result != 0 && (mask != 0 || addr.s_addr == 0);
}

bool cSVDRPhost::Accepts(in_addr_t Address)
{
  return (Address & mask) == (addr.s_addr & mask);
}

// --- cCommands -------------------------------------------------------------

cCommands Commands;
cCommands RecordingCommands;
#ifdef USE_TIMERCMD
cCommands TimerCommands;
#endif /* TIMERCMD */

#ifdef USE_CMDSUBMENU
void cCommands::AddConfig(cCommand *Object)
{
  if (!Object)
     return;
  //isyslog ("Indent %d %s\n", Object->getIndent(), Object->Title());
  for (int index = Count() - 1; index >= 0; index--) {
      cCommand *parent = Get(index);
      if (parent->getIndent() < Object->getIndent()) {
         parent->addChild(Object);
         return;
         }
      }
  cConfig<cCommand>::Add(Object);
}
#endif /* CMDSUBMENU */

// --- cSVDRPhosts -----------------------------------------------------------

cSVDRPhosts SVDRPhosts;

bool cSVDRPhosts::Acceptable(in_addr_t Address)
{
  cSVDRPhost *h = First();
  while (h) {
        if (h->Accepts(Address))
           return true;
        h = (cSVDRPhost *)h->Next();
        }
  return false;
}

// --- cSetupLine ------------------------------------------------------------

cSetupLine::cSetupLine(void)
{
  plugin = name = value = NULL;
}

cSetupLine::cSetupLine(const char *Name, const char *Value, const char *Plugin)
{
  name = strdup(Name);
  value = strdup(Value);
  plugin = Plugin ? strdup(Plugin) : NULL;
}

cSetupLine::~cSetupLine()
{
  free(plugin);
  free(name);
  free(value);
}

int cSetupLine::Compare(const cListObject &ListObject) const
{
  const cSetupLine *sl = (cSetupLine *)&ListObject;
  if (!plugin && !sl->plugin)
     return strcasecmp(name, sl->name);
  if (!plugin)
     return -1;
  if (!sl->plugin)
     return 1;
  int result = strcasecmp(plugin, sl->plugin);
  if (result == 0)
     result = strcasecmp(name, sl->name);
  return result;
}

bool cSetupLine::Parse(char *s)
{
  char *p = strchr(s, '=');
  if (p) {
     *p = 0;
     char *Name  = compactspace(s);
     char *Value = compactspace(p + 1);
     if (*Name) { // value may be an empty string
        p = strchr(Name, '.');
        if (p) {
           *p = 0;
           char *Plugin = compactspace(Name);
           Name = compactspace(p + 1);
           if (!(*Plugin && *Name))
              return false;
           plugin = strdup(Plugin);
           }
        name = strdup(Name);
        value = strdup(Value);
        return true;
        }
     }
  return false;
}

bool cSetupLine::Save(FILE *f)
{
  return fprintf(f, "%s%s%s = %s\n", plugin ? plugin : "", plugin ? "." : "", name, value) > 0;
}

// --- cSetup ----------------------------------------------------------------

cSetup Setup;

cSetup::cSetup(void)
{
  strcpy(OSDLanguage, ""); // default is taken from environment
  strcpy(OSDSkin, "sttng");
  strcpy(OSDTheme, "default");
#ifdef USE_WAREAGLEICON
  WarEagleIcons = 1;
#endif /* WAREAGLEICON */
#ifdef USE_VALIDINPUT
  ShowValidInput = 0;
#endif /* VALIDINPUT */
  PrimaryDVB = 1;
  ShowInfoOnChSwitch = 1;
  TimeoutRequChInfo = 1;
  MenuScrollPage = 1;
  MenuScrollWrap = 0;
  MenuKeyCloses = 0;
  MarkInstantRecord = 1;
  strcpy(NameInstantRecord, "TITLE EPISODE");
  InstantRecordTime = 180;
  LnbSLOF    = 11700;
  LnbFrequLo =  9750;
  LnbFrequHi = 10600;
  DiSEqC = 0;
  SetSystemTime = 0;
  TimeSource = 0;
  TimeTransponder = 0;
  MarginStart = 2;
  MarginStop = 10;
  AudioLanguages[0] = -1;
  DisplaySubtitles = 0;
  SubtitleLanguages[0] = -1;
  SubtitleOffset = 0;
  SubtitleFgTransparency = 0;
  SubtitleBgTransparency = 0;
  EPGLanguages[0] = -1;
  EPGScanTimeout = 5;
  EPGBugfixLevel = 3;
  EPGLinger = 0;
  SVDRPTimeout = 300;
  ZapTimeout = 3;
  ChannelEntryTimeout = 1000;
  PrimaryLimit = 0;
  DefaultPriority = 50;
  DefaultLifetime = 99;
  PausePriority = 10;
  PauseLifetime = 1;
  UseSubtitle = 1;
  UseVps = 0;
  VpsMargin = 120;
  RecordingDirs = 1;
  VideoDisplayFormat = 1;
  VideoFormat = 0;
  UpdateChannels = 5;
  UseDolbyDigital = 1;
#ifdef USE_DOLBYINREC
  UseDolbyInRecordings = 1;
#endif /* DOLBYINREC */
#ifdef USE_DVBSETUP
  DolbyTransferFix = 1;
  NoQamOnDecoder = 0;
  TurnOffPrimary = 0;
#endif /* DVBSETUP */
#ifdef USE_SYNCEARLY
  UseSyncEarlyPatch = 0;
#endif /* SYNCEARLY */
  ChannelInfoPos = 0;
  ChannelInfoTime = 5;
  OSDLeft = 54;
  OSDTop = 45;
  OSDWidth = 624;
  OSDHeight = 486;
  OSDMessageTime = 1;
  UseSmallFont = 1;
  AntiAlias = 1;
  strcpy(FontOsd, DefaultFontOsd);
  strcpy(FontSml, DefaultFontSml);
  strcpy(FontFix, DefaultFontFix);
  FontOsdSize = 22;
  FontSmlSize = 18;
  FontFixSize = 20;
  MaxVideoFileSize = MAXVIDEOFILESIZE;
#ifdef USE_HARDLINKCUTTER
  MaxRecordingSize = DEFAULTRECORDINGSIZE;
#endif /* HARDLINKCUTTER */
  SplitEditedFiles = 0;
#ifdef USE_HARDLINKCUTTER
  HardLinkCutter = 0;
#endif /* HARDLINKCUTTER */
#ifdef USE_DELTIMESHIFTREC
  DelTimeshiftRec = 0;
#endif /* DELTIMESHIFTREC */
  MinEventTimeout = 30;
  MinUserInactivity = 300;
  NextWakeupTime = 0;
  MultiSpeedMode = 0;
  ShowReplayMode = 0;
#ifdef USE_DDEPGENTRY
  DoubleEpgTimeDelta = 15;
  DoubleEpgAction = 0;
  MixEpgAction = 0;
  DisableVPS = 0;
#endif /* DDEPGENTRY */
  ResumeID = 0;
#ifdef USE_JUMPPLAY
  JumpPlay = 0;
  PlayJump = 0;
  PauseLastMark = 0;
  ReloadMarks = 0;
#endif /* JUMPPLAY */
#ifdef USE_SOURCECAPS
  memset(SourceCaps, 0, sizeof SourceCaps);
  SourceCapsSet = false;
#endif /* SOURCECAPS */
  CurrentChannel = -1;
  CurrentVolume = MAXVOLUME;
  CurrentDolby = 0;
  InitialChannel = 0;
  InitialVolume = -1;
#ifdef USE_VOLCTRL
  LRVolumeControl = 0;
  LRChannelGroups = 1;
  LRForwardRewind = 1;
#endif /* VOLCTRL */
  EmergencyExit = 1;
#ifdef USE_NOEPG
  noEPGMode=0;
  noEPGList=strdup("");
#endif /* NOEPG */
#ifdef USE_LIRCSETTINGS
  LircRepeatDelay = 350;
  LircRepeatFreq = 100;
  LircRepeatTimeout = 500;
#endif /* LIRCSETTINGS */
#ifdef USE_LIEMIKUUTIO
  ShowRecDate = 1;
  ShowRecTime = 1;
  ShowRecLength = 0;
  MainMenuTitle = 0;
  strcpy(CustomMainMenuTitle, "Video Disk Recorder");
  ShowTimerStop = 1;
  ShowProgressBar = 0;
  MenuCmdPosition = 0;
  JumpSeconds = 60;
  JumpSecondsSlow = 10;
#endif /* LIEMIKUUTIO */
#ifdef USE_SORTRECORDS
  RecordingsSortMode = 0;
  RecordingsSortDirsFirst = 0;
#endif /* SORTRECORDS */
#ifdef USE_CUTTERQUEUE
  CutterAutoDelete = 0;
#endif /* CUTTERQUEUE */
#ifdef USE_LIVEBUFFER
  LiveBuffer = false;
  KeepPaused = false;
  LiveBufferSize = 100;
  InRAM = false;
  MemBufSize = 5;
  ExtendBuffer = false;
#endif /* LIVEBUFFER */
#ifdef USE_DVDARCHIVE
  DvdDisplayMode = 1;
  DvdDisplayZeros = 1;
  DvdTrayMode = 0;
  DvdSpeedLimit = 0;
#endif /* DVDARCHIVE */
#ifdef USE_LNBSHARE
  VerboseLNBlog = 0;
  for (int i = 0; i < MAXDEVICES; i++) CardUsesLNBnr[i] = i + 1;
#endif /* LNBSHARE */
#ifdef USE_DVLVIDPREFER
  UseVidPrefer = 0; // default = disabled
  nVidPrefer = 1;
  for (int zz = 1; zz < DVLVIDPREFER_MAX; zz++) {
      VidPreferPrio[ zz ] = 50;
      VidPreferSize[ zz ] = 100;
      }
  VidPreferSize[ 0 ] = 800;
  VidPreferPrio[ 0 ] = 50;
#endif /* DVLVIDPREFER */
#ifdef USE_DVLFRIENDLYFNAMES
  UseFriendlyFNames = 0; // default = disabled
#endif /* DVLFRIENDLYFNAMES */
}

#ifdef USE_NOEPG
cSetup::~cSetup()
{
  free(noEPGList);
}
#endif /* NOEPG */

cSetup& cSetup::operator= (const cSetup &s)
{
  memcpy(&__BeginData__, &s.__BeginData__, (char *)&s.__EndData__ - (char *)&s.__BeginData__);
#ifdef USE_NOEPG
  free(noEPGList);
  noEPGList = strdup(s.noEPGList);
#endif /* NOEPG */
  return *this;
}

cSetupLine *cSetup::Get(const char *Name, const char *Plugin)
{
  for (cSetupLine *l = First(); l; l = Next(l)) {
      if ((l->Plugin() == NULL) == (Plugin == NULL)) {
         if ((!Plugin || strcasecmp(l->Plugin(), Plugin) == 0) && strcasecmp(l->Name(), Name) == 0)
            return l;
         }
      }
  return NULL;
}

void cSetup::Store(const char *Name, const char *Value, const char *Plugin, bool AllowMultiple)
{
  if (Name && *Name) {
     cSetupLine *l = Get(Name, Plugin);
     if (l && !AllowMultiple)
        Del(l);
     if (Value)
        Add(new cSetupLine(Name, Value, Plugin));
     }
}

void cSetup::Store(const char *Name, int Value, const char *Plugin)
{
  Store(Name, cString::sprintf("%d", Value), Plugin);
}

bool cSetup::Load(const char *FileName)
{
  if (cConfig<cSetupLine>::Load(FileName, true)) {
     bool result = true;
     for (cSetupLine *l = First(); l; l = Next(l)) {
         bool error = false;
         if (l->Plugin()) {
            cPlugin *p = cPluginManager::GetPlugin(l->Plugin());
            if (p && !p->SetupParse(l->Name(), l->Value()))
               error = true;
            }
         else {
            if (!Parse(l->Name(), l->Value()))
               error = true;
            }
         if (error) {
            esyslog("ERROR: unknown config parameter: %s%s%s = %s", l->Plugin() ? l->Plugin() : "", l->Plugin() ? "." : "", l->Name(), l->Value());
            result = false;
            }
         }
     return result;
     }
  return false;
}

void cSetup::StoreLanguages(const char *Name, int *Values)
{
  char buffer[I18nLanguages()->Size() * 4];
  char *q = buffer;
  for (int i = 0; i < I18nLanguages()->Size(); i++) {
      if (Values[i] < 0)
         break;
      const char *s = I18nLanguageCode(Values[i]);
      if (s) {
         if (q > buffer)
            *q++ = ' ';
         strncpy(q, s, 3);
         q += 3;
         }
      }
  *q = 0;
  Store(Name, buffer);
}

bool cSetup::ParseLanguages(const char *Value, int *Values)
{
  int n = 0;
  while (Value && *Value && n < I18nLanguages()->Size()) {
        char buffer[4];
        strn0cpy(buffer, Value, sizeof(buffer));
        int i = I18nLanguageIndex(buffer);
        if (i >= 0)
           Values[n++] = i;
        if ((Value = strchr(Value, ' ')) != NULL)
           Value++;
        }
  Values[n] = -1;
  return true;
}

#ifdef USE_SOURCECAPS
void cSetup::StoreSourceCaps(const char *Name)
{
  cSetupLine *l;
  while ((l = Get(Name)) != NULL)
     Del(l);

  for (int i = 0; i < MAXDEVICES; i++) {
      char buffer[MAXSOURCECAPS*8]={0,}, *q = buffer;
      int j = 0;
      while (SourceCaps[i][j] && j < MAXSOURCECAPS) {
         if (j==0)
            q += snprintf(buffer, sizeof(buffer), "%i ", i+1);
            q += snprintf(q, sizeof(buffer) - (q-buffer), "%s ", *cSource::ToString(SourceCaps[i][j++]));
         }
      if (*buffer)
         Store(Name, buffer, NULL, true);
      }
}

bool cSetup::ParseSourceCaps(const char *Value)
{
  char *p;
  int d = strtol(Value, &p, 10)-1, i = 0;
  while (p < Value+strlen(Value)) {
     if (*p==0) return true;
     if (isblank(*p)) ++p;
     if (isalpha(*p)) {
        int source = cSource::FromString(p);
        if (source != cSource::stNone) {
           SourceCaps[d][i++] = source;
           SourceCapsSet = true;
           }
        else
           return false;
        while (!isblank(*p) && *p)
           ++p;
        if (i>MAXSOURCECAPS)
           return false;
        }
     }
  return true;
}
#endif /* SOURCECAPS */

bool cSetup::Parse(const char *Name, const char *Value)
{
  if      (!strcasecmp(Name, "OSDLanguage"))       { strn0cpy(OSDLanguage, Value, sizeof(OSDLanguage)); I18nSetLocale(OSDLanguage); }
  else if (!strcasecmp(Name, "OSDSkin"))             Utf8Strn0Cpy(OSDSkin, Value, MaxSkinName);
  else if (!strcasecmp(Name, "OSDTheme"))            Utf8Strn0Cpy(OSDTheme, Value, MaxThemeName);
#ifdef USE_WAREAGLEICON
  else if (!strcasecmp(Name, "WarEagleIcons"))       WarEagleIcons      = atoi(Value);
#endif /* WAREAGLEICON */
#ifdef USE_VALIDINPUT
  else if (!strcasecmp(Name, "ShowValidInput"))      ShowValidInput     = atoi(Value);
#endif /* VALIDINPUT */
  else if (!strcasecmp(Name, "PrimaryDVB"))          PrimaryDVB         = atoi(Value);
  else if (!strcasecmp(Name, "ShowInfoOnChSwitch"))  ShowInfoOnChSwitch = atoi(Value);
  else if (!strcasecmp(Name, "TimeoutRequChInfo"))   TimeoutRequChInfo  = atoi(Value);
  else if (!strcasecmp(Name, "MenuScrollPage"))      MenuScrollPage     = atoi(Value);
  else if (!strcasecmp(Name, "MenuScrollWrap"))      MenuScrollWrap     = atoi(Value);
  else if (!strcasecmp(Name, "MenuKeyCloses"))       MenuKeyCloses      = atoi(Value);
  else if (!strcasecmp(Name, "MarkInstantRecord"))   MarkInstantRecord  = atoi(Value);
  else if (!strcasecmp(Name, "NameInstantRecord"))   Utf8Strn0Cpy(NameInstantRecord, Value, MaxFileName);
  else if (!strcasecmp(Name, "InstantRecordTime"))   InstantRecordTime  = atoi(Value);
  else if (!strcasecmp(Name, "LnbSLOF"))             LnbSLOF            = atoi(Value);
  else if (!strcasecmp(Name, "LnbFrequLo"))          LnbFrequLo         = atoi(Value);
  else if (!strcasecmp(Name, "LnbFrequHi"))          LnbFrequHi         = atoi(Value);
  else if (!strcasecmp(Name, "DiSEqC"))              DiSEqC             = atoi(Value);
  else if (!strcasecmp(Name, "SetSystemTime"))       SetSystemTime      = atoi(Value);
  else if (!strcasecmp(Name, "TimeSource"))          TimeSource         = cSource::FromString(Value);
  else if (!strcasecmp(Name, "TimeTransponder"))     TimeTransponder    = atoi(Value);
  else if (!strcasecmp(Name, "MarginStart"))         MarginStart        = atoi(Value);
  else if (!strcasecmp(Name, "MarginStop"))          MarginStop         = atoi(Value);
  else if (!strcasecmp(Name, "AudioLanguages"))      return ParseLanguages(Value, AudioLanguages);
  else if (!strcasecmp(Name, "DisplaySubtitles"))    DisplaySubtitles   = atoi(Value);
  else if (!strcasecmp(Name, "SubtitleLanguages"))   return ParseLanguages(Value, SubtitleLanguages);
  else if (!strcasecmp(Name, "SubtitleOffset"))      SubtitleOffset     = atoi(Value);
  else if (!strcasecmp(Name, "SubtitleFgTransparency")) SubtitleFgTransparency = atoi(Value);
  else if (!strcasecmp(Name, "SubtitleBgTransparency")) SubtitleBgTransparency = atoi(Value);
  else if (!strcasecmp(Name, "EPGLanguages"))        return ParseLanguages(Value, EPGLanguages);
  else if (!strcasecmp(Name, "EPGScanTimeout"))      EPGScanTimeout     = atoi(Value);
  else if (!strcasecmp(Name, "EPGBugfixLevel"))      EPGBugfixLevel     = atoi(Value);
  else if (!strcasecmp(Name, "EPGLinger"))           EPGLinger          = atoi(Value);
  else if (!strcasecmp(Name, "SVDRPTimeout"))        SVDRPTimeout       = atoi(Value);
  else if (!strcasecmp(Name, "ZapTimeout"))          ZapTimeout         = atoi(Value);
  else if (!strcasecmp(Name, "ChannelEntryTimeout")) ChannelEntryTimeout= atoi(Value);
  else if (!strcasecmp(Name, "PrimaryLimit"))        PrimaryLimit       = atoi(Value);
  else if (!strcasecmp(Name, "DefaultPriority"))     DefaultPriority    = atoi(Value);
  else if (!strcasecmp(Name, "DefaultLifetime"))     DefaultLifetime    = atoi(Value);
  else if (!strcasecmp(Name, "PausePriority"))       PausePriority      = atoi(Value);
  else if (!strcasecmp(Name, "PauseLifetime"))       PauseLifetime      = atoi(Value);
  else if (!strcasecmp(Name, "UseSubtitle"))         UseSubtitle        = atoi(Value);
  else if (!strcasecmp(Name, "UseVps"))              UseVps             = atoi(Value);
  else if (!strcasecmp(Name, "VpsMargin"))           VpsMargin          = atoi(Value);
  else if (!strcasecmp(Name, "RecordingDirs"))       RecordingDirs      = atoi(Value);
  else if (!strcasecmp(Name, "VideoDisplayFormat"))  VideoDisplayFormat = atoi(Value);
  else if (!strcasecmp(Name, "VideoFormat"))         VideoFormat        = atoi(Value);
  else if (!strcasecmp(Name, "UpdateChannels"))      UpdateChannels     = atoi(Value);
  else if (!strcasecmp(Name, "UseDolbyDigital"))     UseDolbyDigital    = atoi(Value);
#ifdef USE_DOLBYINREC
  else if (!strcasecmp(Name, "UseDolbyInRecordings")) UseDolbyInRecordings = atoi(Value);
#endif /* DOLBYINREC */
#ifdef USE_DVBSETUP
  else if (!strcasecmp(Name, "DolbyTransferFix"))    DolbyTransferFix   = atoi(Value);
  else if (!strcasecmp(Name, "NoQamOnDecoder"))      NoQamOnDecoder     = atoi(Value);
  else if (!strcasecmp(Name, "TurnOffPrimary"))      TurnOffPrimary     = atoi(Value);
#endif /* DVBSETUP */
#ifdef USE_SYNCEARLY
  else if (!strcasecmp(Name, "UseSyncEarlyPatch"))   UseSyncEarlyPatch  = atoi(Value);
#endif /* SYNCEARLY */
  else if (!strcasecmp(Name, "ChannelInfoPos"))      ChannelInfoPos     = atoi(Value);
  else if (!strcasecmp(Name, "ChannelInfoTime"))     ChannelInfoTime    = atoi(Value);
  else if (!strcasecmp(Name, "OSDLeft"))             OSDLeft            = atoi(Value);
  else if (!strcasecmp(Name, "OSDTop"))              OSDTop             = atoi(Value);
  else if (!strcasecmp(Name, "OSDWidth"))          { OSDWidth           = atoi(Value); if (OSDWidth  < 100) OSDWidth  *= 12; OSDWidth &= ~0x07; } // OSD width must be a multiple of 8
  else if (!strcasecmp(Name, "OSDHeight"))         { OSDHeight          = atoi(Value); if (OSDHeight < 100) OSDHeight *= 27; }
  else if (!strcasecmp(Name, "OSDMessageTime"))      OSDMessageTime     = atoi(Value);
  else if (!strcasecmp(Name, "UseSmallFont"))        UseSmallFont       = atoi(Value);
  else if (!strcasecmp(Name, "AntiAlias"))           AntiAlias          = atoi(Value);
  else if (!strcasecmp(Name, "FontOsd"))             Utf8Strn0Cpy(FontOsd, Value, MAXFONTNAME);
  else if (!strcasecmp(Name, "FontSml"))             Utf8Strn0Cpy(FontSml, Value, MAXFONTNAME);
  else if (!strcasecmp(Name, "FontFix"))             Utf8Strn0Cpy(FontFix, Value, MAXFONTNAME);
  else if (!strcasecmp(Name, "FontOsdSize"))         FontOsdSize        = atoi(Value);
  else if (!strcasecmp(Name, "FontSmlSize"))         FontSmlSize        = atoi(Value);
  else if (!strcasecmp(Name, "FontFixSize"))         FontFixSize        = atoi(Value);
  else if (!strcasecmp(Name, "MaxVideoFileSize"))    MaxVideoFileSize   = atoi(Value);
#ifdef USE_HARDLINKCUTTER
  else if (!strcasecmp(Name, "MaxRecordingSize"))    MaxRecordingSize   = atoi(Value);
#endif /* HARDLINKCUTTER */
  else if (!strcasecmp(Name, "SplitEditedFiles"))    SplitEditedFiles   = atoi(Value);
#ifdef USE_HARDLINKCUTTER
  else if (!strcasecmp(Name, "HardLinkCutter"))      HardLinkCutter     = atoi(Value);
#endif /* HARDLINKCUTTER */
#ifdef USE_DELTIMESHIFTREC
  else if (!strcasecmp(Name, "DelTimeshiftRec"))     DelTimeshiftRec    = atoi(Value);
#endif /* DELTIMESHIFTREC */
  else if (!strcasecmp(Name, "MinEventTimeout"))     MinEventTimeout    = atoi(Value);
  else if (!strcasecmp(Name, "MinUserInactivity"))   MinUserInactivity  = atoi(Value);
  else if (!strcasecmp(Name, "NextWakeupTime"))      NextWakeupTime     = atoi(Value);
  else if (!strcasecmp(Name, "MultiSpeedMode"))      MultiSpeedMode     = atoi(Value);
  else if (!strcasecmp(Name, "ShowReplayMode"))      ShowReplayMode     = atoi(Value);
#ifdef USE_DDEPGENTRY
  else if (!strcasecmp(Name, "DoubleEpgTimeDelta"))  DoubleEpgTimeDelta = atoi(Value);
  else if (!strcasecmp(Name, "DoubleEpgAction"))     DoubleEpgAction    = atoi(Value);
  else if (!strcasecmp(Name, "MixEpgAction"))        MixEpgAction       = atoi(Value);
  else if (!strcasecmp(Name, "DisableVPS"))          DisableVPS         = atoi(Value);
#endif /* DDEPGENTRY */
  else if (!strcasecmp(Name, "ResumeID"))            ResumeID           = atoi(Value);
#ifdef USE_JUMPPLAY
  else if (!strcasecmp(Name, "JumpPlay"))            JumpPlay           = atoi(Value);
  else if (!strcasecmp(Name, "PlayJump"))            PlayJump           = atoi(Value);
  else if (!strcasecmp(Name, "PauseLastMark"))       PauseLastMark      = atoi(Value);
  else if (!strcasecmp(Name, "ReloadMarks"))         ReloadMarks        = atoi(Value);
#endif /* JUMPPLAY */
#ifdef USE_SOURCECAPS
  else if (!strcasecmp(Name, "SourceCaps"))          return ParseSourceCaps(Value);
#endif /* SOURCECAPS */
  else if (!strcasecmp(Name, "CurrentChannel"))      CurrentChannel     = atoi(Value);
  else if (!strcasecmp(Name, "CurrentVolume"))       CurrentVolume      = atoi(Value);
  else if (!strcasecmp(Name, "CurrentDolby"))        CurrentDolby       = atoi(Value);
  else if (!strcasecmp(Name, "InitialChannel"))      InitialChannel     = atoi(Value);
  else if (!strcasecmp(Name, "InitialVolume"))       InitialVolume      = atoi(Value);
#ifdef USE_VOLCTRL
  else if (!strcasecmp(Name, "LRVolumeControl"))     LRVolumeControl    = atoi(Value);
  else if (!strcasecmp(Name, "LRChannelGroups"))     LRChannelGroups    = atoi(Value);
  else if (!strcasecmp(Name, "LRForwardRewind"))     LRForwardRewind    = atoi(Value);
#endif /* VOLCTRL */
  else if (!strcasecmp(Name, "EmergencyExit"))       EmergencyExit      = atoi(Value);
#ifdef USE_NOEPG
  else if (!strcasecmp(Name, "noEPGMode"))           noEPGMode          = atoi(Value);
  else if (!strcasecmp(Name, "noEPGList")) {
     free(noEPGList);
     noEPGList=strdup(Value ? Value : "");
     }
#endif /* NOEPG */
#ifdef USE_LIRCSETTINGS
  else if (!strcasecmp(Name, "LircRepeatDelay"))     LircRepeatDelay    = atoi(Value);
  else if (!strcasecmp(Name, "LircRepeatFreq"))      LircRepeatFreq     = atoi(Value);
  else if (!strcasecmp(Name, "LircRepeatTimeout"))   LircRepeatTimeout  = atoi(Value);
#endif /* LIRCSETTINGS */
#ifdef USE_LIEMIKUUTIO
  else if (!strcasecmp(Name, "ShowRecDate"))         ShowRecDate        = atoi(Value);
  else if (!strcasecmp(Name, "ShowRecTime"))         ShowRecTime        = atoi(Value);
  else if (!strcasecmp(Name, "ShowRecLength"))       ShowRecLength      = atoi(Value);
  else if (!strcasecmp(Name, "MainMenuTitle"))       MainMenuTitle      = atoi(Value);
  else if (!strcasecmp(Name, "CustomMainMenuTitle")) Utf8Strn0Cpy(CustomMainMenuTitle, Value, MaxTitleName);
  else if (!strcasecmp(Name, "ShowTimerStop"))       ShowTimerStop      = atoi(Value);
  else if (!strcasecmp(Name, "ShowProgressBar"))     ShowProgressBar    = atoi(Value);
  else if (!strcasecmp(Name, "MenuCmdPosition"))     MenuCmdPosition    = atoi(Value);
  else if (!strcasecmp(Name, "JumpSeconds"))         JumpSeconds        = atoi(Value);
  else if (!strcasecmp(Name, "JumpSecondsSlow"))     JumpSecondsSlow    = atoi(Value);
#endif /* LIEMIKUUTIO */
#ifdef USE_SORTRECORDS
  else if (!strcasecmp(Name, "RecordingsSortMode"))  RecordingsSortMode = atoi(Value);
  else if (!strcasecmp(Name, "RecordingsSortDirsFirst")) RecordingsSortDirsFirst = atoi(Value);
#endif /* SORTRECORDS */
#ifdef USE_CUTTERQUEUE
  else if (!strcasecmp(Name, "CutterAutoDelete"))    CutterAutoDelete   = atoi(Value);
#endif /* CUTTERQUEUE */
#ifdef USE_LIVEBUFFER
  else if (!strcasecmp(Name, "LiveBuffer"))          LiveBuffer         = atoi(Value);
  else if (!strcasecmp(Name, "KeepPaused"))          KeepPaused         = atoi(Value);
  else if (!strcasecmp(Name, "LiveBufferSize"))      LiveBufferSize     = atoi(Value);
  else if (!strcasecmp(Name, "InRAM"))               InRAM              = atoi(Value);
  else if (!strcasecmp(Name, "MemBufSize"))          MemBufSize         = atoi(Value);
  else if (!strcasecmp(Name, "ExtendBuffer"))        ExtendBuffer       = atoi(Value);
#endif /* LIVEBUFFER */
#ifdef USE_DVDARCHIVE
  else if (!strcasecmp(Name, "DvdDisplayMode"))      DvdDisplayMode     = atoi(Value);
  else if (!strcasecmp(Name, "DvdDisplayZeros"))     DvdDisplayZeros    = atoi(Value);
  else if (!strcasecmp(Name, "DvdTrayMode"))         DvdTrayMode        = atoi(Value);
  else if (!strcasecmp(Name, "DvdSpeedLimit"))       DvdSpeedLimit      = atoi(Value);
#endif /* DVDARCHIVE */
#ifdef USE_DVLVIDPREFER
  else if (strcasecmp(Name, "UseVidPrefer") == 0)    UseVidPrefer       = atoi(Value);
  else if (strcasecmp(Name, "nVidPrefer") == 0)      nVidPrefer         = atoi(Value);
  else if (strstr(Name, "VidPrefer") == Name) {
     char *x = (char *)&Name[ strlen(Name) - 1 ];
     int vN;

     if (isdigit(*x) != 0) {
        while (isdigit(*x) != 0)
              x--;
        x++;
        }

     vN = atoi(x);
     if (vN < DVLVIDPREFER_MAX) {
        if (strstr(Name, "VidPreferPrio") == Name) {
           VidPreferPrio[ vN ] = atoi(Value);
           if (VidPreferPrio[ vN ] > 99)
              VidPreferPrio[ vN ] = 99;
           }
        else if (strstr(Name, "VidPreferSize") == Name) {
           VidPreferSize[ vN ] = atoi(Value);
           }
        else
           return false;
        }
     }
#endif /* DVLVIDPREFER */
#ifdef USE_DVLFRIENDLYFNAMES
  else if (strcasecmp(Name, "UseFriendlyFNames") == 0) UseFriendlyFNames = atoi(Value);
#endif /* DVLFRIENDLYFNAMES */
  else
#ifdef USE_LNBSHARE
  if (!strcasecmp(Name, "VerboseLNBlog")) VerboseLNBlog = atoi(Value);
  else {
     char tmp[20];
     bool result = false;
     for (int i = 1; i <= MAXDEVICES; i++) {
         sprintf(tmp, "Card%dusesLNBnr", i);
         if (!strcasecmp(Name, tmp)) {
            CardUsesLNBnr[i - 1] = atoi(Value);
            result = true;
            }
         }
     return result;
  }
#else
     return false;
#endif /* LNBSHARE */
  return true;
}

bool cSetup::Save(void)
{
  Store("OSDLanguage",        OSDLanguage);
  Store("OSDSkin",            OSDSkin);
  Store("OSDTheme",           OSDTheme);
#ifdef USE_WAREAGLEICON
  Store("WarEagleIcons",      WarEagleIcons);
#endif /* WAREAGLEICON */
#ifdef USE_VALIDINPUT
  Store("ShowValidInput",     ShowValidInput);
#endif /* VALIDINPUT */
  Store("PrimaryDVB",         PrimaryDVB);
  Store("ShowInfoOnChSwitch", ShowInfoOnChSwitch);
  Store("TimeoutRequChInfo",  TimeoutRequChInfo);
  Store("MenuScrollPage",     MenuScrollPage);
  Store("MenuScrollWrap",     MenuScrollWrap);
  Store("MenuKeyCloses",      MenuKeyCloses);
  Store("MarkInstantRecord",  MarkInstantRecord);
  Store("NameInstantRecord",  NameInstantRecord);
  Store("InstantRecordTime",  InstantRecordTime);
  Store("LnbSLOF",            LnbSLOF);
  Store("LnbFrequLo",         LnbFrequLo);
  Store("LnbFrequHi",         LnbFrequHi);
  Store("DiSEqC",             DiSEqC);
  Store("SetSystemTime",      SetSystemTime);
  Store("TimeSource",         cSource::ToString(TimeSource));
  Store("TimeTransponder",    TimeTransponder);
  Store("MarginStart",        MarginStart);
  Store("MarginStop",         MarginStop);
  StoreLanguages("AudioLanguages", AudioLanguages);
  Store("DisplaySubtitles",   DisplaySubtitles);
  StoreLanguages("SubtitleLanguages", SubtitleLanguages);
  Store("SubtitleOffset",     SubtitleOffset);
  Store("SubtitleFgTransparency", SubtitleFgTransparency);
  Store("SubtitleBgTransparency", SubtitleBgTransparency);
  StoreLanguages("EPGLanguages", EPGLanguages);
  Store("EPGScanTimeout",     EPGScanTimeout);
  Store("EPGBugfixLevel",     EPGBugfixLevel);
  Store("EPGLinger",          EPGLinger);
  Store("SVDRPTimeout",       SVDRPTimeout);
  Store("ZapTimeout",         ZapTimeout);
  Store("ChannelEntryTimeout",ChannelEntryTimeout);
  Store("PrimaryLimit",       PrimaryLimit);
  Store("DefaultPriority",    DefaultPriority);
  Store("DefaultLifetime",    DefaultLifetime);
  Store("PausePriority",      PausePriority);
  Store("PauseLifetime",      PauseLifetime);
  Store("UseSubtitle",        UseSubtitle);
  Store("UseVps",             UseVps);
  Store("VpsMargin",          VpsMargin);
  Store("RecordingDirs",      RecordingDirs);
  Store("VideoDisplayFormat", VideoDisplayFormat);
  Store("VideoFormat",        VideoFormat);
  Store("UpdateChannels",     UpdateChannels);
  Store("UseDolbyDigital",    UseDolbyDigital);
#ifdef USE_DOLBYINREC
  Store("UseDolbyInRecordings", UseDolbyInRecordings);
#endif /* DOLBYINREC */
#ifdef USE_DVBSETUP
  Store("DolbyTransferFix",   DolbyTransferFix);
  Store("NoQamOnDecoder",     NoQamOnDecoder);
  Store("TurnOffPrimary",     TurnOffPrimary);
#endif /* DVBSETUP */
#ifdef USE_SYNCEARLY
  Store("UseSyncEarlyPatch",  UseSyncEarlyPatch);
#endif /* SYNCEARLY */
  Store("ChannelInfoPos",     ChannelInfoPos);
  Store("ChannelInfoTime",    ChannelInfoTime);
  Store("OSDLeft",            OSDLeft);
  Store("OSDTop",             OSDTop);
  Store("OSDWidth",           OSDWidth);
  Store("OSDHeight",          OSDHeight);
  Store("OSDMessageTime",     OSDMessageTime);
  Store("UseSmallFont",       UseSmallFont);
  Store("AntiAlias",          AntiAlias);
  Store("FontOsd",            FontOsd);
  Store("FontSml",            FontSml);
  Store("FontFix",            FontFix);
  Store("FontOsdSize",        FontOsdSize);
  Store("FontSmlSize",        FontSmlSize);
  Store("FontFixSize",        FontFixSize);
  Store("MaxVideoFileSize",   MaxVideoFileSize);
#ifdef USE_HARDLINKCUTTER
  Store("MaxRecordingSize",   MaxRecordingSize);
#endif /* HARDLINKCUTTER */
  Store("SplitEditedFiles",   SplitEditedFiles);
#ifdef USE_HARDLINKCUTTER
  Store("HardLinkCutter",     HardLinkCutter);
#endif /* HARDLINKCUTTER */
#ifdef USE_DELTIMESHIFTREC
  Store("DelTimeshiftRec",    DelTimeshiftRec);
#endif /* DELTIMESHIFTREC */
  Store("MinEventTimeout",    MinEventTimeout);
  Store("MinUserInactivity",  MinUserInactivity);
  Store("NextWakeupTime",     NextWakeupTime);
#ifdef USE_DDEPGENTRY
  Store("DoubleEpgAction",    DoubleEpgAction);
  Store("MixEpgAction",       MixEpgAction);
  Store("DisableVPS",         DisableVPS);
  Store("DoubleEpgTimeDelta", DoubleEpgTimeDelta);
#endif /* DDEPGENTRY */
  Store("MultiSpeedMode",     MultiSpeedMode);
  Store("ShowReplayMode",     ShowReplayMode);
  Store("ResumeID",           ResumeID);
#ifdef USE_JUMPPLAY
  Store("JumpPlay",           JumpPlay);
  Store("PlayJump",           PlayJump);
  Store("PauseLastMark",      PauseLastMark);
  Store("ReloadMarks",        ReloadMarks);
#endif /* JUMPPLAY */
#ifdef USE_SOURCECAPS
  if (SourceCapsSet) StoreSourceCaps("SourceCaps");
#endif /* SOURCECAPS */
  Store("CurrentChannel",     CurrentChannel);
  Store("CurrentVolume",      CurrentVolume);
  Store("CurrentDolby",       CurrentDolby);
  Store("InitialChannel",     InitialChannel);
  Store("InitialVolume",      InitialVolume);
#ifdef USE_VOLCTRL
  Store("LRVolumeControl",    LRVolumeControl);
  Store("LRChannelGroups",    LRChannelGroups);
  Store("LRForwardRewind",    LRForwardRewind);
#endif /* VOLCTRL */
  Store("EmergencyExit",      EmergencyExit);
#ifdef USE_NOEPG
  Store("noEPGMode",          noEPGMode);
  Store("noEPGList",          noEPGList);
#endif /* NOEPG */
#ifdef USE_LIRCSETTINGS
  Store("LircRepeatDelay",    LircRepeatDelay);
  Store("LircRepeatFreq",     LircRepeatFreq);
  Store("LircRepeatTimeout",  LircRepeatTimeout);
#endif /* LIRCSETTINGS */
#ifdef USE_LIEMIKUUTIO
  Store("ShowRecDate",        ShowRecDate);
  Store("ShowRecTime",        ShowRecTime);
  Store("ShowRecLength",      ShowRecLength);
  Store("MainMenuTitle",      MainMenuTitle);
  Store("CustomMainMenuTitle",CustomMainMenuTitle);
  Store("ShowTimerStop",      ShowTimerStop);
  Store("ShowProgressBar",    ShowProgressBar);
  Store("MenuCmdPosition",    MenuCmdPosition);
  Store("JumpSeconds",        JumpSeconds);
  Store("JumpSecondsSlow",    JumpSecondsSlow);
#endif /* LIEMIKUUTIO */
#ifdef USE_SORTRECORDS
  Store("RecordingsSortMode", RecordingsSortMode);
  Store("RecordingsSortDirsFirst", RecordingsSortDirsFirst);
#endif /* SORTRECORDS */
#ifdef USE_CUTTERQUEUE
  Store("CutterAutoDelete",   CutterAutoDelete);
#endif /* CUTTERQUEUE */
#ifdef USE_LIVEBUFFER
  Store("LiveBuffer",         LiveBuffer);
  Store("KeepPaused",         KeepPaused);
  Store("LiveBufferSize",     LiveBufferSize);
  Store("InRAM",              InRAM);
  Store("MemBufSize",         MemBufSize);
  Store("ExtendBuffer",       ExtendBuffer);
#endif /* LIVEBUFFER */
#ifdef USE_DVDARCHIVE
  Store("DvdDisplayMode",     DvdDisplayMode);
  Store("DvdDisplayZeros",    DvdDisplayZeros);
  Store("DvdTrayMode",        DvdTrayMode);
  Store("DvdSpeedLimit",      DvdSpeedLimit);
#endif /* DVDARCHIVE */
#ifdef USE_LNBSHARE
  Store("VerboseLNBlog",      VerboseLNBlog);
  char tmp[20];
  if (cDevice::NumDevices() > 1) {
     for (int i = 1; i <= cDevice::NumDevices(); i++) {
         sprintf(tmp, "Card%dusesLNBnr", i);
         Store(tmp, CardUsesLNBnr[i - 1]);
         }
     }
#endif /* LNBSHARE */
#ifdef USE_DVLVIDPREFER
  Store ("UseVidPrefer",      UseVidPrefer);
  Store ("nVidPrefer",        nVidPrefer);

  char vidBuf[32];
  for (int zz = 0; zz < nVidPrefer; zz++) {
      sprintf(vidBuf, "VidPreferPrio%d", zz);
      Store (vidBuf, VidPreferPrio[zz]);
      sprintf(vidBuf, "VidPreferSize%d", zz);
      Store (vidBuf, VidPreferSize[zz]);
      }
#endif /* DVLVIDPREFER */
#ifdef USE_DVLFRIENDLYFNAMES
  Store ("UseFriendlyFNames", UseFriendlyFNames);
#endif /* DVLFRIENDLYFNAMES */

  Sort();

  if (cConfig<cSetupLine>::Save()) {
     isyslog("saved setup to %s", FileName());
#ifdef USE_DVDARCHIVE
     if (DvdDisplayMode >= 1) ::Recordings.Load();
#endif /* DVDARCHIVE */
     return true;
     }
  return false;
}
