diff options
-rw-r--r-- | CONTRIBUTORS | 10 | ||||
-rw-r--r-- | FORMATS | 27 | ||||
-rw-r--r-- | HISTORY | 39 | ||||
-rw-r--r-- | INSTALL | 5 | ||||
-rw-r--r-- | MANUAL | 16 | ||||
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | channels.conf | 2 | ||||
-rw-r--r-- | config.c | 158 | ||||
-rw-r--r-- | config.h | 35 | ||||
-rw-r--r-- | dvbapi.c | 17 | ||||
-rw-r--r-- | dvbapi.h | 3 | ||||
-rw-r--r-- | dvbosd.h | 3 | ||||
-rw-r--r-- | eit.c | 85 | ||||
-rw-r--r-- | gmon.out | bin | 0 -> 101224 bytes | |||
-rw-r--r-- | i18n.c | 11 | ||||
-rw-r--r-- | menu.c | 13 | ||||
-rw-r--r-- | recording.c | 31 | ||||
-rw-r--r-- | recording.h | 4 | ||||
-rw-r--r-- | remux.c | 16 | ||||
-rw-r--r-- | svdrp.c | 16 | ||||
-rw-r--r-- | svdrphosts.conf | 13 | ||||
-rw-r--r-- | tools.c | 23 | ||||
-rw-r--r-- | tools.h | 9 | ||||
-rw-r--r-- | vdr.c | 3 |
24 files changed, 427 insertions, 116 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 1d06173..e0b9ee1 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -137,6 +137,7 @@ Matjaz Thaler <matjaz.thaler@guest.arnes.si> Artur Skawina <skawina@geocities.com> for improving the font file generation in the Makefile + for pointing out a problem with the ERR macro defined by ncurses.h Werner Fink <werner@suse.de> for making I/O more robust by handling EINTR @@ -179,3 +180,12 @@ Lauri Pesonen <lauri.pesonen@firsthop.com> Sergei Haller <Sergei.Haller@math.uni-giessen.de> for fixing the LastActivity timestamp after a shutdown prompt + +Andreas Gebel <andreas@xcapenet.de> + for his help in keeping 'channels.conf' up to date + +Davide Achilli <davide@objsystem.it> + for pointing out a bug in error handling while establishing an SVDRP connection + +Michael Paar <mpaar@uumail.de> + for enabling recording of radio channels @@ -24,7 +24,7 @@ Video Disk Recorder File Formats - Polarization (one of 'h', 'H', 'v', 'V') ** - Diseqc number ** - Symbol rate *** - - Video PID + - Video PID (set to '0' for radio channels, '1' for encrypted radio channels) - Audio PID (either one number, or two, separated by a comma) If this channel also carries Dolby Digital sound, the Dolby PIDs follow the audio PIDs, separated by a semicolon, as in "...:101,102;103,104:..." @@ -72,6 +72,11 @@ Video Disk Recorder File Formats any ':' characters, these have to be replaced with '|'. If the name shall contain subdirectories, these have to be delimited by '~' (since the '/' character may be part of a regular programme name). + The special keywords TITLE and EPISODE, if present, will be replaced + with the title and episode information from the EPG data at the time of + recording (if that data is available). If at the time of recording either + of these cannot be determined, TITLE will default to the channel name, and + EPISODE will default to a blank. - Summary (any newline characters in the summary have to be replaced with '|'; the summary may contain ':' characters) @@ -111,6 +116,26 @@ Video Disk Recorder File Formats 1..9, the command can be selected directly by pressing the respective numerical key on the remote control. +* svdrphosts.conf + + This file contains the IP numbers of all hosts that are allowed to access the + SVDRP port. + + Each line contains one IP number in the format + + IP-Address[/Netmask] + + where 'IP-Address' is the address of a host or a network in the usual dot + separated notation (as in 192.168.100.1). If the optional 'Netmask' is given + only the given number of bits of 'IP-Address' are taken into account. This + allows you to grant SVDRP access to all hosts of an entire network. 'Netmask' + can be any integer from 1 to 32. The special value of 0 is only accepted if + the 'IP-Address' is 0.0.0.0, because this will give access to any host (USE + THIS WITH CARE!). + + Everything following (and including) a '#' character is considered to be + comment. + * marks.vdr This file (if present in a recording directory) contains the editing marks @@ -930,3 +930,42 @@ Video Disk Recorder Revision History 2002-01-30: Version 0.99pre4 - Fixed handling improperly formatted EIT data (thanks to Rolf Hakenes). + +2002-02-03: Version 0.99pre5 + +- Updated channel settings for 'N24' (thanks to Andreas Gebel). +- Fixed handling hierarchical recordings menu in case of directories starting + with the same sequence of characters. +- Fixed handling timers on the 29th, 30th or 31st of a month in case the next + month has less than 31 days. +- Added a description of the sort order of individual episodes in the + recordings menu to the MANUAL. +- Removed the EPG bugfix for "Title / Subtitle" cleanup. Apparently Pro-7 has + finally stopped this nasty habit. +- Added some EPG bugfix statistics (printed to the log file every time the EPG + data is cleaned up and when VDR is terminated). Maybe somebody in charge of + the EPG data at the listed channels will read this and take the necessary + actions to fix these things... +- Changed the [dei]syslog macros in tools.h to use a variable number of args, + thus making it safe to use them in nested 'if/else' statements. +- Fixed error handling in establishing an SVDRP connection (thanks to Davide + Achilli) for pointing this out). +- The new configuration file 'svdrphosts.conf' is now used to define which + hosts may access the SVDRP port (by default only 'localhost' has access). + See FORMATS for details. +- The special keywords TITLE and EPISODE can now be used in timer file names + (see MANUAL and FORMATS for details). +- The new setup parameter NameInstantRecord can be used to define how an + instant recording will be named (see MANUAL for details). +- When looking for the EPG record of the timer that starts a recording, now + that record is taken which covers the time calculated as + 'start + (Setup.MarginStart * 2) + 1)' in order to have a better chance of + hitting the right record in case of an instant recording. Timers that start + further in the future should always be programmed via the "Schedules" menu. +- The special VPIDs '0' and '1' are now used to enable recording radio channels. + Actually '0' should be enough, but '1' must be used with encrypted channels + (driver bug?). Note, though, that since VDR is mainly a *video recorder*, some + features like, e. g., the progress display, may not work as expected with + radio recordings. Thanks to Michael Paar. +- Fixed a problem with the ERR macro defined by ncurses.h (thanks to Artur + Skawina). @@ -81,6 +81,11 @@ WARNING: DUE TO THE OPEN SVDRP PORT THIS PROGRAM MAY CONSTITUTE A A CONTROLLED ENVIRONMENT, YOU MAY WANT TO DISABLE SVDRP BY USING '--port=0'! +The file 'svdrphosts.conf' can be used to define which hosts are allowed +to access the SVDRP port. By default only localhost (127.0.0.1) is granted +access. If you want to give other hosts access to your SVDRP port you need to +add their IP numbers to 'svdrphosts.conf'. + If the program shall run as a daemon, use the --daemon option. This will completely detach it from the terminal and will continue as a background process. @@ -166,6 +166,14 @@ Video Disk Recorder User's Manual that directory (and any possible subdirectory thereof) as well as the total number of new recordings (as opposed to a recording's entry, which displays the date and time of the recording). + + If the setup parameter UseSubtitle was turned on when a recording took place, + VDR adds the "subtitle" (which is usually the name of the episode in case of + a series) to the recording's name. The "Recordings" menu then displays all + recordings of a periodic timer in chronological order, since these are + usually the individual episodes of a series, which you may want to view in + the order in which they were broadcast. + Playback can be stopped via the "Main" menu by selecting "Stop replaying", or by pressing the "Blue" button outside the menu. A previously stopped playback session can be resumed by pressing the "Blue" @@ -377,6 +385,14 @@ Video Disk Recorder User's Manual 0 = instant recordings will not be marked 1 = instant recordings will be marked. + NameInstantRecord = TITLE-EPISODE + Defines how to name an instant recording. If the keywords + TITLE and/or EPISODE are present, they will be replaced + with the title and episode information from the EPG data + at the time of recording (if that data is available). + If this parameter is empty, the channel name will be used + by default. + LnbSLOF = 11700 The switching frequency (in MHz) between low and high LOF LnbFrequLo = 9750 The LNB's low and high local oscillator frequencies (in MHz) LnbFrequHi = 10600 (these have no meaning for DVB-C receivers) @@ -4,7 +4,7 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.29 2002/01/13 16:57:27 kls Exp $ +# $Id: Makefile 1.30 2002/02/01 14:40:09 kls Exp $ .DELETE_ON_ERROR: @@ -105,7 +105,7 @@ $(DTVLIB) $(DTVDIR)/libdtv.h: clean: make -C $(AC3DIR) clean make -C $(DTVDIR) clean - -rm -f $(OBJS) $(DEPFILE) vdr genfontfile genfontfile.o core *~ + -rm -f $(OBJS) $(DEPFILE) vdr genfontfile genfontfile.o core* *~ fontclean: -rm -f fontfix.c fontosd.c CLEAN: clean fontclean diff --git a/channels.conf b/channels.conf index a2bd32f..87796ae 100644 --- a/channels.conf +++ b/channels.conf @@ -96,7 +96,7 @@ Cinedom 5A:11758:h:0:27500:1279:1280:0:3:194 Cinedom 5B:11720:h:0:27500:1791:1792:0:3:177 Cinedom 5C:12070:h:0:27500:1023:1024:0:3:186 :Beta Digital -N24:11914:H:0:27500:255:256:8191:3:52 +N24:12480:v:0:27500:2047:2048:0:0:47 CNBC:11954:h:0:27500:510:520:0:0:28010 Liberty TV.com:12610:V:0:22000:941:943,942:0:0:12199 :PW Erotic @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.77 2002/01/19 16:06:42 kls Exp $ + * $Id: config.c 1.82 2002/02/03 15:25:44 kls Exp $ */ #include "config.h" @@ -296,9 +296,8 @@ bool cChannel::Switch(cDvbApi *DvbApi, bool Log) if (!DvbApi) DvbApi = cDvbApi::PrimaryDvbApi; if (!DvbApi->Recording() && !groupSep) { - if (Log) { + if (Log) isyslog(LOG_INFO, "switching to channel %d", number); - } for (int i = 3; i--;) { switch (DvbApi->SetChannel(number, frequency, polarization, diseqc, srate, vpid, apid1, apid2, dpid1, dpid2, tpid, ca, pnr)) { case scrOk: return true; @@ -341,7 +340,7 @@ cTimer::cTimer(bool Instant) *file = 0; summary = NULL; if (Instant && ch) - snprintf(file, sizeof(file), "%s%s", Setup.MarkInstantRecord ? "@" : "", ch->name); + snprintf(file, sizeof(file), "%s%s", Setup.MarkInstantRecord ? "@" : "", *Setup.NameInstantRecord ? Setup.NameInstantRecord : ch->name); } cTimer::cTimer(const cEventInfo *EventInfo) @@ -540,6 +539,13 @@ time_t cTimer::SetTime(time_t t, int SecondsFromMidnight) return mktime(&tm); } +char *cTimer::SetFile(const char *File) +{ + if (!isempty(File)) + strn0cpy(file, File, sizeof(file)); + return file; +} + bool cTimer::Matches(time_t t) { startTime = stopTime = 0; @@ -551,7 +557,7 @@ bool cTimer::Matches(time_t t) if (length < 0) length += SECSINDAY; - int DaysToCheck = IsSingleEvent() ? 31 : 7; + int DaysToCheck = IsSingleEvent() ? 61 : 7; // 61 to handle months with 31/30/31 for (int i = -1; i <= DaysToCheck; i++) { time_t t0 = IncDay(t, i); if (DayMatches(t0)) { @@ -647,6 +653,40 @@ const char *cCommand::Execute(void) return result; } +// -- 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 && !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); + } + 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; +} + // -- cKeys ------------------------------------------------------------------ cKeys Keys; @@ -659,9 +699,9 @@ cCommands Commands; cChannels Channels; -bool cChannels::Load(const char *FileName) +bool cChannels::Load(const char *FileName, bool AllowComments) { - if (cConfig<cChannel>::Load(FileName)) { + if (cConfig<cChannel>::Load(FileName, AllowComments)) { ReNumber(); return true; } @@ -779,6 +819,21 @@ cTimer *cTimers::GetNextActiveTimer(void) return t0; } +// -- 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; +} + // -- cSetup ----------------------------------------------------------------- cSetup Setup; @@ -792,6 +847,7 @@ cSetup::cSetup(void) ShowInfoOnChSwitch = 1; MenuScrollPage = 1; MarkInstantRecord = 1; + strcpy(NameInstantRecord, "TITLE-EPISODE"); LnbSLOF = 11700; LnbFrequLo = 9750; LnbFrequHi = 10600; @@ -825,47 +881,51 @@ cSetup::cSetup(void) 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, "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, "MarginStart")) MarginStart = atoi(Value); - else if (!strcasecmp(Name, "MarginStop")) MarginStop = atoi(Value); - else if (!strcasecmp(Name, "EPGScanTimeout")) EPGScanTimeout = atoi(Value); - else if (!strcasecmp(Name, "EPGBugfixLevel")) EPGBugfixLevel = atoi(Value); - else if (!strcasecmp(Name, "SVDRPTimeout")) SVDRPTimeout = atoi(Value); - else if (!strcasecmp(Name, "SortTimers")) SortTimers = 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, "UseSubtitle")) UseSubtitle = atoi(Value); - else if (!strcasecmp(Name, "RecordingDirs")) RecordingDirs = atoi(Value); - else if (!strcasecmp(Name, "VideoFormat")) VideoFormat = atoi(Value); - else if (!strcasecmp(Name, "ChannelInfoPos")) ChannelInfoPos = atoi(Value); - else if (!strcasecmp(Name, "OSDwidth")) OSDwidth = atoi(Value); - else if (!strcasecmp(Name, "OSDheight")) OSDheight = atoi(Value); - else if (!strcasecmp(Name, "OSDMessageTime")) OSDMessageTime = atoi(Value); - else if (!strcasecmp(Name, "MaxVideoFileSize")) MaxVideoFileSize = atoi(Value); - else if (!strcasecmp(Name, "SplitEditedFiles")) SplitEditedFiles = atoi(Value); - else if (!strcasecmp(Name, "MinEventTimeout")) MinEventTimeout = atoi(Value); - else if (!strcasecmp(Name, "MinUserInactivity")) MinUserInactivity = atoi(Value); - else if (!strcasecmp(Name, "MultiSpeedMode")) MultiSpeedMode = atoi(Value); - else if (!strcasecmp(Name, "ShowReplayMode")) ShowReplayMode = atoi(Value); - else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value); - else if (!strcasecmp(Name, "CurrentVolume")) CurrentVolume = atoi(Value); - else - return false; - return true; + char *p = strchr(s, '='); + if (p) { + *p = 0; + char *Name = compactspace(s); + char *Value = compactspace(p + 1); + 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, "NameInstantRecord")) strn0cpy(NameInstantRecord, Value, MaxFileName); + 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, "MarginStart")) MarginStart = atoi(Value); + else if (!strcasecmp(Name, "MarginStop")) MarginStop = atoi(Value); + else if (!strcasecmp(Name, "EPGScanTimeout")) EPGScanTimeout = atoi(Value); + else if (!strcasecmp(Name, "EPGBugfixLevel")) EPGBugfixLevel = atoi(Value); + else if (!strcasecmp(Name, "SVDRPTimeout")) SVDRPTimeout = atoi(Value); + else if (!strcasecmp(Name, "SortTimers")) SortTimers = 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, "UseSubtitle")) UseSubtitle = atoi(Value); + else if (!strcasecmp(Name, "RecordingDirs")) RecordingDirs = atoi(Value); + else if (!strcasecmp(Name, "VideoFormat")) VideoFormat = atoi(Value); + else if (!strcasecmp(Name, "ChannelInfoPos")) ChannelInfoPos = atoi(Value); + else if (!strcasecmp(Name, "OSDwidth")) OSDwidth = atoi(Value); + else if (!strcasecmp(Name, "OSDheight")) OSDheight = atoi(Value); + else if (!strcasecmp(Name, "OSDMessageTime")) OSDMessageTime = atoi(Value); + else if (!strcasecmp(Name, "MaxVideoFileSize")) MaxVideoFileSize = atoi(Value); + else if (!strcasecmp(Name, "SplitEditedFiles")) SplitEditedFiles = atoi(Value); + else if (!strcasecmp(Name, "MinEventTimeout")) MinEventTimeout = atoi(Value); + else if (!strcasecmp(Name, "MinUserInactivity")) MinUserInactivity = atoi(Value); + else if (!strcasecmp(Name, "MultiSpeedMode")) MultiSpeedMode = atoi(Value); + else if (!strcasecmp(Name, "ShowReplayMode")) ShowReplayMode = atoi(Value); + else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value); + else if (!strcasecmp(Name, "CurrentVolume")) CurrentVolume = atoi(Value); + else + return false; + return true; + } } return false; } @@ -882,6 +942,7 @@ bool cSetup::Load(const char *FileName) bool result = true; while (fgets(buffer, sizeof(buffer), f) > 0) { line++; + stripspace(buffer); if (!isempty(buffer)) { if (*buffer != '#' && !Parse(buffer)) { esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line); @@ -911,6 +972,7 @@ bool cSetup::Save(const char *FileName) fprintf(f, "ShowInfoOnChSwitch = %d\n", ShowInfoOnChSwitch); fprintf(f, "MenuScrollPage = %d\n", MenuScrollPage); fprintf(f, "MarkInstantRecord = %d\n", MarkInstantRecord); + fprintf(f, "NameInstantRecord = %s\n", NameInstantRecord); fprintf(f, "LnbSLOF = %d\n", LnbSLOF); fprintf(f, "LnbFrequLo = %d\n", LnbFrequLo); fprintf(f, "LnbFrequHi = %d\n", LnbFrequHi); @@ -4,12 +4,13 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.90 2002/01/30 18:30:03 kls Exp $ + * $Id: config.h 1.93 2002/02/03 15:16:21 kls Exp $ */ #ifndef __CONFIG_H #define __CONFIG_H +#include <arpa/inet.h> #include <stdio.h> #include <string.h> #include <time.h> @@ -18,7 +19,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "0.99pre4" +#define VDRVERSION "0.99pre5" #define MAXPRIORITY 99 #define MAXLIFETIME 99 @@ -65,6 +66,8 @@ enum eKeys { // "Up" and "Down" must be the first two keys! #define ISRAWKEY(k) ((k) != kNone && ((k) & k_Flags) == 0) #define NORMALKEY(k) (eKeys((k) & ~k_Repeat)) +#define MaxFileName 256 + struct tKey { eKeys type; char *name; @@ -122,7 +125,6 @@ private: static char *buffer; static const char *ToText(cTimer *Timer); public: - enum { MaxFileName = 256 }; bool recording, pending; int active; int channel; @@ -148,6 +150,7 @@ public: bool DayMatches(time_t t); time_t IncDay(time_t t, int Days); time_t SetTime(time_t t, int SecondsFromMidnight); + char *SetFile(const char *File); bool Matches(time_t t = 0); time_t StartTime(void); time_t StopTime(void); @@ -171,6 +174,16 @@ public: const char *Execute(void); }; +class cSVDRPhost : public cListObject { +private: + struct in_addr addr; + in_addr_t mask; +public: + cSVDRPhost(void); + bool Parse(const char *s); + bool Accepts(in_addr_t Address); + }; + template<class T> class cConfig : public cList<T> { private: char *fileName; @@ -182,7 +195,7 @@ private: public: cConfig(void) { fileName = NULL; } virtual ~cConfig() { delete fileName; } - virtual bool Load(const char *FileName) + virtual bool Load(const char *FileName, bool AllowComments = false) { Clear(); fileName = strdup(FileName); @@ -196,6 +209,11 @@ public: result = true; while (fgets(buffer, sizeof(buffer), f) > 0) { line++; + if (AllowComments) { + char *p = strchr(buffer, '#'); + if (p) + *p = 0; + } if (!isempty(buffer)) { T *l = new T; if (l->Parse(buffer)) @@ -242,7 +260,7 @@ protected: int maxNumber; public: cChannels(void) { maxNumber = 0; } - virtual bool Load(const char *FileName); + virtual bool Load(const char *FileName, bool AllowComments = false); int GetNextGroup(int Idx); // Get next channel group int GetPrevGroup(int Idx); // Get previous channel group int GetNextNormal(int Idx); // Get next normal channel (not group) @@ -263,10 +281,16 @@ public: class cCommands : public cConfig<cCommand> {}; +class cSVDRPhosts : public cConfig<cSVDRPhost> { +public: + bool Acceptable(in_addr_t Address); + }; + extern cChannels Channels; extern cTimers Timers; extern cKeys Keys; extern cCommands Commands; +extern cSVDRPhosts SVDRPhosts; class cSetup { private: @@ -279,6 +303,7 @@ public: int ShowInfoOnChSwitch; int MenuScrollPage; int MarkInstantRecord; + char NameInstantRecord[MaxFileName]; int LnbSLOF; int LnbFrequLo; int LnbFrequHi; @@ -7,7 +7,7 @@ * DVD support initially written by Andreas Schultz <aschultz@warp10.net> * based on dvdplayer-0.5 by Matjaz Thaler <matjaz.thaler@guest.arnes.si> * - * $Id: dvbapi.c 1.146 2002/01/26 15:39:48 kls Exp $ + * $Id: dvbapi.c 1.147 2002/02/02 13:04:00 kls Exp $ */ //#define DVDDEBUG 1 @@ -548,9 +548,8 @@ void cRecordBuffer::Input(void) } else if (r < 0) { if (FATALERRNO) { - if (errno == EBUFFEROVERFLOW) { // this error code is not defined in the library + if (errno == EBUFFEROVERFLOW) // this error code is not defined in the library esyslog(LOG_ERR, "ERROR (%s,%d): DVB driver buffer overflow", __FILE__, __LINE__); - } else { LOG_ERROR; break; @@ -1064,9 +1063,8 @@ cReplayBuffer::cReplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, const return; // Create the index file: index = new cIndexFile(FileName, false); - if (!index) { + if (!index) esyslog(LOG_ERR, "ERROR: can't allocate index"); - } else if (!index->Ok()) { delete index; index = NULL; @@ -2251,9 +2249,8 @@ void cTransferBuffer::Input(void) } else if (r < 0) { if (FATALERRNO) { - if (errno == EBUFFEROVERFLOW) { // this error code is not defined in the library + if (errno == EBUFFEROVERFLOW) // this error code is not defined in the library esyslog(LOG_ERR, "ERROR (%s,%d): DVB driver buffer overflow", __FILE__, __LINE__); - } else { LOG_ERROR; break; @@ -2719,12 +2716,10 @@ bool cDvbApi::Init(void) } } PrimaryDvbApi = dvbApi[0]; - if (NumDvbApis > 0) { + if (NumDvbApis > 0) isyslog(LOG_INFO, "found %d video device%s", NumDvbApis, NumDvbApis > 1 ? "s" : ""); - } // need braces because of isyslog-macro - else { + else esyslog(LOG_ERR, "ERROR: no video device found, giving up!"); - } return NumDvbApis > 0; } @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.60 2002/01/26 13:01:16 kls Exp $ + * $Id: dvbapi.h 1.61 2002/02/03 16:43:38 kls Exp $ */ #ifndef __DVBAPI_H @@ -12,6 +12,7 @@ #if defined(DEBUG_OSD) || defined(REMOTE_KBD) #include <ncurses.h> +#undef ERR //XXX ncurses defines this - but this clashes with newer system header files #endif #include <stdlib.h> // FIXME: this is apparently necessary for the ost/... header files // FIXME: shouldn't every header file include ALL the other header @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbosd.h 1.9 2001/12/09 15:11:05 kls Exp $ + * $Id: dvbosd.h 1.10 2002/02/03 16:43:50 kls Exp $ */ #ifndef __DVBOSD_H @@ -12,6 +12,7 @@ #if defined(DEBUG_OSD) || defined(REMOTE_KBD) #include <ncurses.h> +#undef ERR //XXX ncurses defines this - but this clashes with newer system header files #endif #include <ost/osd.h> #include <stdio.h> @@ -16,7 +16,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.c 1.31 2002/01/13 16:14:31 kls Exp $ + * $Id: eit.c 1.33 2002/02/02 12:12:26 kls Exp $ ***************************************************************************/ #include "eit.h" @@ -352,6 +352,64 @@ void cEventInfo::Dump(FILE *f, const char *Prefix) const } } +#define MAXEPGBUGFIXSTATS 6 +#define MAXEPGBUGFIXCHANS 50 +struct tEpgBugFixStats { + int hits; + int n; + unsigned short serviceIDs[MAXEPGBUGFIXCHANS]; + tEpgBugFixStats(void) { hits = n = 0; } + }; + +tEpgBugFixStats EpgBugFixStats[MAXEPGBUGFIXSTATS]; + +static void EpgBugFixStat(int Number, unsigned int ServiceID) +{ + if (0 <= Number && Number < MAXEPGBUGFIXSTATS) { + tEpgBugFixStats *p = &EpgBugFixStats[Number]; + p->hits++; + int i = 0; + for (; i < p->n; i++) { + if (p->serviceIDs[i] == ServiceID) + break; + } + if (i == p->n && p->n < MAXEPGBUGFIXCHANS) + p->serviceIDs[p->n++] = ServiceID; + } +} + +static void ReportEpgBugFixStats(bool Reset = false) +{ + if (Setup.EPGBugfixLevel > 0) { + dsyslog(LOG_INFO, "====================="); + dsyslog(LOG_INFO, "EPG bugfix statistics"); + dsyslog(LOG_INFO, "====================="); + dsyslog(LOG_INFO, "IF SOMEBODY WHO IS IN CHARGE OF THE EPG DATA FOR ONE OF THE LISTED"); + dsyslog(LOG_INFO, "CHANNELS READS THIS: PLEASE TAKE A LOOK AT THE FUNCTION cEventInfo::FixEpgBugs()"); + dsyslog(LOG_INFO, "IN VDR/eit.c TO LEARN WHAT'S WRONG WITH YOUR DATA, AND FIX IT!"); + dsyslog(LOG_INFO, "====================="); + dsyslog(LOG_INFO, "Fix\tHits\tChannels"); + char buffer[1024]; + for (int i = 0; i < MAXEPGBUGFIXSTATS; i++) { + const char *delim = "\t"; + tEpgBugFixStats *p = &EpgBugFixStats[i]; + char *q = buffer; + q += snprintf(q, sizeof(buffer) - (q - buffer), "%d\t%d", i, p->hits); + for (int c = 0; c < p->n; c++) { + cChannel *channel = Channels.GetByServiceID(p->serviceIDs[c]); + if (channel) { + q += snprintf(q, sizeof(buffer) - (q - buffer), "%s%s", delim, channel->name); + delim = ", "; + } + } + dsyslog(LOG_INFO, "%s", buffer); + if (Reset) + p->hits = p->n = 0; + } + dsyslog(LOG_INFO, "====================="); + } +} + void cEventInfo::FixEpgBugs(void) { // VDR can't usefully handle newline characters in the EPG data, so let's @@ -367,20 +425,6 @@ void cEventInfo::FixEpgBugs(void) // EPG data. Let's fix their bugs as good as we can: if (pTitle) { - // Pro7 preceeds the Subtitle with the Title: - // - // Title - // Title / Subtitle - // - if (pSubtitle && strstr(pSubtitle, pTitle) == pSubtitle) { - char *p = pSubtitle + strlen(pTitle); - const char *delim = " / "; - if (strstr(p, delim) == p) { - p += strlen(delim); - memmove(pSubtitle, p, strlen(p) + 1); - } - } - // VOX and VIVA put the Subtitle in quotes and use either the Subtitle // or the Extended Description field, depending on how long the string is: // @@ -400,6 +444,7 @@ void cEventInfo::FixEpgBugs(void) delete pExtendedDescription; pSubtitle = s; pExtendedDescription = d; + EpgBugFixStat(0, GetServiceID()); } } } @@ -416,6 +461,7 @@ void cEventInfo::FixEpgBugs(void) memmove(pSubtitle, pSubtitle + 1, strlen(pSubtitle)); pExtendedDescription = pSubtitle; pSubtitle = NULL; + EpgBugFixStat(1, GetServiceID()); } } @@ -427,6 +473,7 @@ void cEventInfo::FixEpgBugs(void) if (pSubtitle && strcmp(pTitle, pSubtitle) == 0) { delete pSubtitle; pSubtitle = NULL; + EpgBugFixStat(2, GetServiceID()); } // ZDF.info puts the Subtitle between double quotes, which is nothing @@ -442,6 +489,7 @@ void cEventInfo::FixEpgBugs(void) char *p = strrchr(pSubtitle, '"'); if (p) *p = 0; + EpgBugFixStat(3, GetServiceID()); } } @@ -460,8 +508,10 @@ void cEventInfo::FixEpgBugs(void) char *p = pExtendedDescription + 1; while (*p) { if (*p == '-' && *(p + 1) == ' ' && *(p + 2) && islower(*(p - 1)) && islower(*(p + 2))) { - if (!startswith(p + 2, "und ")) // special case in German, as in "Lach- und Sachgeschichten" + if (!startswith(p + 2, "und ")) { // special case in German, as in "Lach- und Sachgeschichten" memmove(p, p + 2, strlen(p + 2) + 1); + EpgBugFixStat(4, GetServiceID()); + } } p++; } @@ -845,6 +895,8 @@ cSIProcessor::cSIProcessor(const char *FileName) cSIProcessor::~cSIProcessor() { + if (masterSIProcessor) + ReportEpgBugFixStats(); active = false; Cancel(3); ShutDownFilters(); @@ -913,6 +965,7 @@ void cSIProcessor::Action() schedules->Cleanup(); schedulesMutex.Unlock(); lastCleanup = now; + ReportEpgBugFixStats(true); } if (epgDataFileName && now - lastDump > 600) { diff --git a/gmon.out b/gmon.out Binary files differnew file mode 100644 index 0000000..ea79bc5 --- /dev/null +++ b/gmon.out @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: i18n.c 1.50 2002/01/27 15:52:32 kls Exp $ + * $Id: i18n.c 1.51 2002/02/03 14:34:33 kls Exp $ * * Slovenian translations provided by Miha Setina <mihasetina@softhome.net> * Italian translations provided by Alberto Carraro <bertocar@tin.it> @@ -776,6 +776,15 @@ const tPhrase Phrases[] = { "Enregistrement immédiat", "Markere direkteopptak", }, + { "NameInstantRecord", + "Direktaufz. benennen", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, { "LnbSLOF", "LnbSLOF", "LnbSLOF", @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.146 2002/01/27 15:50:50 kls Exp $ + * $Id: menu.c 1.148 2002/02/03 15:42:38 kls Exp $ */ #include "menu.h" @@ -1553,7 +1553,7 @@ cMenuRecordings::cMenuRecordings(const char *Base, int Level, bool OpenSubMenus) cMenuRecordingItem *LastItem = NULL; char *LastItemText = NULL; for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) { - if (!Base || strstr(recording->Name(), Base) == recording->Name()) { + if (!Base || (strstr(recording->Name(), Base) == recording->Name() && recording->Name()[strlen(Base)] == '~')) { cMenuRecordingItem *Item = new cMenuRecordingItem(recording, level); if (*Item->Text() && (!LastItem || strcmp(Item->Text(), LastItemText) != 0)) { Add(Item); @@ -1829,6 +1829,7 @@ void cMenuSetup::Set(void) Add(new cMenuEditBoolItem(tr("ShowInfoOnChSwitch"), &data.ShowInfoOnChSwitch)); Add(new cMenuEditBoolItem(tr("MenuScrollPage"), &data.MenuScrollPage)); Add(new cMenuEditBoolItem(tr("MarkInstantRecord"), &data.MarkInstantRecord)); + Add(new cMenuEditStrItem( tr("NameInstantRecord"), data.NameInstantRecord, sizeof(data.NameInstantRecord), FileNameChars)); Add(new cMenuEditIntItem( tr("LnbSLOF"), &data.LnbSLOF)); Add(new cMenuEditIntItem( tr("LnbFrequLo"), &data.LnbFrequLo)); Add(new cMenuEditIntItem( tr("LnbFrequHi"), &data.LnbFrequHi)); @@ -2309,14 +2310,16 @@ cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer) timer->SetPending(true); timer->SetRecording(true); if (Channels.SwitchTo(timer->channel, dvbApi)) { + const char *Title = NULL; const char *Subtitle = NULL; const char *Summary = NULL; if (GetEventInfo()) { - dsyslog(LOG_INFO, "Title: '%s' Subtitle: '%s'", eventInfo->GetTitle(), eventInfo->GetSubtitle()); + Title = eventInfo->GetTitle(); Subtitle = eventInfo->GetSubtitle(); Summary = eventInfo->GetExtendedDescription(); + dsyslog(LOG_INFO, "Title: '%s' Subtitle: '%s'", Title, Subtitle); } - cRecording Recording(timer, Subtitle, Summary); + cRecording Recording(timer, Title, Subtitle, Summary); fileName = strdup(Recording.FileName()); cRecordingUserCommand::InvokeCommand(RUC_BEFORERECORDING, fileName); if (dvbApi->StartRecord(fileName, Channels.GetByNumber(timer->channel)->ca, timer->priority)) @@ -2337,7 +2340,7 @@ cRecordControl::~cRecordControl() bool cRecordControl::GetEventInfo(void) { cChannel *channel = Channels.GetByNumber(timer->channel); - time_t Time = timer->StartTime() + (timer->StopTime() - timer->StartTime()) / 2; + time_t Time = timer->StartTime() + ((Setup.MarginStart * 2) + 1) * 60; for (int seconds = 0; seconds <= MAXWAIT4EPGINFO; seconds++) { { cThreadLock ThreadLock; diff --git a/recording.c b/recording.c index acdf264..7a55e1a 100644 --- a/recording.c +++ b/recording.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.48 2002/01/27 15:14:45 kls Exp $ + * $Id: recording.c 1.49 2002/02/03 15:46:42 kls Exp $ */ #include "recording.h" @@ -41,6 +41,9 @@ #define DISKCHECKDELTA 100 // seconds between checks for free disk space #define REMOVELATENCY 10 // seconds to wait until next check after removing a file +#define TIMERMACRO_TITLE "TITLE" +#define TIMERMACRO_EPISODE "EPISODE" + void RemoveDeletedRecordings(void) { static time_t LastRemoveCheck = 0; @@ -214,19 +217,33 @@ char *ExchangeChars(char *s, bool ToFileSystem) return s; } -cRecording::cRecording(cTimer *Timer, const char *Subtitle, const char *Summary) +cRecording::cRecording(cTimer *Timer, const char *Title, const char *Subtitle, const char *Summary) { resume = RESUME_NOT_INITIALIZED; titleBuffer = NULL; sortBuffer = NULL; fileName = NULL; - if (Timer->IsSingleEvent() || !Setup.UseSubtitle) + name = NULL; + // set up the actual name: + if (isempty(Title)) + Title = Channels.GetChannelNameByNumber(Timer->channel); + if (isempty(Subtitle)) + Subtitle = " "; + char *macroTITLE = strstr(Timer->file, TIMERMACRO_TITLE); + char *macroEPISODE = strstr(Timer->file, TIMERMACRO_EPISODE); + if (macroTITLE || macroEPISODE) { name = strdup(Timer->file); - else { - if (isempty(Subtitle)) - Subtitle = " "; - asprintf(&name, "%s~%s", Timer->file, Subtitle); + name = strreplace(name, TIMERMACRO_TITLE, Title); + name = strreplace(name, TIMERMACRO_EPISODE, Subtitle); + if (Timer->IsSingleEvent()) { + Timer->SetFile(name); // this was an instant recording, so let's set the actual data + Timers.Save(); + } } + else if (Timer->IsSingleEvent() || !Setup.UseSubtitle) + name = strdup(Timer->file); + else + asprintf(&name, "%s~%s", Timer->file, Subtitle); // substitute characters that would cause problems in file names: strreplace(name, '\n', ' '); start = Timer->StartTime(); diff --git a/recording.h b/recording.h index 3aaa7e9..38626f8 100644 --- a/recording.h +++ b/recording.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.h 1.21 2002/01/26 15:18:16 kls Exp $ + * $Id: recording.h 1.22 2002/02/03 11:59:49 kls Exp $ */ #ifndef __RECORDING_H @@ -43,7 +43,7 @@ public: time_t start; int priority; int lifetime; - cRecording(cTimer *Timer, const char *Subtitle, const char *Summary); + cRecording(cTimer *Timer, const char *Title, const char *Subtitle, const char *Summary); cRecording(const char *FileName); ~cRecording(); virtual bool operator< (const cListObject &ListObject); @@ -8,7 +8,7 @@ * the Linux DVB driver's 'tuxplayer' example and were rewritten to suit * VDR's needs. * - * $Id: remux.c 1.6 2001/08/19 11:52:05 kls Exp $ + * $Id: remux.c 1.8 2002/02/03 16:20:37 kls Exp $ */ /* The calling interface of the 'cRemux::Process()' function is defined @@ -555,6 +555,17 @@ XXX*/ return Result ? resultBuffer : NULL; XXX*/ + // Special VPID case to enable recording radio channels: + + if (vPid == 0 || vPid == 1 || vPid == 0x1FFF) { + // XXX actually '0' should be enough, but '1' must be used with encrypted channels (driver bug?) + // XXX also allowing 0x1FFF to not break Michael Paar's original patch, + // XXX but it would probably be best to only use '0' + *PictureType = I_FRAME; + Result = resultDelivered = resultCount; + return Result ? resultBuffer : NULL; + } + // Check if we're getting anywhere here: if (!synced && skipped >= 0) { @@ -583,9 +594,8 @@ XXX*/ if (l < 0) return NULL; // no useful data found, wait for more if (pt != NO_PICTURE) { - if (pt < I_FRAME || B_FRAME < pt) { + if (pt < I_FRAME || B_FRAME < pt) esyslog(LOG_ERR, "ERROR: unknown picture type '%d'", pt); - } else if (!synced) { if (pt == I_FRAME) { resultDelivered = i; // will drop everything before this position @@ -10,7 +10,7 @@ * and interact with the Video Disk Recorder - or write a full featured * graphical interface that sits on top of an SVDRP connection. * - * $Id: svdrp.c 1.28 2002/01/13 16:07:42 kls Exp $ + * $Id: svdrp.c 1.30 2002/02/02 15:39:46 kls Exp $ */ #include "svdrp.h" @@ -101,9 +101,17 @@ int cSocket::Accept(void) struct sockaddr_in clientname; uint size = sizeof(clientname); int newsock = accept(sock, (struct sockaddr *)&clientname, &size); - if (newsock > 0) - isyslog(LOG_INFO, "connect from %s, port %hd", inet_ntoa(clientname.sin_addr), ntohs(clientname.sin_port)); - else if (errno != EINTR) + if (newsock > 0) { + bool accepted = SVDRPhosts.Acceptable(clientname.sin_addr.s_addr); + if (!accepted) { + const char *s = "Access denied!\n"; + write(newsock, s, strlen(s)); + close(newsock); + newsock = -1; + } + isyslog(LOG_INFO, "connect from %s, port %hd - %s", inet_ntoa(clientname.sin_addr), ntohs(clientname.sin_port), accepted ? "accepted" : "DENIED"); + } + else if (errno != EINTR && errno != EAGAIN) LOG_ERROR; return newsock; } diff --git a/svdrphosts.conf b/svdrphosts.conf new file mode 100644 index 0000000..dec9c42 --- /dev/null +++ b/svdrphosts.conf @@ -0,0 +1,13 @@ +# +# svdrphosts This file describes a number of host addresses that +# are allowed to connect to the SVDRP port of the Video +# Disk Recorder (VDR) running on this system. +# Syntax: +# +# IP-Address[/Netmask] +# + +127.0.0.1 # always accept localhost +#192.168.100.0/24 # any host on the local net +#204.152.189.113 # a specific host +#0.0.0.0/0 # any host on any net (USE THIS WITH CARE!) @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.53 2002/01/27 12:36:23 kls Exp $ + * $Id: tools.c 1.56 2002/02/03 16:44:08 kls Exp $ */ #include "tools.h" @@ -13,6 +13,7 @@ #include <errno.h> #if defined(DEBUG_OSD) #include <ncurses.h> +#undef ERR //XXX ncurses defines this - but this clashes with newer system header files #endif #include <stdlib.h> #include <sys/time.h> @@ -100,6 +101,23 @@ char *strreplace(char *s, char c1, char c2) return s; } +char *strreplace(char *s, const char *s1, const char *s2) +{ + char *p = strstr(s, s1); + if (p) { + int of = p - s; + int l = strlen(s); + int l1 = strlen(s1); + int l2 = strlen(s2); + if (l2 > l1) + s = (char *)realloc(s, strlen(s) + l2 - l1 + 1); + if (l2 != l1) + memmove(s + of + l2, s + of + l1, l - of - l1 + 1); + strncpy(s + of, s2, l2); + } + return s; +} + char *skipspace(const char *s) { while (*s && isspace(*s)) @@ -404,9 +422,8 @@ char *ReadLink(const char *FileName) if (n < 0) { if (errno == ENOENT || errno == EINVAL) // file doesn't exist or is not a symlink TargetName = FileName; - else { // some other error occurred + else // some other error occurred LOG_ERROR_STR(FileName); - } } else if (n < int(sizeof(RealName))) { // got it! RealName[n] = 0; @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.39 2002/01/26 15:38:10 kls Exp $ + * $Id: tools.h 1.41 2002/02/03 12:36:25 kls Exp $ */ #ifndef __TOOLS_H @@ -20,9 +20,9 @@ extern int SysLogLevel; -#define esyslog if (SysLogLevel > 0) syslog -#define isyslog if (SysLogLevel > 1) syslog -#define dsyslog if (SysLogLevel > 2) syslog +#define esyslog(a...) void( (SysLogLevel > 0) ? syslog(a) : void() ) +#define isyslog(a...) void( (SysLogLevel > 1) ? syslog(a) : void() ) +#define dsyslog(a...) void( (SysLogLevel > 2) ? syslog(a) : void() ) #define LOG_ERROR esyslog(LOG_ERR, "ERROR (%s,%d): %m", __FILE__, __LINE__) #define LOG_ERROR_STR(s) esyslog(LOG_ERR, "ERROR: %s: %m", s) @@ -47,6 +47,7 @@ char *readline(FILE *f); char *strcpyrealloc(char *dest, const char *src); char *strn0cpy(char *dest, const char *src, size_t n); char *strreplace(char *s, char c1, char c2); +char *strreplace(char *s, const char *s1, const char *s2); // re-allocates 's' and deletes the original string if necessary! char *skipspace(const char *s); char *stripspace(char *s); char *compactspace(char *s); @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.93 2002/01/26 14:07:01 kls Exp $ + * $Id: vdr.c 1.94 2002/02/02 15:50:43 kls Exp $ */ #include <getopt.h> @@ -272,6 +272,7 @@ int main(int argc, char *argv[]) Channels.Load(AddDirectory(ConfigDirectory, "channels.conf")); Timers.Load(AddDirectory(ConfigDirectory, "timers.conf")); Commands.Load(AddDirectory(ConfigDirectory, "commands.conf")); + SVDRPhosts.Load(AddDirectory(ConfigDirectory, "svdrphosts.conf"), true); #if defined(REMOTE_LIRC) Keys.SetDummyValues(); #elif !defined(REMOTE_NONE) |