diff -u vdr-1.6.0/channels.c vdr-1.6.0-kw-006/channels.c
--- vdr-1.6.0/channels.c	2008-03-05 17:42:50.000000000 +0100
+++ vdr-1.6.0-kw-006/channels.c	2008-03-29 14:26:08.000000000 +0100
@@ -14,6 +14,7 @@
 #include "epg.h"
 #include "timers.h"
 
+
 // 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!
@@ -905,6 +906,7 @@
   return false;
 }
 
+
 void cChannels::HashChannel(cChannel *Channel)
 {
   channelsHashSid.Add(Channel, Channel->Sid());
diff -u vdr-1.6.0/channels.h vdr-1.6.0-kw-006/channels.h
--- vdr-1.6.0/channels.h	2008-02-08 14:48:31.000000000 +0100
+++ vdr-1.6.0-kw-006/channels.h	2008-03-29 14:25:39.000000000 +0100
@@ -185,6 +185,11 @@
   int Tid(void) const { return tid; }
   int Sid(void) const { return sid; }
   int Rid(void) const { return rid; }
+  bool IsTV(void)        const { return (vpid > 0)  && (Apid(0)>0); }  //kw
+  bool IsVideoOnly(void) const { return (vpid > 0)  && (Apid(0)==0); }  //kw
+  bool IsRadio(void)     const { return (vpid == 0) && (Apid(0)>0); }  //kw
+  bool IsDolby(void)     const { return (Dpid(0) > 0); }               //kw
+  bool IsCrypted(void) const { return (Ca() > 4); }                //kw
   int Number(void) const { return number; }
   void SetNumber(int Number) { number = Number; }
   bool GroupSep(void) const { return groupSep; }
diff -u vdr-1.6.0/config.c vdr-1.6.0-kw-006/config.c
--- vdr-1.6.0/config.c	2008-02-17 14:39:00.000000000 +0100
+++ vdr-1.6.0-kw-006/config.c	2008-03-29 14:35:47.000000000 +0100
@@ -216,6 +216,7 @@
   strcpy(OSDLanguage, ""); // default is taken from environment
   strcpy(OSDSkin, "sttng");
   strcpy(OSDTheme, "default");
+  WarEagleIcons = 1;
   PrimaryDVB = 1;
   ShowInfoOnChSwitch = 1;
   TimeoutRequChInfo = 1;
@@ -234,6 +235,8 @@
   TimeTransponder = 0;
   MarginStart = 2;
   MarginStop = 10;
+  JumpSeconds = 60;
+  JumpSecondsRepeat = 300;
   AudioLanguages[0] = -1;
   DisplaySubtitles = 0;
   SubtitleLanguages[0] = -1;
@@ -289,6 +292,14 @@
   InitialChannel = 0;
   InitialVolume = -1;
   EmergencyExit = 1;
+
+  ShowRecDate = 1;    
+  ShowRecTime = 1;
+  ShowRecLength = 0;
+  ShowProgressBar = 0;
+  MenuCmdPosition = 0;
+  ShowRecNew = 1;
+   
 }
 
 cSetup& cSetup::operator= (const cSetup &s)
@@ -389,6 +400,7 @@
   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);
+  else if (!strcasecmp(Name, "WarEagleIcons"))       WarEagleIcons      = atoi(Value);
   else if (!strcasecmp(Name, "PrimaryDVB"))          PrimaryDVB         = atoi(Value);
   else if (!strcasecmp(Name, "ShowInfoOnChSwitch"))  ShowInfoOnChSwitch = atoi(Value);
   else if (!strcasecmp(Name, "TimeoutRequChInfo"))   TimeoutRequChInfo  = atoi(Value);
@@ -407,6 +419,8 @@
   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, "JumpSeconds"))         JumpSeconds        = atoi(Value);  
+  else if (!strcasecmp(Name, "JumpSecondsRepeat"))   JumpSecondsRepeat  = 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);
@@ -462,8 +476,14 @@
   else if (!strcasecmp(Name, "InitialChannel"))      InitialChannel     = atoi(Value);
   else if (!strcasecmp(Name, "InitialVolume"))       InitialVolume      = atoi(Value);
   else if (!strcasecmp(Name, "EmergencyExit"))       EmergencyExit      = atoi(Value);
-  else
-     return false;
+  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, "ShowProgressBar"))     ShowProgressBar    = atoi(Value);
+  else if (!strcasecmp(Name, "MenuCmdPosition"))     MenuCmdPosition    = atoi(Value);
+  else if (!strcasecmp(Name, "ShowRecNew"))          ShowRecNew         = atoi(Value);
+  else 
+      return false;
   return true;
 }
 
@@ -472,6 +492,7 @@
   Store("OSDLanguage",        OSDLanguage);
   Store("OSDSkin",            OSDSkin);
   Store("OSDTheme",           OSDTheme);
+  Store("WarEagleIcons",      WarEagleIcons);
   Store("PrimaryDVB",         PrimaryDVB);
   Store("ShowInfoOnChSwitch", ShowInfoOnChSwitch);
   Store("TimeoutRequChInfo",  TimeoutRequChInfo);
@@ -490,6 +511,8 @@
   Store("TimeTransponder",    TimeTransponder);
   Store("MarginStart",        MarginStart);
   Store("MarginStop",         MarginStop);
+  Store("JumpSeconds",        JumpSeconds);  
+  Store("JumpSecondsRepeat",  JumpSecondsRepeat);  
   StoreLanguages("AudioLanguages", AudioLanguages);
   Store("DisplaySubtitles",   DisplaySubtitles);
   StoreLanguages("SubtitleLanguages", SubtitleLanguages);
@@ -545,6 +568,12 @@
   Store("InitialChannel",     InitialChannel);
   Store("InitialVolume",      InitialVolume);
   Store("EmergencyExit",      EmergencyExit);
+  Store("ShowRecDate",        ShowRecDate);
+  Store("ShowRecTime",        ShowRecTime);
+  Store("ShowRecLength",      ShowRecLength);
+  Store("ShowProgressBar",    ShowProgressBar);
+  Store("MenuCmdPosition",    MenuCmdPosition);
+  Store("ShowRecNew",         ShowRecNew);
 
   Sort();
 
diff -u vdr-1.6.0/config.h vdr-1.6.0-kw-006/config.h
--- vdr-1.6.0/config.h	2008-03-23 11:26:10.000000000 +0100
+++ vdr-1.6.0-kw-006/config.h	2008-03-29 14:32:30.000000000 +0100
@@ -36,6 +36,10 @@
 // plugins to work with newer versions of the core VDR as long as no
 // VDR header files have changed.
 
+
+#define KWPATCHLEVEL 4
+#define LIEMIKUUTIO  113           
+
 #define MAXPRIORITY 99
 #define MAXLIFETIME 99
 
@@ -202,6 +206,7 @@
   char OSDLanguage[I18N_MAX_LOCALE_LEN];
   char OSDSkin[MaxSkinName];
   char OSDTheme[MaxThemeName];
+  int WarEagleIcons;
   int PrimaryDVB;
   int ShowInfoOnChSwitch;
   int TimeoutRequChInfo;
@@ -219,6 +224,7 @@
   int TimeSource;
   int TimeTransponder;
   int MarginStart, MarginStop;
+  int JumpSeconds, JumpSecondsRepeat;  // JP
   int AudioLanguages[I18N_MAX_LANGUAGES + 1];
   int DisplaySubtitles;
   int SubtitleLanguages[I18N_MAX_LANGUAGES + 1];
@@ -266,6 +272,8 @@
   int CurrentDolby;
   int InitialChannel;
   int InitialVolume;
+  int ShowRecDate, ShowRecTime, ShowRecLength, ShowRecNew, MenuCmdPosition, ShowProgressBar; //
+    
   int EmergencyExit;
   int __EndData__;
   cSetup(void);
@@ -277,3 +285,4 @@
 extern cSetup Setup;
 
 #endif //__CONFIG_H
+
diff -u vdr-1.6.0/cutter.c vdr-1.6.0-kw-006/cutter.c
--- vdr-1.6.0/cutter.c	2008-01-13 13:22:21.000000000 +0100
+++ vdr-1.6.0-kw-006/cutter.c	2008-03-24 19:52:29.000000000 +0100
@@ -194,6 +194,12 @@
      error = false;
      ended = false;
      cRecording Recording(FileName);
+     //+cuttime-patch begin    
+     cMarks FromMarks;    
+     FromMarks.Load(FileName); 
+     cMark *First=FromMarks.First();   
+     if (First) Recording.SetStartTime(Recording.start+((First->position/FRAMESPERSEC+30)/60)*60);  
+     //+cuttime-patch end
      const char *evn = Recording.PrefixFileName('%');
      if (evn && RemoveVideoFile(evn) && MakeDirs(evn, true)) {
         // XXX this can be removed once RenameVideoFile() follows symlinks (see videodir.c)
diff -u vdr-1.6.0/device.h vdr-1.6.0-kw-006/device.h
--- vdr-1.6.0/device.h	2008-02-23 14:13:04.000000000 +0100
+++ vdr-1.6.0-kw-006/device.h	2008-03-29 14:36:36.000000000 +0100
@@ -149,6 +149,7 @@
   static void SetAvoidDevice(cDevice *Device) { avoidDevice = Device; }
          ///< Sets the given Device to be temporarily avoided in the next call to
          ///< GetDevice(const cChannel, int, bool).
+
   static void Shutdown(void);
          ///< Closes down all devices.
          ///< Must be called at the end of the program.
@@ -237,6 +238,7 @@
   bool SwitchChannel(const cChannel *Channel, bool LiveView);
          ///< Switches the device to the given Channel, initiating transfer mode
          ///< if necessary.
+
   static bool SwitchChannel(int Direction);
          ///< Switches the primary device to the next available channel in the given
          ///< Direction (only the sign of Direction is evaluated, positive values
diff -u vdr-1.6.0/eit.c vdr-1.6.0-kw-006/eit.c
--- vdr-1.6.0/eit.c	2007-08-26 12:56:33.000000000 +0200
+++ vdr-1.6.0-kw-006/eit.c	2008-03-24 19:52:29.000000000 +0100
@@ -30,6 +30,7 @@
   if (!CheckCRCAndParse())
      return;
 
+
   tChannelID channelID(Source, getOriginalNetworkId(), getTransportStreamId(), getServiceId());
   cChannel *channel = Channels.GetByChannelID(channelID, true);
   if (!channel)
@@ -37,6 +38,22 @@
 
   cSchedule *pSchedule = (cSchedule *)Schedules->GetSchedule(channel, true);
 
+//+w-epgfix-mod begin  
+  static int offset, lastSource, lastONID, lastTSID, lastSID;  //+w-epgfix-mod
+  if (!pSchedule ||        
+      lastSource != Source ||   
+      lastONID != getOriginalNetworkId() ||    
+      lastTSID != getTransportStreamId() ||    
+      lastSID != getServiceId())    
+    offset = 0;    
+
+  lastSource = Source;                 
+  lastONID = getOriginalNetworkId();    
+  lastTSID = getTransportStreamId();
+  lastSID = getServiceId();             
+//+w-epgfix-mod end
+
+
   bool Empty = true;
   bool Modified = false;
   bool HasExternalData = false;
@@ -55,7 +72,7 @@
       SegmentEnd = SiEitEvent.getStartTime() + SiEitEvent.getDuration();
       cEvent *newEvent = NULL;
       cEvent *rEvent = NULL;
-      cEvent *pEvent = (cEvent *)pSchedule->GetEvent(SiEitEvent.getEventId(), SiEitEvent.getStartTime());
+      cEvent *pEvent = (cEvent *)pSchedule->GetEvent(SiEitEvent.getEventId(), SiEitEvent.getStartTime()+offset, SiEitEvent.getDuration());      //mod w-epgfix-mod
       if (!pEvent) {
          if (OnlyRunningStatus)
             continue;
@@ -68,6 +85,18 @@
       else {
          // We have found an existing event, either through its event ID or its start time.
          pEvent->SetSeen();
+         //-----------------------------------------------------------------------------------------------------       //+w-epgfix-mod
+         // w_epgfix: some stations have different event IDs and/or StartTime and/or Duration for the same event.      //+w-epgfix-mod
+         // therefore we try to find them by StartTime + offset, or if this fails by event ID                           //+w-epgfix-mod
+         // If the event is shifted by some minutes, all following events on the same Schedule will be shifted            //+w-epgfix-mod
+         // or will have different duration                                                                                //+w-epgfix-mod
+         if (Tid <= pEvent->TableID() && pEvent->TableID() != 0x00) {                                                           //+w-epgfix-mod
+            offset = SiEitEvent.getStartTime() + SiEitEvent.getDuration() - pEvent->EndTime();                              //+w-epgfix-mod
+         //   pEvent->SetEventID(SiEitEvent.getEventId());                                                                  //+w-epgfix-mod
+            if (offset > 900 || offset < -900)                                                                               //+w-epgfix-mod
+              offset = 0; //do not allow more than 15min StartTime offset                                                    //+w-epgfix-mod
+            }                                                                                                                //+w-epgfix-mod
+         //-----------------------------------------------------------------------------------------------------               //+w-epgfix-mod
          // If the existing event has a zero table ID it was defined externally and shall
          // not be overwritten.
          if (pEvent->TableID() == 0x00) {
diff -u vdr-1.6.0/epg.c vdr-1.6.0-kw-006/epg.c
--- vdr-1.6.0/epg.c	2008-02-16 17:09:12.000000000 +0100
+++ vdr-1.6.0-kw-006/epg.c	2008-03-24 19:52:29.000000000 +0100
@@ -325,7 +325,7 @@
                           unsigned int Version = 0xFF; // actual value is ignored
                           int n = sscanf(t, "%u %ld %d %X %X", &EventID, &StartTime, &Duration, &TableID, &Version);
                           if (n >= 3 && n <= 5) {
-                             Event = (cEvent *)Schedule->GetEvent(EventID, StartTime);
+                             Event = (cEvent *)Schedule->GetEvent(EventID, StartTime, Duration);       //mod w-epgfix-mod
                              cEvent *newEvent = NULL;
                              if (Event)
                                 DELETENULL(Event->components);
@@ -718,14 +718,41 @@
   return p;
 }
 
-const cEvent *cSchedule::GetEvent(tEventID EventID, time_t StartTime) const
+const cEvent *cSchedule::GetEvent(tEventID EventID, time_t StartTime, int Duration) const       //mod w-epgfix-mod
 {
   // Returns the event info with the given StartTime or, if no actual StartTime
   // is given, the one with the given EventID.
-  if (StartTime > 0) // 'StartTime < 0' is apparently used with NVOD channels
-     return eventsHashStartTime.Get(StartTime);
-  else
-     return eventsHashID.Get(EventID);
+  //-------------------- w_epgfix.patch ----------------------       //+w-epgfix-mod
+  // Returns either the event info with                                   //+w-epgfix-mod
+  // a) the one with the given StartTime be found,                        //+w-epgfix-mod
+  // b) the Event found -10/+15min around StartTime and a simmilar Duration //+w-epgfix-mod
+  // c) the given EventID or, if that one can't                            //+w-epgfix-mod
+  // d) NULL if none of them found)                                       //+w-epgfix-mod
+  if (StartTime > 0) { // 'StartTime < 0' is apparently used with NVOD channels   //mod w-epgfix-mod
+     cEvent *p = eventsHashStartTime.Get(StartTime);                    //+w-epgfix-mod
+
+     if (p) {                                                                 //+w-epgfix-mod
+        return p;                                                             //+w-epgfix-mod
+     // given offset was wrong; let's search a little bit around;             //+w-epgfix-mod
+     } else {                                                                 //+w-epgfix-mod
+        for (p = events.First(); p; p = events.Next(p)) {                     //+w-epgfix-mod
+           if (p &&                                                           //+w-epgfix-mod
+                (p->StartTime() >= StartTime - 10*60 &&                       //+w-epgfix-mod
+                 p->StartTime() <= StartTime + 15*60) &&                      //+w-epgfix-mod
+                (Duration == 0 ||                                             //+w-epgfix-mod
+                  (Duration >= (p->Duration() - (p->Duration()/ 5) - 1) &&    //+w-epgfix-mod
+                   Duration <= (p->Duration() + (p->Duration()/ 5) + 1))      //+w-epgfix-mod
+                ) )                                                           //+w-epgfix-mod
+              return p;                                                       //+w-epgfix-mod
+        }                                                                     //+w-epgfix-mod
+     }                                                                        //+w-epgfix-mod
+                                                                              //+w-epgfix-mod
+//     return eventsHashStartTime.Get(StartTime);                             //+w-epgfix-mod
+  }                                                                           //+w-epgfix-mod
+//  else                                                                      //+w-epgfix-mod
+/* If the program gets here, no event has been found by its StartTime.        //+w-epgfix-mod
+   So let's try it by EventID. */                                             //+w-epgfix-mod
+  return eventsHashID.Get(EventID);                                           //+w-epgfix-mod
 }
 
 const cEvent *cSchedule::GetEventAround(time_t Time) const
diff -u vdr-1.6.0/epg.h vdr-1.6.0-kw-006/epg.h
--- vdr-1.6.0/epg.h	2006-10-07 15:47:19.000000000 +0200
+++ vdr-1.6.0-kw-006/epg.h	2008-03-24 19:52:29.000000000 +0100
@@ -144,7 +144,7 @@
   const cList<cEvent> *Events(void) const { return &events; }
   const cEvent *GetPresentEvent(void) const;
   const cEvent *GetFollowingEvent(void) const;
-  const cEvent *GetEvent(tEventID EventID, time_t StartTime = 0) const;
+  const cEvent *GetEvent(tEventID EventID, time_t StartTime = 0, int Duration = 0) const; // mod w-epgfix-mod
   const cEvent *GetEventAround(time_t Time) const;
   void Dump(FILE *f, const char *Prefix = "", eDumpMode DumpMode = dmAll, time_t AtTime = 0) const;
   static bool Read(FILE *f, cSchedules *Schedules);
diff -u vdr-1.6.0/iconpatch.h vdr-1.6.0-kw-006/iconpatch.h
--- vdr-1.6.0/iconpatch.h	2008-03-30 19:30:11.000000000 +0200
+++ vdr-1.6.0-kw-006/iconpatch.h	2008-03-24 19:52:32.000000000 +0100
@@ -0,0 +1,52 @@
+/*
+ * iconpatch.h: Information of iconpatch
+ *
+ * Diese Datei ist die Übersichtsdatei für den Iconpatch.
+ * Hier werden kleine Infos abgelegt.
+ * Der Iconpatch ändert die Dateien:
+ *   iconpatch.h
+ *   menu.c
+ *   recording.c
+ *   fontosd.c
+ *
+ */
+
+//Iconpatch-Variablen - Anfang
+#define ICON_RADIO         char(244)
+#define ICON_TV            char(245)
+//#define ICON_TV_VERSCHL    char(239)
+#define ICON_VERSCHL       char(239)
+#define ICON_UNVERSCHL     char(128)
+#define ICON_REC           char(249)
+#define ICON_NEU           char(250)
+#define ICON_RENNER        char(251)
+#define ICON_UHR           char(253)
+#define ICON_LAUTSPRECHER  char(254)
+#define ICON_PFEIL         char(255)
+//Iconpatch-Variablen - Ende
+/*
+ * iconpatch.h: Information of iconpatch
+ *
+ * Diese Datei ist die Übersichtsdatei für den Iconpatch.
+ * Hier werden kleine Infos abgelegt.
+ * Der Iconpatch ändert die Dateien:
+ *   iconpatch.h
+ *   menu.c
+ *   recording.c
+ *   fontosd.c
+ *
+ */
+
+//Iconpatch-Variablen - Anfang
+#define ICON_RADIO         char(244)
+#define ICON_TV            char(245)
+//#define ICON_TV_VERSCHL    char(239)
+#define ICON_VERSCHL       char(239)
+#define ICON_UNVERSCHL     char(128)
+#define ICON_REC           char(249)
+#define ICON_NEU           char(250)
+#define ICON_RENNER        char(251)
+#define ICON_UHR           char(253)
+#define ICON_LAUTSPRECHER  char(254)
+#define ICON_PFEIL         char(255)
+//Iconpatch-Variablen - Ende
Gemeinsame Unterverzeichnisse: vdr-1.6.0/libsi und vdr-1.6.0-kw-006/libsi.
diff -u vdr-1.6.0/menu.c vdr-1.6.0-kw-006/menu.c
--- vdr-1.6.0/menu.c	2008-03-16 12:15:28.000000000 +0100
+++ vdr-1.6.0-kw-006/menu.c	2008-03-29 15:05:34.000000000 +0100
@@ -8,11 +8,13 @@
  */
 
 #include "menu.h"
+#include "iconpatch.h"
 #include <ctype.h>
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <math.h>
 #include "channels.h"
 #include "config.h"
 #include "cutter.h"
@@ -77,7 +79,8 @@
         int Minutes = int(double(FreeMB) / MB_PER_MINUTE);
         int Hours = Minutes / 60;
         Minutes %= 60;
-        freeDiskSpaceString = cString::sprintf("%s %d%%  -  %2d:%02d %s", tr("Disk"), Percent, Hours, Minutes, tr("free"));
+        freeDiskSpaceString = cString::sprintf(/* "%s %d%%  -  %2d:%02d %s", tr("Disk"), Percent, Hours, Minutes, tr("free")); */
+                                                  "%s %d%%  %2d:%02d %s  (%.1f GB)", tr("Disk"), Percent, Hours, Minutes, tr("free"), FreeMB / 1024.0 ); //kw
         lastFreeMB = FreeMB;
         return true;
         }
@@ -85,6 +88,7 @@
   return false;
 }
 
+
 // --- cMenuEditCaItem -------------------------------------------------------
 
 class cMenuEditCaItem : public cMenuEditIntItem {
@@ -403,7 +407,16 @@
      if (sortMode == csmProvider)
         buffer = cString::sprintf("%d\t%s - %s", channel->Number(), channel->Provider(), channel->Name());
      else
-        buffer = cString::sprintf("%d\t%s", channel->Number(), channel->Name());
+        buffer = cString::sprintf("%d\t%s%s%s%s  %s\t\t%s %s", channel->Number(), 
+                  channel->IsTV()        ? "t":     // TV         //kw-cfp
+                  channel->IsVideoOnly() ? "v":" ", // TV without audio //kw-cfp
+                  channel->IsRadio()     ? "r":" ", // Radio      //kw-cfp
+                  channel->IsDolby()     ? "d":" ", // Dolby      //kw-cfp
+                  channel->IsCrypted()   ? "x":" ", // encrypted  //kw-cfp
+                  channel->Name(),
+                  channel->Alang(0),
+                  channel->Alang(1)
+              );
      }
   else
      buffer = cString::sprintf("---\t%s ----------------------------------------------------------------", channel->Name());
@@ -421,9 +434,14 @@
   void Setup(void);
   cChannel *GetChannel(int Index);
   void Propagate(void);
+  
+  bool IsFiltered(void);                      // kw-cfp 
+  void MessageFilterState(void);              // kw-cfp 
+  static int onlyTV, onlyRadio, onlyUncrypt, onlyCrypt;  // kw-cfp 
+  
 protected:
   eOSState Number(eKeys Key);
-  eOSState Switch(void);
+  eOSState Switch(eOSState returnVal);   // kw-cfp mod
   eOSState Edit(void);
   eOSState New(void);
   eOSState Delete(void);
@@ -434,6 +452,13 @@
   virtual eOSState ProcessKey(eKeys Key);
   };
 
+int                inSubMenu = 0;       // kw-cfp
+int cMenuChannels::onlyTV = 0;          // kw-cfp 
+int cMenuChannels::onlyRadio = 0;       // kw-cfp 
+int cMenuChannels::onlyUncrypt = 0;     // kw-cfp 
+int cMenuChannels::onlyCrypt = 0;     // kw-cfp 
+  
+
 cMenuChannels::cMenuChannels(void)
 :cOsdMenu(tr("Channels"), CHNUMWIDTH)
 {
@@ -453,20 +478,41 @@
   if (!currentChannel)
      currentChannel = Channels.GetByNumber(cDevice::CurrentChannel());
   cMenuChannelItem *currentItem = NULL;
+  cMenuChannelItem *lastUsedItem = NULL;
+  cMenuChannelItem *firstUsedItem = NULL;
   Clear();
+
   for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel)) {
-      if (!channel->GroupSep() || cMenuChannelItem::SortMode() == cMenuChannelItem::csmNumber && *channel->Name()) {
-         cMenuChannelItem *item = new cMenuChannelItem(channel);
-         Add(item);
-         if (channel == currentChannel)
-            currentItem = item;
-         }
+      if ((!channel->GroupSep() || cMenuChannelItem::SortMode() == cMenuChannelItem::csmNumber)
+            && *channel->Name()  //Channel must have a name
+	    && (channel->GroupSep() || //Do not filter Groupseperators
+        (  !(onlyTV      && !channel->IsTV()      )  //kw-cfp
+  		&& !(onlyRadio   && !channel->IsRadio()   )  //kw-cfp
+		&& !(onlyUncrypt && channel->IsCrypted()  )  //kw-cfp
+		&& !(onlyCrypt   && !channel->IsCrypted() )  //kw-cfp
+	    ))) {
+            cMenuChannelItem *item = new cMenuChannelItem(channel);
+            Add(item);
+            if (channel == currentChannel)
+        	    currentItem = item;
+	    if (!channel->GroupSep()) {
+		    lastUsedItem = item;
+		if( !firstUsedItem )
+		    firstUsedItem = item;
+	    }
+      } else {
+            if (channel == currentChannel)
+              	currentItem = lastUsedItem; // current channel is now invisible, so we use the nearest channel
       }
+  }
   if (cMenuChannelItem::SortMode() != cMenuChannelItem::csmNumber)
      Sort();
+  if (!currentItem) // happens, if after filtering the first line is a groupsep
+     currentItem = firstUsedItem;
   SetCurrent(currentItem);
   SetHelp(tr("Button$Edit"), tr("Button$New"), tr("Button$Delete"), tr("Button$Mark"));
   Display();
+  MessageFilterState();
 }
 
 cChannel *cMenuChannels::GetChannel(int Index)
@@ -484,38 +530,61 @@
   Channels.SetModified(true);
 }
 
-eOSState cMenuChannels::Number(eKeys Key)
-{
-  if (HasSubMenu())
-     return osContinue;
-  if (numberTimer.TimedOut())
-     number = 0;
-  if (!number && Key == k0) {
-     cMenuChannelItem::IncSortMode();
-     Setup();
-     }
-  else {
-     number = number * 10 + Key - k0;
-     for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next()) {
-         if (!ci->Channel()->GroupSep() && ci->Channel()->Number() == number) {
-            SetCurrent(ci);
-            Display();
-            break;
-            }
-         }
-     numberTimer.Set(CHANNELNUMBERTIMEOUT);
-     }
-  return osContinue;
-}
+// kw-cfp  start
+bool cMenuChannels::IsFiltered(void)  
+{                                     
+  return onlyTV || onlyRadio || onlyUncrypt || onlyCrypt; 
+}                                            
+
+void cMenuChannels::MessageFilterState(void)    
+{
+   char *buffer = NULL;
+   if( IsFiltered() )
+      asprintf(&buffer, tr("filter: show %s%s%s%s "),
+            onlyTV      ? tr("tv ")      : "" ,
+            onlyRadio   ? tr("radio ")   : "" ,
+            onlyUncrypt ? tr("FTA ")     : "" ,
+            onlyCrypt   ? tr("crypted ") : ""
+      );
+   else 
+      asprintf(&buffer, "Filter: off");
+   Skins.Message(mtStatus, buffer); 
+}
+// kw-cfp  end
+
+
+eOSState cMenuChannels::Number(eKeys Key)                                                                
+{                                                                                                        
+  if (HasSubMenu())                                                                                      
+     return osContinue;                                                                                  
+  if (numberTimer.TimedOut())                                                                            
+     number = 0;                                                                                         
+  if (!number && Key == k0) {                                                                            
+     inSubMenu = 1;                   // kw-cfp mod
+     Skins.Message(mtStatus, tr("0=sort - 1=TV - 2=Radio - 3=FTA only - 4=crypt only - 5=both - 9=unfiltered - 8=switch")); // kw-cfp
+     }                                                                                                   
+  else {                                                                                                 
+     number = number * 10 + Key - k0;                                                                    
+     for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next()) { 
+         if (!ci->Channel()->GroupSep() && ci->Channel()->Number() == number) {                          
+            SetCurrent(ci);                                                                              
+            Display();                                                                                   
+            break;                                                                                       
+            }                                                                                            
+         }                                                                                               
+     numberTimer.Set(CHANNELNUMBERTIMEOUT);                                                              
+     }                                                                                                   
+  return osContinue;   
+}                                                                                                        
 
-eOSState cMenuChannels::Switch(void)
+eOSState cMenuChannels::Switch(eOSState returnVal)   // kw-cfp mod
 {
   if (HasSubMenu())
      return osContinue;
   cChannel *ch = GetChannel(Current());
   if (ch)
-     return cDevice::PrimaryDevice()->SwitchChannel(ch, true) ? osEnd : osContinue;
-  return osEnd;
+     return cDevice::PrimaryDevice()->SwitchChannel(ch, true) ? returnVal : osContinue;
+  return returnVal;   // kw-cfp mod
 }
 
 eOSState cMenuChannels::Edit(void)
@@ -595,6 +664,7 @@
      }
 }
 
+
 eOSState cMenuChannels::ProcessKey(eKeys Key)
 {
   eOSState state = cOsdMenu::ProcessKey(Key);
@@ -608,21 +678,86 @@
             }
          }
          break;
-    default:
-         if (state == osUnknown) {
-            switch (Key) {
-              case k0 ... k9:
-                            return Number(Key);
-              case kOk:     return Switch();
-              case kRed:    return Edit();
-              case kGreen:  return New();
-              case kYellow: return Delete();
-              case kBlue:   if (!HasSubMenu())
-                               Mark();
-                            break;
-              default: break;
-              }
-            }
+         
+    case osUnknown:		                    // kw-cfp
+         if( inSubMenu == 0 ) {             // kw-cfp
+             switch (Key) {                 // kw-cfp
+               case k0 ... k9:
+                             return Number(Key);
+               case kOk:     return Switch(osEnd);      // kw-cfp mod
+               case kRed:    return Edit();
+               case kGreen:  return New();
+               case kYellow: return Delete();
+               case kBlue:   if (!HasSubMenu())
+                             Mark();
+                             break;
+                    default: break;
+               }
+// kw-cfp start               
+          } else {    
+              switch (Key) { 
+                case k0: // Sorting (Number -> Name -> Transponder)
+                             cMenuChannelItem::IncSortMode();                                                                    
+                             Setup();
+                             inSubMenu = 0;
+                             state = osContinue; 
+                             break;
+                case k1: // toggle   only TV-channels (those with sound)
+                             onlyTV = !onlyTV;
+                             if (onlyTV) onlyRadio = 0;
+                             Setup();
+                             inSubMenu = 0;
+                             state = osContinue; 
+                             break;
+                case k2: // show only radio/broadcast
+                             onlyRadio = !onlyRadio;
+                             if (onlyRadio) onlyTV = 0;
+                             Setup();
+                             inSubMenu = 0;
+                             state = osContinue; 
+                             break;
+                case k3: // onlyFTA
+                             onlyUncrypt = 1;
+                             onlyCrypt = 0;
+                             Setup();
+                             inSubMenu = 0;
+                             state = osContinue;     
+                             break;
+                case k4: // only Crypted
+                             onlyUncrypt = 0;
+                             onlyCrypt = 1;
+                             Setup();
+                             inSubMenu = 0;
+                             state = osContinue;     
+                             break;
+                case k5: // FTA + Crypted
+                             onlyUncrypt = 1;
+                             onlyCrypt = 1;
+                             Setup();
+                             inSubMenu = 0;
+                             state = osContinue;     
+                             break;
+                case k8: //kw Switch without quitting OSD    
+                             inSubMenu = 0;
+                             MessageFilterState();
+                             return Switch(osContinue); 
+
+                case k9: // no filter
+                             onlyRadio = onlyTV = onlyUncrypt = onlyCrypt = 0;
+                             Setup();
+                             inSubMenu = 0;
+                             state = osContinue; 
+                             break;
+
+                default:     state = osContinue; 
+                             break;
+                } //switch    
+            } //if inSubMenu  
+
+          break;
+           
+     default: break;     
+// kw-cfp end
     }
   return state;
 }
@@ -813,7 +948,7 @@
      day = buffer;
      }
   SetText(cString::sprintf("%c\t%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s",
-                    !(timer->HasFlags(tfActive)) ? ' ' : timer->FirstDay() ? '!' : timer->Recording() ? '#' : '>',
+                    !(timer->HasFlags(tfActive)) ? ' ' : timer->FirstDay() ? Setup.WarEagleIcons ? ICON_PFEIL : '!' : timer->Recording() ? Setup.WarEagleIcons ? ICON_REC : '#' : Setup.WarEagleIcons ? ICON_UHR : '>',
                     timer->Channel()->Number(),
                     *name,
                     *name && **name ? " " : "",
@@ -1036,12 +1171,13 @@
   return state;
 }
 
-// --- cMenuScheduleItem -----------------------------------------------------
+// --- cMenuScheduleItem ------------------------------------------------------
 
 class cMenuScheduleItem : public cOsdItem {
 public:
   enum eScheduleSortMode { ssmAllThis, ssmThisThis, ssmThisAll, ssmAllAll }; // "which event(s) on which channel(s)"
 private:
+  static const char * const ProgressBar[7];
   static eScheduleSortMode sortMode;
 public:
   const cEvent *event;
@@ -1056,6 +1192,7 @@
   bool Update(bool Force = false);
   };
 
+
 cMenuScheduleItem::eScheduleSortMode cMenuScheduleItem::sortMode = ssmAllThis;
 
 cMenuScheduleItem::cMenuScheduleItem(const cEvent *Event, cChannel *Channel, bool WithDate)
@@ -1066,7 +1203,7 @@
   timerMatch = tmNone;
   Update(true);
 }
-
+  
 int cMenuScheduleItem::Compare(const cListObject &ListObject) const
 {
   cMenuScheduleItem *p = (cMenuScheduleItem *)&ListObject;
@@ -1079,29 +1216,39 @@
 }
 
 static const char *TimerMatchChars = " tT";
+  
+const char * const cMenuScheduleItem::ProgressBar[7] =
+ {
+   "[      ]",
+   "[|     ]",
+   "[||    ]",
+   "[|||   ]",
+   "[||||  ]",
+   "[||||| ]",
+   "[||||||]"
+ };
+ 
 
 bool cMenuScheduleItem::Update(bool Force)
 {
-  bool result = false;
-  int OldTimerMatch = timerMatch;
-  Timers.GetMatch(event, &timerMatch);
-  if (Force || timerMatch != OldTimerMatch) {
-     cString buffer;
-     char t = TimerMatchChars[timerMatch];
-     char v = event->Vps() && (event->Vps() - event->StartTime()) ? 'V' : ' ';
-     char r = event->SeenWithin(30) && event->IsRunning() ? '*' : ' ';
-     const char *csn = channel ? channel->ShortName(true) : NULL;
-     cString eds = event->GetDateString();
-     if (channel && withDate)
-        buffer = cString::sprintf("%d\t%.*s\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title());
-     else if (channel)
-        buffer = cString::sprintf("%d\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title());
-     else
-        buffer = cString::sprintf("%.*s\t%s\t%c%c%c\t%s", Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title());
-     SetText(buffer);
-     result = true;
-     }
-  return result;
+    bool result = false;
+    int OldTimerMatch = timerMatch;
+    Timers.GetMatch(event, &timerMatch);
+    if (Force || timerMatch != OldTimerMatch) {
+       char *buffer = NULL;
+       char t = TimerMatchChars[timerMatch];
+       char v = event->Vps() && (event->Vps() - event->StartTime()) ? 'V' : ' ';
+       char r = event->SeenWithin(30) && event->IsRunning() ? '*' : ' ';
+       if (channel && withDate )
+          asprintf(&buffer, "%d\t%.*s\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), 6, channel->ShortName(true), 6, *event->GetDateString(), *event->GetTimeString(), t, v, r, event->Title());
+       else if (channel)
+          asprintf(&buffer, "%d\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), 6, channel->ShortName(true), *event->GetTimeString(), t, v, r, event->Title());
+       else
+          asprintf(&buffer, "%.*s\t%s\t%c%c%c\t%s", 6, *event->GetDateString(), *event->GetTimeString(), t, v, r, event->Title());
+       SetText(buffer, false);
+       result = true;
+       }
+    return result;
 }
 
 // --- cMenuWhatsOn ----------------------------------------------------------
@@ -1899,23 +2046,169 @@
   totalEntries++;
   if (New)
      newEntries++;
-  SetText(cString::sprintf("%d\t%d\t%s", totalEntries, newEntries, name));
+  if( Setup.ShowRecNew )  //kw 
+     SetText(cString::sprintf("%7d\t%d\t%s", totalEntries, newEntries, name)); //kw mod
+  else                                                                         //kw
+     SetText(cString::sprintf("%7d\t%s", totalEntries, name));                 //kw
 }
 
+
+// --- cMenuRenameRecording --------------------------------------------------
+
+class cMenuRenameRecording : public cOsdMenu {
+private:
+  int lifetime;
+  int priority;
+  char name[MaxFileName];
+  char path[MaxFileName];
+  cOsdItem *marksItem, *resumeItem; 
+  bool isResume, isMarks;           
+  cRecording *recording;
+public:
+  cMenuRenameRecording(cRecording *Recording);
+  virtual eOSState ProcessKey(eKeys Key);
+};
+
+cMenuRenameRecording::cMenuRenameRecording(cRecording *Recording)
+:cOsdMenu(tr("Rename recording"), 12)
+{
+  cMarks marks;
+  char *buffer = NULL;
+
+  recording = Recording;
+  priority = recording->priority;
+  lifetime = recording->lifetime;
+
+  char* p = strrchr(recording->Name(), '~');
+  if (p) {
+     p++;
+     strn0cpy(name, p, sizeof(name));
+     strn0cpy(path, recording->Name(), sizeof(path));
+     p = strrchr(path, '~');
+     if (p)
+        p[0] = 0;
+     }   
+  else {
+     strn0cpy(name, recording->Name(), sizeof(name));
+     strn0cpy(path, "", sizeof(path));
+     }
+  Add(new cMenuEditStrItem(tr("Name"),      name,     sizeof(name), tr(FileNameChars)));
+  Add(new cMenuEditRecPathItem(tr("Path"),  path,     sizeof(path)                   ));
+  Add(new cMenuEditIntItem(tr("Priority"), &priority, 0,            MAXPRIORITY      ));
+  Add(new cMenuEditIntItem(tr("Lifetime"), &lifetime, 0,            MAXLIFETIME      ));
+
+  Add(new cOsdItem("",                     osUnknown, false));
+
+  asprintf(&buffer, "%s:\t%s", tr("Date"), *DayDateTime(recording->start));
+  Add(new cOsdItem(buffer,                 osUnknown, false));
+  free(buffer);
+
+  cChannel *channel = Channels.GetByChannelID(((cRecordingInfo *)recording->Info())->ChannelID());
+  if (channel) {
+     asprintf(&buffer, "%s:\t%s", tr("Channel"), *ChannelString(channel, 0));
+     Add(new cOsdItem(buffer,              osUnknown, false));
+     free(buffer);
+     }
+
+  cIndexFile *index = new cIndexFile(recording->FileName(), false);
+  if (index) {
+     asprintf(&buffer, "%s:\t%s", tr("Length"), *IndexToHMSF(index->Last()));
+     Add(new cOsdItem(buffer,              osUnknown, false));
+     free(buffer);
+     }
+  delete index;
+
+  int dirSize = DirSizeMB(recording->FileName());
+  if (dirSize > 9999)
+     asprintf(&buffer, "%s:\t%.2f GB", tr("Size"), dirSize / 1024.0);
+  else
+     asprintf(&buffer, "%s:\t%d MB", tr("Size"), dirSize);
+  Add(new cOsdItem(buffer,                 osUnknown, false));
+  free(buffer);
+
+  Add(new cOsdItem("",                     osUnknown, false));
+
+  isMarks = marks.Load(recording->FileName()) && marks.Count();
+  marksItem = new cOsdItem(tr("Delete marks information?"),   osUser1, isMarks);
+  Add(marksItem);
+
+  cResumeFile ResumeFile(recording->FileName());
+  isResume = (ResumeFile.Read() != -1); 
+  resumeItem = new cOsdItem(tr("Delete resume information?"), osUser2, isResume);
+  Add(resumeItem);
+}
+
+eOSState cMenuRenameRecording::ProcessKey(eKeys Key)
+{
+  eOSState state = cOsdMenu::ProcessKey(Key);
+
+  if (state == osUnknown) {
+     if (Key == kOk) {
+        char buffer[MaxFileName];
+        if (strlen(path))        
+           snprintf(buffer, sizeof(buffer), "%s~%s", path, name);
+        else
+           snprintf(buffer, sizeof(buffer), "%s", name);
+        if (recording->Rename(buffer, &priority, &lifetime)) {
+           Recordings.ChangeState();
+           Recordings.TouchUpdate();
+           return osRecordings;
+           }
+        else
+           Skins.Message(mtError, tr("Error while accessing recording!"));
+        }
+     return osContinue;
+     }
+  else if (state == osUser1) {
+     if (isMarks && Interface->Confirm(tr("Delete marks information?"))) {
+        cMarks marks;
+        marks.Load(recording->FileName());
+        cMark *mark = marks.First();
+        while (mark) {
+          cMark *nextmark = marks.Next(mark);
+          marks.Del(mark);
+          mark = nextmark;
+          }
+        marks.Save();
+        isMarks = false;
+        marksItem->SetSelectable(isMarks);
+        SetCurrent(First());
+        Display();
+        }
+     return osContinue;
+     }
+  else if (state == osUser2) {
+     if (isResume && Interface->Confirm(tr("Delete resume information?"))) {
+        cResumeFile ResumeFile(recording->FileName());
+        ResumeFile.Delete();
+        isResume = false;
+        resumeItem->SetSelectable(isResume);
+        SetCurrent(First());
+        Display();
+        }
+     return osContinue;
+     }
+  return state;
+}
+
+
+
 // --- cMenuRecordings -------------------------------------------------------
 
+ 
 cMenuRecordings::cMenuRecordings(const char *Base, int Level, bool OpenSubMenus)
-:cOsdMenu(Base ? Base : tr("Recordings"), 9, 7)
+:cOsdMenu(Base ? Base : tr("Recordings"), 8, 6, 6)
 {
   base = Base ? strdup(Base) : NULL;
   level = Setup.RecordingDirs ? Level : -1;
   Recordings.StateChanged(recordingsState); // just to get the current state
   helpKeys = -1;
+  dirOrderAlpha = level == 0; 
   Display(); // this keeps the higher level menus from showing up briefly when pressing 'Back' during replay
   Set();
   SetFreeDiskDisplay(true);
   if (Current() < 0)
-     SetCurrent(First());
+     SetCurrent(First());     
   else if (OpenSubMenus && cReplayControl::LastReplayed() && Open(true))
      return;
   Display();
@@ -1978,6 +2271,7 @@
         }
      }
   Clear();
+  DirOrderState = dirOrderAlpha; //kw records sorting
   Recordings.Sort();
   for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) {
       if (!base || (strstr(recording->Name(), base) == recording->Name() && recording->Name()[strlen(base)] == '~')) {
@@ -2000,6 +2294,7 @@
       }
   free(LastItemText);
   Refresh |= SetFreeDiskDisplay(Refresh);
+ 
   if (Refresh)
      Display();
 }
@@ -2136,6 +2431,19 @@
   return osContinue;
 }
 
+eOSState cMenuRecordings::Rename(void)
+{
+  if (HasSubMenu() || Count() == 0)
+     return osContinue;
+  cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
+  if (ri && !ri->IsDirectory()) {
+     cRecording *recording = GetRecording(ri);
+     if (recording)
+        return AddSubMenu(new cMenuRenameRecording(recording));
+     }
+  return osContinue;
+}
+
 eOSState cMenuRecordings::ProcessKey(eKeys Key)
 {
   bool HadSubMenu = HasSubMenu();
@@ -2150,7 +2458,18 @@
        case kYellow: return Delete();
        case kInfo:
        case kBlue:   return Info();
-       case k1...k9: return Commands(Key);
+       case k0:      dirOrderAlpha = !dirOrderAlpha ; //kw records sorting
+                     DirOrderState = dirOrderAlpha;
+                     Set(true);                       //kw records sorting
+                     Skins.Message(mtStatus,          //kw records sorting
+                        dirOrderAlpha ? "alphabetisch sortiert" : "chronologisch" //kw records sorting
+                     );
+                     return osContinue;        //kw records sorting
+       case k1...k7: return Commands(Key);     //kw records sorting
+       case k8:      return Rename();          //kw records sorting
+       case k9:      Recordings.TouchUpdate(); //kw records sorting
+                     Skins.Message(mtStatus, "Rescanning recordings..."); //kw records sorting
+                     return osBack;            //kw records sorting
        case kNone:   if (Recordings.StateChanged(recordingsState))
                         Set(true);
                      break;
@@ -2255,6 +2574,7 @@
   Add(new cMenuEditStraItem(tr("Setup.OSD$Skin"),                   &skinIndex, numSkins, skinDescriptions));
   if (themes.NumThemes())
   Add(new cMenuEditStraItem(tr("Setup.OSD$Theme"),                  &themeIndex, themes.NumThemes(), themes.Descriptions()));
+  Add(new cMenuEditBoolItem(tr("Setup.OSD$WarEagle icons"),         &data.WarEagleIcons));
   Add(new cMenuEditIntItem( tr("Setup.OSD$Left"),                   &data.OSDLeft, 0, MAXOSDWIDTH));
   Add(new cMenuEditIntItem( tr("Setup.OSD$Top"),                    &data.OSDTop, 0, MAXOSDHEIGHT));
   Add(new cMenuEditIntItem( tr("Setup.OSD$Width"),                  &data.OSDWidth, MINOSDWIDTH, MAXOSDWIDTH));
@@ -2276,6 +2596,7 @@
   Add(new cMenuEditBoolItem(tr("Setup.OSD$Scroll wraps"),           &data.MenuScrollWrap));
   Add(new cMenuEditBoolItem(tr("Setup.OSD$Menu key closes"),        &data.MenuKeyCloses));
   Add(new cMenuEditBoolItem(tr("Setup.OSD$Recording directories"),  &data.RecordingDirs));
+  Add(new cMenuEditBoolItem(tr("Setup.OSD$Main menu command position"), &data.MenuCmdPosition, tr("bottom"), tr("top")));
   SetCurrent(Get(current));
   Display();
 }
@@ -2380,6 +2701,7 @@
   Add(new cMenuEditIntItem( tr("Setup.EPG$EPG scan timeout (h)"),      &data.EPGScanTimeout));
   Add(new cMenuEditIntItem( tr("Setup.EPG$EPG bugfix level"),          &data.EPGBugfixLevel, 0, MAXEPGBUGFIXLEVEL));
   Add(new cMenuEditIntItem( tr("Setup.EPG$EPG linger time (min)"),     &data.EPGLinger, 0));
+  Add(new cMenuEditBoolItem(tr("Setup.EPG$Show progress bar"),         &data.ShowProgressBar));
   Add(new cMenuEditBoolItem(tr("Setup.EPG$Set system time"),           &data.SetSystemTime));
   if (data.SetSystemTime)
      Add(new cMenuEditTranItem(tr("Setup.EPG$Use time from transponder"), &data.TimeTransponder, &data.TimeSource));
@@ -2758,6 +3080,10 @@
   Add(new cMenuEditIntItem( tr("Setup.Recording$Instant rec. time (min)"),   &data.InstantRecordTime, 1, MAXINSTANTRECTIME));
   Add(new cMenuEditIntItem( tr("Setup.Recording$Max. video file size (MB)"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZE));
   Add(new cMenuEditBoolItem(tr("Setup.Recording$Split edited files"),        &data.SplitEditedFiles));
+  Add(new cMenuEditBoolItem(tr("Setup.Recording$Show date"),                 &data.ShowRecDate));
+  Add(new cMenuEditBoolItem(tr("Setup.Recording$Show time"),                 &data.ShowRecTime));
+  Add(new cMenuEditBoolItem(tr("Setup.Recording$Show length"),               &data.ShowRecLength));
+  Add(new cMenuEditBoolItem(tr("Setup.Recording$Show 'New' indicator"),      &data.ShowRecNew));
 }
 
 // --- cMenuSetupReplay ------------------------------------------------------
@@ -2775,6 +3101,8 @@
   Add(new cMenuEditBoolItem(tr("Setup.Replay$Multi speed mode"), &data.MultiSpeedMode));
   Add(new cMenuEditBoolItem(tr("Setup.Replay$Show replay mode"), &data.ShowReplayMode));
   Add(new cMenuEditIntItem(tr("Setup.Replay$Resume ID"), &data.ResumeID, 0, 99));
+  Add(new cMenuEditIntItem( tr("Setup.Recording$Jump Seconds"),            &data.JumpSeconds));
+  Add(new cMenuEditIntItem( tr("Setup.Recording$Jump Seconds (repeated)"), &data.JumpSecondsRepeat));
 }
 
 void cMenuSetupReplay::Store(void)
@@ -2974,7 +3302,14 @@
   // Initial submenus:
 
   switch (State) {
-    case osSchedule:   AddSubMenu(new cMenuSchedule); break;
+    case osSchedule:   // AddSubMenu(new cMenuSchedule); break;
+                       //EPGSEARCH-Plugin-Patch-Begin
+                    {        
+			            cPlugin *p = cPluginManager::GetPlugin("epgsearch");
+    			        (p && !p->SetupParse("IsOrgSchedule", "0")) ? AddSubMenu((cOsdMenu *)p->MainMenuAction()) : AddSubMenu(new cMenuSchedule);
+		            }			
+		            break;
+                       //EPGSEARCH-Plugin-Patch-end
     case osChannels:   AddSubMenu(new cMenuChannels); break;
     case osTimers:     AddSubMenu(new cMenuTimers); break;
     case osRecordings: AddSubMenu(new cMenuRecordings(NULL, 0, true)); break;
@@ -2994,9 +3329,13 @@
 void cMenuMain::Set(void)
 {
   Clear();
-  SetTitle("VDR");
+  SetTitle("VDR"); 
   SetHasHotkeys();
 
+  if (Setup.MenuCmdPosition) {
+        Update(true);
+  }
+
   // Basic menu items:
 
   Add(new cOsdItem(hk(tr("Schedule")),   osSchedule));
@@ -3023,7 +3362,9 @@
   if (Commands.Count())
      Add(new cOsdItem(hk(tr("Commands")),  osCommands));
 
-  Update(true);
+  if (!Setup.MenuCmdPosition) {
+         Update(true);
+  }
 
   Display();
 }
@@ -3053,7 +3394,7 @@
      // Color buttons:
      SetHelp(!replaying ? tr("Button$Record") : NULL, tr("Button$Audio"), replaying ? NULL : tr("Button$Pause"), replaying ? tr("Button$Stop") : cReplayControl::LastReplayed() ? tr("Button$Resume") : NULL);
      result = true;
-     }
+     }                     
 
   // Editing control:
   bool CutterActive = cCutter::Active();
@@ -3085,7 +3426,7 @@
            }
      result = true;
      }
-
+     
   return result;
 }
 
@@ -3097,7 +3438,16 @@
   HadSubMenu |= HasSubMenu();
 
   switch (state) {
-    case osSchedule:   return AddSubMenu(new cMenuSchedule);
+    case osSchedule:   {
+			cPlugin *p = cPluginManager::GetPlugin("epgsearch");
+            		if (p && !p->SetupParse("IsOrgSchedule", "0")) {
+			    return AddSubMenu((cOsdMenu *)p->MainMenuAction());
+			    state = osEnd;
+			    }
+			else 
+			    return AddSubMenu(new cMenuSchedule);
+		       }			
+		       break;
     case osChannels:   return AddSubMenu(new cMenuChannels);
     case osTimers:     return AddSubMenu(new cMenuTimers);
     case osRecordings: return AddSubMenu(new cMenuRecordings);
@@ -3761,7 +4111,7 @@
 
 // --- cRecordControl --------------------------------------------------------
 
-cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause)
+cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause, cChannel *Channel)
 {
   // We're going to manipulate an event here, so we need to prevent
   // others from modifying any EPG data:
@@ -3810,9 +4160,10 @@
   cRecordingUserCommand::InvokeCommand(RUC_BEFORERECORDING, fileName);
   isyslog("record %s", fileName);
   if (MakeDirs(fileName, true)) {
-     const cChannel *ch = timer->Channel();
-     recorder = new cRecorder(fileName, ch->GetChannelID(), timer->Priority(), ch->Vpid(), ch->Apids(), ch->Dpids(), ch->Spids());
-     if (device->AttachReceiver(recorder)) {
+      const cChannel *ch = Channel ? Channel : timer->Channel();
+      if (ch)
+         recorder = new cRecorder(fileName,  ch->GetChannelID(), timer->Priority(), ch->Vpid(), ch->Apids(), ch->Dpids(), ch->Spids());
+      if (ch && device->AttachReceiver(recorder)) {
         Recording.WriteInfo();
         cStatus::MsgRecording(device, Recording.Name(), Recording.FileName(), true);
         if (!Timer && !cReplayControl::LastReplayed()) // an instant recording, maybe from cRecordControls::PauseLiveVideo()
@@ -3821,7 +4172,8 @@
         return;
         }
      else
-        DELETENULL(recorder);
+        if (ch)
+	   DELETENULL(recorder);
      }
   if (!Timer) {
      Timers.Del(timer);
@@ -3928,7 +4280,7 @@
         if (!Timer || Timer->Matches()) {
            for (int i = 0; i < MAXRECORDCONTROLS; i++) {
                if (!RecordControls[i]) {
-                  RecordControls[i] = new cRecordControl(device, Timer, Pause);
+                  RecordControls[i] = new cRecordControl(device, Timer, Pause, channel);
                   return RecordControls[i]->Process(time(NULL));
                   }
                }
@@ -4394,6 +4746,9 @@
 
 eOSState cReplayControl::ProcessKey(eKeys Key)
 {
+  static int jmpWidth = 1;
+  int pkw = 0;
+
   if (!Active())
      return osEnd;
   if (visible) {
@@ -4431,14 +4786,44 @@
     case kFastFwd:
     case kRight:   Forward(); break;
     case kRed:     TimeSearch(); break;
-    case kGreen|k_Repeat:
-    case kGreen:   SkipSeconds(-60); break;
-    case kYellow|k_Repeat:
-    case kYellow:  SkipSeconds( 60); break;
+    case kGreen|k_Repeat: 
+                   SkipSeconds(-(Setup.JumpSecondsRepeat)); break;
+    case kGreen:   SkipSeconds(-(Setup.JumpSeconds)); break;
+    case kYellow|k_Repeat: 
+                   SkipSeconds(Setup.JumpSecondsRepeat); break;
+    case kYellow:  SkipSeconds(Setup.JumpSeconds); break;
     case kStop:
-    case kBlue:    Hide();
+    case kBlue:    Hide();   
                    Stop();
                    return osEnd;
+//begin kw-Jumpseconds etc.                   
+     case k1|k_Repeat:
+            jmpWidth += 15;
+   		    displayFrames = false;
+ 		    pkw = SkipFrames(-jmpWidth); 
+ 		    Goto(pkw, true);
+ 		    break;
+     case k1:	   
+            jmpWidth = 1;
+     		displayFrames = true;
+ 		    pkw = SkipFrames(-1); 
+ 		    Goto(pkw, true);
+ 		    break;
+
+     case k3|k_Repeat:
+            jmpWidth += 15;
+   		    displayFrames = false;
+ 		    pkw = SkipFrames(jmpWidth); 
+ 		    Goto(pkw, true);
+ 		    break;
+     case k3:	   
+            jmpWidth = 1;
+ 		    displayFrames = true;
+ 		    pkw = SkipFrames(1); 
+ 		    Goto(pkw, true);
+ 		    break;
+//begin kw-Jumpseconds etc.                   
+         
     default: {
       DoShowMode = false;
       switch (Key) {
@@ -4480,3 +4865,4 @@
      ShowMode();
   return osContinue;
 }
+
diff -u vdr-1.6.0/menu.h vdr-1.6.0-kw-006/menu.h
--- vdr-1.6.0/menu.h	2008-02-10 17:01:53.000000000 +0100
+++ vdr-1.6.0-kw-006/menu.h	2008-03-24 19:52:32.000000000 +0100
@@ -163,7 +163,9 @@
   eOSState Delete(void);
   eOSState Info(void);
   eOSState Commands(eKeys Key = kNone);
-protected:
+  eOSState Rename(void);
+  bool dirOrderAlpha;   //kw simple-record-sort-patch
+protected:  
   cRecording *GetRecording(cMenuRecordingItem *Item);
 public:
   cMenuRecordings(const char *Base = NULL, int Level = 0, bool OpenSubMenus = false);
@@ -181,7 +183,7 @@
   char *fileName;
   bool GetEvent(void);
 public:
-  cRecordControl(cDevice *Device, cTimer *Timer = NULL, bool Pause = false);
+  cRecordControl(cDevice *Device, cTimer *Timer = NULL, bool Pause = false, cChannel *Channel = NULL);
   virtual ~cRecordControl();
   bool Process(time_t t);
   cDevice *Device(void) { return device; }
diff -u vdr-1.6.0/menuitems.c vdr-1.6.0-kw-006/menuitems.c
--- vdr-1.6.0/menuitems.c	2008-02-10 17:03:30.000000000 +0100
+++ vdr-1.6.0-kw-006/menuitems.c	2008-03-24 19:52:32.000000000 +0100
@@ -466,6 +466,7 @@
                     }
                  else
                     return osUnknown;
+                 lastKey = Key;
                  break;
     case kYellow|k_Repeat:
     case kYellow: // Remove the character at the current position; in insert mode it is the character to the right of the cursor
@@ -487,6 +488,7 @@
                     }
                  else
                     return osUnknown;
+		 lastKey = Key;
                  break;
     case kBlue|k_Repeat:
     case kBlue:  // consume the key only if in edit-mode
@@ -509,7 +511,7 @@
                     EnterEditMode();
                     SetHelpKeys();
                     }
-                 break;
+                   break;
     case kUp|k_Repeat:
     case kUp:
     case kDown|k_Repeat:
@@ -527,6 +529,7 @@
                     }
                  else
                     return cMenuEditItem::ProcessKey(Key);
+                 lastKey = Key;
                  break;
     case k0|k_Repeat ... k9|k_Repeat:
     case k0 ... k9: {
@@ -619,6 +622,157 @@
   return osContinue;
 }
 
+// --- cMenuEditRecPathItem --------------------------------------------------
+
+cMenuEditRecPathItem::cMenuEditRecPathItem(const char* Name, char* Path,
+   int Length): cMenuEditStrItem(Name, Path, Length, tr(FileNameChars))
+{
+  SetBase(Path);
+}
+
+cMenuEditRecPathItem::~cMenuEditRecPathItem()
+{
+}
+
+void cMenuEditRecPathItem::SetBase(const char* Path)
+{
+  if (!Path)
+      base[0] = 0;
+  strn0cpy(base, Path, sizeof(base));
+  char* p = strrchr(base, '~');
+  if (p)
+     p[0] = 0; 
+  else
+     base[0] = 0;
+}
+
+void cMenuEditRecPathItem::FindNextLevel()
+{
+  char item[MaxFileName];
+
+  for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
+  {
+     char* p;
+     strn0cpy(item, recording->Name(), sizeof(item));
+     stripspace(value);
+     if (!strlen(value))
+        p = strchr(item, '~');
+     else {
+        if (strstr(item, value) != item)
+           continue;
+        if (item[strlen(value)] != '~')
+           continue;
+        p = strchr(item + strlen(value) + 1, '~');
+        }
+     if (!p)
+        continue;
+     p[0] = 0;
+     strn0cpy(base, value, length);
+     strn0cpy(value, item, length);
+     return;
+     }
+}
+
+void cMenuEditRecPathItem::Find(bool Next)
+{
+  char item[MaxFileName];
+  char lastItem[MaxFileName] = "";
+
+  for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
+  {
+     const char* recName = recording->Name();
+     if (strlen(base) && strstr(recName, base) != recName)
+        continue;
+     if (strlen(base) && recName[strlen(base)] != '~')
+        continue;
+     strn0cpy(item, recName, sizeof(item));
+     char* p = strchr(item + strlen(base) + 1, '~');
+     if (!p)
+        continue;
+     p[0] = 0;
+
+     if (!Next && (strcmp(item, value) == 0)) {
+        if (strlen(lastItem))
+           strn0cpy(value, lastItem, length);
+        return;
+        }
+     if (strcmp(lastItem, item) != 0) {
+        if(Next && strlen(lastItem) && strcmp(lastItem, value) == 0) {
+           strn0cpy(value, item, length);
+           return;
+           }
+        strn0cpy(lastItem, item, sizeof(lastItem));
+        }
+     }
+}
+
+void cMenuEditRecPathItem::SetHelpKeys(void)
+{
+  cSkinDisplay::Current()->SetButtons(tr("Rename$Up"), tr("Rename$Down"), tr("Rename$Previous"), tr("Rename$Next"));
+}
+
+eOSState cMenuEditRecPathItem::ProcessKey(eKeys Key)
+{
+  switch (Key) {
+    case kLeft:
+    case kRed:    // one level up
+                  if (pos<0)
+                     return cMenuEditItem::ProcessKey(Key);
+                  strn0cpy(value, base, length);
+                  SetBase(base);
+                  pos = strlen(base);
+                  if (pos)
+                     pos++;
+                  if (!strlen(value))
+                     strn0cpy(value, " ", length);
+                  break;
+    case kRight:
+    case kGreen:  // one level down
+                  if (pos>=0)
+                     FindNextLevel();
+                  if (!strlen(value))
+                     strn0cpy(value, " ", length);
+                  pos = strlen(base);
+                  if (pos)
+                     pos++;
+                  SetHelpKeys();
+                  break;
+    case kUp|k_Repeat:
+    case kUp:
+    case kYellow|k_Repeat:
+    case kYellow: // previous directory in list
+                  if (pos<0)
+                     return cMenuEditItem::ProcessKey(Key);
+                  Find(false);
+                  pos = strlen(base);
+                  if (pos)
+                     pos++;
+                  break;
+    case kDown|k_Repeat:
+    case kDown:
+    case kBlue|k_Repeat:
+    case kBlue:   // next directory in list
+                  if (pos<0)
+                     return cMenuEditItem::ProcessKey(Key);
+                  Find(true);
+                  pos = strlen(base);
+                  if (pos)
+                     pos++;
+                  break;
+    case kOk:     // done
+                  if (pos<0)
+                     return cMenuEditItem::ProcessKey(Key);
+                  stripspace(value);
+                  cSkinDisplay::Current()->SetButtons(NULL);
+                  pos = -1;
+                  break;
+    default:
+                  return cMenuEditItem::ProcessKey(Key);
+    }
+  Set();
+  return osContinue;
+}
+
 // --- cMenuEditStraItem -----------------------------------------------------
 
 cMenuEditStraItem::cMenuEditStraItem(const char *Name, int *Value, int NumStrings, const char * const *Strings)
diff -u vdr-1.6.0/menuitems.h vdr-1.6.0-kw-006/menuitems.h
--- vdr-1.6.0/menuitems.h	2008-02-16 17:09:58.000000000 +0100
+++ vdr-1.6.0-kw-006/menuitems.h	2008-03-24 21:11:32.000000000 +0100
@@ -78,10 +78,11 @@
 
 class cMenuEditStrItem : public cMenuEditItem {
 private:
-  char *value;
-  int length;
-  const char *allowed;
-  int pos, offset;
+  // char *value;         //kw moved to protected:
+  // int length;          //kw moved to protected:
+  // const char *allowed; //kw moved to protected:
+  // int pos;             //kw moved to protected:
+  int offset;
   bool insert, newchar, uppercase;
   int lengthUtf8;
   uint *valueUtf8;
@@ -90,14 +91,23 @@
   uint *currentCharUtf8;
   eKeys lastKey;
   cTimeMs autoAdvanceTimeout;
-  void SetHelpKeys(void);
+  //void SetHelpKeys(void); //kw moved to protected:
   uint *IsAllowed(uint c);
   void AdvancePos(void);
-  virtual void Set(void);
+  // virtual void Set(void); //kw moved to protected:
   uint Inc(uint c, bool Up);
+  int ieCurChr;     //kw
+  time_t lastActivity;  //kw
   void Insert(void);
   void Delete(void);
 protected:
+  char *value;   //kw  mv from private:
+  int length;    //kw  mv from private:
+  const char *allowed; //kw  mv from private:
+  int pos;       //kw  mv from private:
+  virtual void SetHelpKeys(void);  //kw  mv from private:
+  virtual void Set(void);          //kw  mv from private:
+
   void EnterEditMode(void);
   void LeaveEditMode(bool SaveValue = false);
   bool InEditMode(void) { return valueUtf8 != NULL; }
@@ -107,6 +117,19 @@
   virtual eOSState ProcessKey(eKeys Key);
   };
 
+class cMenuEditRecPathItem : public cMenuEditStrItem {
+protected:
+  char base[MaxFileName];
+  virtual void SetHelpKeys(void);
+  void SetBase(const char* Path);
+  void FindNextLevel();
+  void Find(bool Next);
+public:
+  cMenuEditRecPathItem(const char* Name, char* Path, int Length);
+  ~cMenuEditRecPathItem();
+  virtual eOSState ProcessKey(eKeys Key);
+  };
+
 class cMenuEditStraItem : public cMenuEditIntItem {
 private:
   const char * const *strings;
diff -u vdr-1.6.0/osdbase.c vdr-1.6.0-kw-006/osdbase.c
--- vdr-1.6.0/osdbase.c	2008-02-17 12:33:04.000000000 +0100
+++ vdr-1.6.0-kw-006/osdbase.c	2008-03-24 21:39:11.000000000 +0100
@@ -77,6 +77,7 @@
 {
   isMenu = true;
   digit = 0;
+  key_nr = -1;
   hasHotkeys = false;
   title = NULL;
   SetTitle(Title);
@@ -119,7 +120,7 @@
         digit = -1; // prevents automatic hotkeys - input already has them
      if (digit >= 0) {
         digit++;
-        buffer = cString::sprintf(" %c %s", (digit < 10) ? '0' + digit : ' ' , s);
+        buffer = cString::sprintf(" %2d%s %s", digit, (digit > 9) ? "" : " ", s);        
         s = buffer;
         }
      }
@@ -448,23 +449,66 @@
      }
 }
 
+ #define MENUKEY_TIMEOUT 1500
+ 
 eOSState cOsdMenu::HotKey(eKeys Key)
-{
-  for (cOsdItem *item = First(); item; item = Next(item)) {
-      const char *s = item->Text();
-      if (s && (s = skipspace(s)) != NULL) {
-         if (*s == Key - k1 + '1') {
-            current = item->Index();
-            RefreshCurrent();
-            Display();
-            cRemote::Put(kOk, true);
-            break;
-            }
-         }
+  {
+  // kw-patch
+   bool match = false;
+   bool highlight = false;
+   int  item_nr;
+   int  i;
+ 
+   if (Key == kNone) {
+      if (lastActivity.TimedOut())
+         Key = kOk;
+      else
+         return osContinue;
       }
-  return osContinue;
+   else {
+      lastActivity.Set(MENUKEY_TIMEOUT);
+      }
+   for (cOsdItem *item = Last(); item; item = Prev(item)) {
+       const char *s = item->Text();
+       i = 0;
+       item_nr = 0;
+       if (s && (s = skipspace(s)) != '\0' && '0' <= s[i] && s[i] <= '9') {
+          do {
+             item_nr = item_nr * 10 + (s[i] - '0');
+             }
+          while ( !((s[++i] == '\t')||(s[i] == ' ')) && (s[i] != '\0') && ('0' <= s[i]) && (s[i] <= '9'));
+          if ((Key == kOk) && (item_nr == key_nr)) {
+             current = item->Index();
+             cRemote::Put(kOk, true);
+             key_nr = -1;
+             break;
+             }
+          else if (Key != kOk) {
+             if (!highlight && (item_nr == (Key - k0))) {
+                highlight = true;
+                current = item->Index();
+                }
+             if (!match && (key_nr == -1) && ((item_nr / 10) == (Key - k0))) {
+                match = true;
+                key_nr = (Key - k0);
+                }
+             else if (((key_nr == -1) && (item_nr == (Key - k0))) || (!match && (key_nr >= 0) && (item_nr == (10 * key_nr + Key - k0)))) {
+                current = item->Index();
+                cRemote::Put(kOk, true);
+                key_nr = -1;
+                break;
+                }
+             }
+          }
+       }
+   if ((!match) && (Key != kNone)) {
+      key_nr = -1;
+      }
+    return osContinue;
+  // kw-patch???
 }
 
+
 eOSState cOsdMenu::AddSubMenu(cOsdMenu *SubMenu)
 {
   delete subMenu;
@@ -500,8 +544,8 @@
         }
      }
   switch (Key) {
-    case k0:      return osUnknown;
-    case k1...k9: return hasHotkeys ? HotKey(Key) : osUnknown;
+    case kNone:
+    case k0...k9: return hasHotkeys ? HotKey(Key) : osUnknown;
     case kUp|k_Repeat:
     case kUp:   CursorUp();   break;
     case kDown|k_Repeat:
diff -u vdr-1.6.0/osdbase.h vdr-1.6.0-kw-006/osdbase.h
--- vdr-1.6.0/osdbase.h	2007-11-03 15:50:52.000000000 +0100
+++ vdr-1.6.0-kw-006/osdbase.h	2008-03-24 19:52:32.000000000 +0100
@@ -95,6 +95,8 @@
   char *status;
   int digit;
   bool hasHotkeys;
+  int key_nr;
+  cTimeMs lastActivity;
 protected:
   void SetDisplayMenu(void);
   cSkinDisplayMenu *DisplayMenu(void) { return displayMenu; }
Gemeinsame Unterverzeichnisse: vdr-1.6.0/PLUGINS und vdr-1.6.0-kw-006/PLUGINS.
Gemeinsame Unterverzeichnisse: vdr-1.6.0/po und vdr-1.6.0-kw-006/po.
diff -u vdr-1.6.0/README.kw vdr-1.6.0-kw-006/README.kw
--- vdr-1.6.0/README.kw	2008-03-30 19:30:11.000000000 +0200
+++ vdr-1.6.0-kw-006/README.kw	2008-03-29 14:10:16.000000000 +0100
@@ -0,0 +1,510 @@
+kw-Patches
+==========
+
+Hier die Patches, die andere oder ich erstellt haben 
+und die ich selbst nutze. Die erste Version basierte auf dem enAIO-Patch,
+der seinerseits diverse Patches zusammenfasste. Inzwischen ähnelt meine
+Sammlung dem liemikuutio-Patch (http://www.saunalahti.fi/~rahrenbe/vdr/patches/). 
+Offenbar hat dessen Entwickler Rolf Ahrenberg unabhängig von mir ähnliche
+Patches darin aufgenommen. Da es ungezählte Varianten der enthaltenen Patches
+gibt, und auch ich nicht mehr weiß, welche der zahlreichen meist minimalen 
+Änderungen von mir und welche von anderen Autoren stammt ist folgende Aufzählung 
+möglicherweise nicht ganz komplett. 
+
+Derzeit (vdr 1.6.0-kw-006) sind folgende Patches enthalten:
+
+  * vdr-1.4.7-audioindexer.patch   (von Reinhard Nissl)
+   "you may have noticed that radio recordings report a length which is much
+    larger than the actual playtime of the recording. This is a result of
+    VDR generating an index entry for every audio frame, but audio frames
+    provide most often only 24 ms of music while VDR's recording length
+    calculation is based on 40 ms per index entry.
+    The attached patch fixes cRemux to only generate an index entry whenever
+    the recorded amount of music crosses a 40 ms boundary."
+    http://www.mail-archive.com/vdr@linuxtv.org/msg04082.html
+    (seit 25.10.07)
+
+  * w_epgfix    
+    zur Vermeidung doppelter EPG-Einträge bei schlampigen EPG-Anbietern (z.B. Prosiebensat1)
+    von vdr-Portal-User Wirbel (http://www.vdr-portal.de/board/profile.php?userid=4146) und 
+    "Norad" (http://www.vdr-portal.de/board/profile.php?userid=5190)
+    Thread: http://www.vdr-portal.de/board/thread.php?threadid=36640&threadview=0&hilight=&hilightuser=0&page=1
+    Download: http://www.vdr-portal.de/board/attachment.php?attachmentid=10284    
+    (seit 1.4.3-kw-003)
+
+  * Cuttime-Patch (2006-05-14) von Udo Richter  // +cuttime-patch
+    (http://www.richter-udo.de/vdr/patches.html#cuttime)
+    Ändert beim Schneiden die Zeit im Verzeichnisnamen,
+    dadurch kann dieselbe Sendung mehrfach geschnitten werden, ohne
+    vorherige Schnittergebnisse zu löschen
+    (seit 1.4.2-kw)
+
+  * Rename Recordings Patch von Torsten Kunkel ( // tk-rrp )
+    (http://www.vdr-wiki.de/wiki/index.php/Renamerecordings-patch)
+    Umbennen von Aufzeichnungen per Fernbedienung
+
+  * Menu Selection Patch von Peter Dittmann 
+    (http://www.vdr-wiki.de/wiki/index.php/Menuselection-patch)
+    Es können alle Menüpunkte, auch die größer 9,
+    per Zahleneingabe angesprungen werden.
+
+  * Recording-Length-Patch von Tobias Faust ( // tf-rlp )
+    (http://www.vdr-portal.de/board/thread.php?threadid=40417, geändert lt. 
+    "liemikuutio"-Patch).
+    Zeigt die Länge von Aufzeichnungen an. 
+    
+  * Channelfilter-Patch 0.5 von Walter Koch ( // kw-cfp )
+    Filtern der Kanalliste. Beschreibung siehe unten
+
+  * Singlestep/JumpingSecond-Patch von Tobias Faust und Walter Koch
+
+  * Einfaches Aufzeichnungssortieren-Patch (simple record sort patch) 
+    von Walter Koch ( //kw-srsp ). Anleitung s.u.
+
+  * Patch zum Ersetzen des Menüpunktes "Programm" durch das EPGSEARCH-Plugin
+    falls vorhanden. Dieser Patch funktioniert auch ohne das EPGSEARCH-Plugin.
+    Dieser Patch stammt aus dem EPGSEARCH-Plugin (http://freenet-homepage.de/cwieninger/html/vdr-epg-search.html).
+
+  * Wareagle-Iconpatch 
+    (http://www.vdr-wiki.de/wiki/index.php/Wareagleicon-patch)
+    Mit willkürlichen Änderungen meinerseits.
+  
+  * Diverse kleine Layoutänderungen von OSD-Listen u.ä.  
+  
+  * Klarere deutsche Texte ("Ändern" statt "Edit", "Programmvorschau" 
+    statt "Programm" u.ä.)
+    
+  * die Anzeige des freien Platzes
+
+Der Status des "Show Weekdays Patch" von Oskar Signell
+ist mir derzeit unklar. 
+
+"kw" ist übrigens das Kürzel, welches ich seit Urzeiten für
+Quellcodekommentare nutze. 
+
+Gruss,
+  Walter
+  
+  
+Entfernt: 
+
+  * Der ursprünglich enthaltene Easy-Input-Patch ist seit vdr 1.3.38 in
+    vdr integriert und daher nicht mehr hier drin
+
+  * Alternative channel-patch (vdr-1.4.0_AlternativeChannelPatch_0.0.3) //acp    
+    Der Patch erweitert VDR um die Möglichkeit, jedem Kanal einen Alternativ-Kanal
+    für eine Aufnahme zu hinterlegen. Damit ist es möglich in einem System mit 
+    mehreren Empfangsarten (z.B. DVB-C und analoge Kanäle) einen Fallback auf 
+    einen analogen Kanal für die Aufnahme eines qualitativ besseren DVB-C Kanals 
+    einzurichten. (http://www.vdr-portal.de/board/thread.php?threadid=52862)
+    Für diesen muß im vdr-Config-Verzeichnis ein Datei namens 
+    channels_alternative.conf vorhanden sein. Das Originalannoncement steht unten
+    (seit 1.4.6.kw-005 drin, seit 1.6.0-kw-006 entfernt mangels Nutzung)
+    
+  * Lnbsharing-patch (configurableLNBshare-VDR_1.4.3.patch) //ML
+    Mit dem LNB-Sharing-Patch können zwei oder mehr DVB-Karten ein Kabel sowie
+    den angeschlossenen LNB gleichzeitig nutzen, ohne dass es zu gegenseitigen
+    Störungen kommt. (http://lötzke.de/vdr.html, http://www.vdr-wiki.de/wiki/index.php/Lnbsharing-patch)
+    (seit 1.4.6.kw-005, seit 1.6.0-kw-006 entfernt mangels Nutzung)
+
+  * recordsshowfree-patch 0.2  //kw
+    Der Patch ist für die Anzeige des freien Platzes auf der Platte auch 
+    auf der Aufnahmenlisteseite. Bislang wird der freie Platz nur im 
+    vdr-Hauptmenü angezeigt. Viel nützlicher ist er aber auf der Seite 
+    mit der Aufnahmeliste. Denn dort springt der gemeine vdr-Nutzer ja 
+    gerne mal direkt hin (Default: Rote Taste der Fernbedienung, 
+    sofern kein Menü angezeigt ist). 
+    http://www.u32.de/vdr-1.4.6-recordsshowfree-0.2.diff
+    (seit 1.4.6.kw-005, seit 1.6.0-kw-007 entfernt, da nun in vdr selber drin)
+  
+  
+
+==============================================================================
+simple-record-sort-patch (Aufnahmesortierung)
+==============================================================================
+Durch Betätigen der Taste "0" wird das aktuelle Aufnahmeverzeichnis sofort 
+umsortiert: Beim ersten Male wird es alphabetisch sortiert, beim zweiten 
+Male chronologisch, beim dritten Male wieder alphabetisch etc. Die neue 
+Sortierart wird bei Änderungen in der Statuszeile unten angezeigt.
+
+Die aktuelle Sortierart wird für jedes andere Aufnahmeverzeichnis, in das
+man danach wechselt beibehalten. Ausnahme: Das Hauptverzeichnis ist immer 
+chronologisch geordnet.
+
+Die Taste Null wurde in Analogie zur Kanalliste gewählt - auch dort dient 
+die Null der Sortierung. Das kollidiert zwar bei einigen Patchsammlungen 
+mit der Belegung der 0 zum Umbenennen von Aufnahmen. Aber einheitliche 
+Bedienung ist m.E. wichtiger. 
+
+Der Patch ist gegen ein originales vdr 1.3.37, sollte aber auch gegen 
+frühere Versionen funktionieren, da der Patch nur wenig ändert.
+
+==============================================================================
+Channelfilter 0.5
+==============================================================================
+ english text see below
+ 
+ Dieser Patch filtert in der Kanalliste (Punkt 2 im Hauptmenü)
+ bei Bedarf unerwünschte Einträge, was die Übersichtlichkeit erhöhen kann.
+ Ausserdem werden in der Liste Kanalattribute angezeigt:
+  "t" = TV
+  "v" = TV ohne Ton
+  "r" = Radio
+  "d" = Dolby
+  "x" = verschlüsselt
+ 
+ Drückt man in der Liste die Taste "0 und dann die Taste "1", so werden nur noch Fernsehsender 
+ angezeigt (also keine Radiosender, keine veraltete Einträge, keine reine
+ Datenkanäle und keine Standbildersender). Nochmaliges "0" "1" blendet sie wieder ein.
+ 
+ Drückt man die Tasten "0" und dann "2" so werden nur noch Radiosender angezeigt.
+ Nochmaliges "0" "2" blendet sie wieder ein.
+ 
+ Drückt man die "0" und dann die "3", so werden alle verschlüsselten 
+ Kanäle (caid>4) ausgeblendet. Somit sind nur noch die sogenannten "free to air"-Sender sichtbar.
+ 
+ Drückt man die "0" "3" nochmal, so werden die verschlüsselten Kanäle 
+ wieder eingeblendet. Das funktioniert auch im Zusammenhang mit den 
+ anderen Filtern: Drückt man z.B. die "0" "1" und dann die "0" "3", so werden nur
+ unverschlüsselte TV-Kanäle aufgelistet.
+ 
+ Das Filtern funktioniert auch zusammen mit dem vdr-eigenen 
+ Sortieren, das mit diesem Patch aber auch den 0-Prefix benötigt: 
+ Drücken von "0" "0" sortiert die Sender alphabetisch. Nochmaliges
+ "0" "0" sortiert nach Transponder und ein weiteres "0" "0" 
+ sortiert wieder original nach Kanalnummern.
+ 
+ Die Taste "0" "9" schaltet alle Filter jederzeit aus; die Sortierung bleibt davon unberührt.
+ 
+ Der Patch ist auf vdr 1.4.3 und vdr 1.4.5 getestet. 
+ Es fehlen allerdings noch die Übersetzungen.
+ 
+ Eine Header-Datei wurde geändert, daher müssen die Plugins auch 
+ neu übersetzt werden: "make plugins".
+ 
+ Homepage www.u32.de/vdr.html#patches
+ Fehlerberichte an  vdrpatch [at] u32.de
+ 
+ 0.4: Jetzt sind in der Kanalsicht auch die Kanale erreichbar, die eine Null 
+      enthalten (101, 1230 etc.) (seit Patch 1.4.5-kw-004)
+ 0.5: Ausgabe      
+ 
+ 
+------- Alternative Channel ------ 
+ 
+Was macht der Patch?
+Der Patch erweitert VDR um die Möglichkeit, jedem Kanal einen Alternativ-Kanal für eine Aufnahme zu hinterlegen. Damit ist es möglich in einem System mit mehreren Empfangsarten (z.B. DVB-C und analoge Kanäle) einen Fallback auf einen anlogen Kanal für die Aufnahme eines qualitativ besseren DVB-C Kanals einzurichten.
+
+Was bringt mir das?
+Man kann damit für alle Aufnahmen den vermeindlich besseren DVB-C Kanal 
+im Timer hinterlegen. Ist für diesen Kanal keine DVB-C Karte beim 
+Timer-Start verfügbar, dann versucht VDR den alternativen analog-Kanal
+ für die Aufnahme zu verwenden. Ist dieser auch nicht verfügbar wird's
+  wohl nix mit der Aufnahme.  
+
+Wie nutze ich den Patch?
+[[...]]
+Nun muss man die Konfigurationsdatei anpassen. Dazu hinterlegt man in dieser
+ Datei pro Kanal für den man diese Funktion nutzen will ein ChannelID-Paar 
+ im Format ChannelID;alternativeChannelID. Diese Zeile bedeutet: wenn bei 
+ einer Aufnahme des Kanals mit der channel ID ChannelID dieser Kanal nicht
+  verfügbar ist, benutze stattdessen den Kanal mit der ID alternativeChannelID.
+
+Wie bekomme ich die ChannelIDs raus?
+Am einfachsten mit dem Perl-Skript "printchannels.pl" aus dem tvmovie2vdr-Pakets.
+
+Was macht der Patch nicht?
+Er ändert nichts am Verhalten des VDRs beim Live-TV.
+
+!!! Achtung !!!
+Dieser Patch greift aktiv in das Aufnahmeverhalten (zumindest bei den in der channel_alternative.conf aufgelisteten Kanäle) ein. Somit sollte nach der Installation des Patches das Aufnahmeverhalten für eben diese Kanäle beobachtet werden! 
+ 
+- ----------- english ------------------------------------------------------------------
+ 
+ (out of date; only valid for channelfilter 0.0.2)
+ 
+ This patch filters the channel list on demand. 
+ A additional column of channel attributes is also added:
+  "t" = TV
+  "r" = radio
+  "d" = dolby
+  "x" = encrypted
+ 
+ Pressing the key "2" in the channel list hides all non TV channels.
+ 
+ Pressing the key "3" hides all non radio channels.
+ 
+ Pressing the key "4" hides all encrypted channesls (caid>4) 
+ Pressing the "4" again shows the encrypted channels again.
+ This works also in conjunction with the other filters.
+ e.g. pressing "2" and then "4", results in a list containing only 
+ unencrypted tv channels.
+ 
+ The filtering works also together with vdr's own sorting (key "0")
+ 
+ Pressing "1" or closing and reopening the channel list
+ resets any filtering.
+ 
+ I tested the patch against vdr 1.3.31 and vdr 1.3.33. It should 
+ also works with older 1.3.x-Versions. There are no translations yet. I'll 
+ add them after final bugfixing.
+ 
+ Install it as usual in the source directory of vdr
+   patch -p1 < vdr-1.3.xx-channelfilter-0.1.diff
+   make
+   make plugins
+ (a header file was changed, so plugin needs to be rebuild too)
+ 
+ Homepage www.u32.de/vdr.html#patches
+ Reports Bugs to  vdrpatch [at] u32.de
+kw-Patches
+==========
+
+Hier die Patches, die andere oder ich erstellt haben 
+und die ich selbst nutze. Die erste Version basierte auf dem enAIO-Patch,
+der seinerseits diverse Patches zusammenfasste. Inzwischen ähnelt meine
+Sammlung dem liemikuutio-Patch (http://www.saunalahti.fi/~rahrenbe/vdr/patches/). 
+Offenbar hat dessen Entwickler Rolf Ahrenberg unabhängig von mir ähnliche
+Patches darin aufgenommen. Da es ungezählte Varianten der enthaltenen Patches
+gibt, und auch ich nicht mehr weiß, welche der zahlreichen meist minimalen 
+Änderungen von mir und welche von anderen Autoren stammt ist folgende Aufzählung 
+möglicherweise nicht ganz komplett. 
+
+Derzeit (vdr 1.4.6-kw-005) sind folgende Patches enthalten:
+
+  * vdr-1.4.7-audioindexer.patch   (von Reinhard Nissl)
+   "you may have noticed that radio recordings report a length which is much
+    larger than the actual playtime of the recording. This is a result of
+    VDR generating an index entry for every audio frame, but audio frames
+    provide most often only 24 ms of music while VDR's recording length
+    calculation is based on 40 ms per index entry.
+    The attached patch fixes cRemux to only generate an index entry whenever
+    the recorded amount of music crosses a 40 ms boundary."
+    (seit 25.10.07)
+
+  * recordsshowfree-patch 0.2  //kw
+    Der Patch ist für die Anzeige des freien Platzes auf der Platte auch 
+    auf der Aufnahmenlisteseite. Bislang wird der freie Platz nur im 
+    vdr-Hauptmenü angezeigt. Viel nützlicher ist er aber auf der Seite 
+    mit der Aufnahmeliste. Denn dort springt der gemeine vdr-Nutzer ja 
+    gerne mal direkt hin (Default: Rote Taste der Fernbedienung, 
+    sofern kein Menü angezeigt ist). 
+    http://www.u32.de/vdr-1.4.6-recordsshowfree-0.2.diff
+    (seit 1.4.6.kw-005)
+
+  * Alternative channel-patch (vdr-1.4.0_AlternativeChannelPatch_0.0.3) //acp    
+    Der Patch erweitert VDR um die Möglichkeit, jedem Kanal einen Alternativ-Kanal
+    für eine Aufnahme zu hinterlegen. Damit ist es möglich in einem System mit 
+    mehreren Empfangsarten (z.B. DVB-C und analoge Kanäle) einen Fallback auf 
+    einen analogen Kanal für die Aufnahme eines qualitativ besseren DVB-C Kanals 
+    einzurichten. (http://www.vdr-portal.de/board/thread.php?threadid=52862)
+    Für diesen muß im vdr-Config-Verzeichnis ein Datei namens 
+    channels_alternative.conf vorhanden sein. Das Originalannoncement steht unten
+    (seit 1.4.6.kw-005)
+
+  * Lnbsharing-patch (configurableLNBshare-VDR_1.4.3.patch) //ML
+    Mit dem LNB-Sharing-Patch können zwei oder mehr DVB-Karten ein Kabel sowie
+    den angeschlossenen LNB gleichzeitig nutzen, ohne dass es zu gegenseitigen
+    Störungen kommt. (http://lötzke.de/vdr.html, http://www.vdr-wiki.de/wiki/index.php/Lnbsharing-patch)
+    (seit 1.4.6.kw-005)
+
+  * w_epgfix    
+    zur Vermeidung doppelter EPG-Einträge bei schlampigen EPG-Anbietern (z.B. Prosiebensat1)
+    von vdr-Portal-User Wirbel (http://www.vdr-portal.de/board/profile.php?userid=4146) und 
+    "Norad" (http://www.vdr-portal.de/board/profile.php?userid=5190)
+    Thread: http://www.vdr-portal.de/board/thread.php?threadid=36640&threadview=0&hilight=&hilightuser=0&page=1
+    Download: http://www.vdr-portal.de/board/attachment.php?attachmentid=10284    
+    (seit 1.4.3-kw-003)
+
+  * Cuttime-Patch (2006-05-14) von Udo Richter  // +cuttime-patch
+    (http://www.richter-udo.de/vdr/patches.html#cuttime)
+    Ändert beim Schneiden die Zeit im Verzeichnisnamen,
+    dadurch kann dieselbe Sendung mehrfach geschnitten werden, ohne
+    vorherige Schnittergebnisse zu löschen
+    (seit 1.4.2-kw)
+
+  * Rename Recordings Patch von Torsten Kunkel ( // tk-rrp )
+    (http://www.vdr-wiki.de/wiki/index.php/Renamerecordings-patch)
+    Umbennen von Aufzeichnungen per Fernbedienung
+
+  * Menu Selection Patch von Peter Dittmann 
+    (http://www.vdr-wiki.de/wiki/index.php/Menuselection-patch)
+    Es können alle Menüpunkte, auch die größer 9,
+    per Zahleneingabe angesprungen werden.
+
+  * Recording-Length-Patch von Tobias Faust ( // tf-rlp )
+    (http://www.vdr-portal.de/board/thread.php?threadid=40417, geändert lt. 
+    "liemikuutio"-Patch).
+    Zeigt die Länge von Aufzeichnungen an. 
+    
+  * Channelfilter-Patch 0.5 von Walter Koch ( // kw-cfp )
+    Filtern der Kanalliste. Beschreibung siehe unten
+
+  * Singlestep/JumpingSecond-Patch von Tobias Faust und Walter Koch
+
+  * Einfaches Aufzeichnungssortieren-Patch (simple record sort patch) 
+    von Walter Koch ( //kw-srsp ). Anleitung s.u.
+
+  * Patch zum Ersetzen des Menüpunktes "Programm" durch das EPGSEARCH-Plugin
+    falls vorhanden. Dieser Patch funktioniert auch ohne das EPGSEARCH-Plugin.
+    Dieser Patch stammt aus dem EPGSEARCH-Plugin (http://freenet-homepage.de/cwieninger/html/vdr-epg-search.html).
+
+  * Wareagle-Iconpatch 
+    (http://www.vdr-wiki.de/wiki/index.php/Wareagleicon-patch)
+    Mit willkürlichen Änderungen meinerseits.
+  
+  * Diverse kleine Layoutänderungen von OSD-Listen u.ä.  
+  
+  * Klarere deutsche Texte ("Ändern" statt "Edit", "Programmvorschau" 
+    statt "Programm" u.ä.)
+
+Der Status des "Show Weekdays Patch" von Oskar Signell
+ist mir derzeit unklar. 
+
+Der ursprünglich enthaltene Easy-Input-Patch ist seit vdr 1.3.38 in
+vdr integriert und daher nicht mehr drin.
+
+"kw" ist übrigens das Kürzel, welches ich seit Urzeiten für
+Quellcodekommentare nutze. 
+
+Gruss,
+  Walter
+
+==============================================================================
+simple-record-sort-patch (Aufnahmesortierung)
+==============================================================================
+Durch Betätigen der Taste "0" wird das aktuelle Aufnahmeverzeichnis sofort 
+umsortiert: Beim ersten Male wird es alphabetisch sortiert, beim zweiten 
+Male chronologisch, beim dritten Male wieder alphabetisch etc. Die neue 
+Sortierart wird bei Änderungen in der Statuszeile unten angezeigt.
+
+Die aktuelle Sortierart wird für jedes andere Aufnahmeverzeichnis, in das
+man danach wechselt beibehalten. Ausnahme: Das Hauptverzeichnis ist immer 
+chronologisch geordnet.
+
+Die Taste Null wurde in Analogie zur Kanalliste gewählt - auch dort dient 
+die Null der Sortierung. Das kollidiert zwar bei einigen Patchsammlungen 
+mit der Belegung der 0 zum Umbenennen von Aufnahmen. Aber einheitliche 
+Bedienung ist m.E. wichtiger. 
+
+Der Patch ist gegen ein originales vdr 1.3.37, sollte aber auch gegen 
+frühere Versionen funktionieren, da der Patch nur wenig ändert.
+
+==============================================================================
+Channelfilter 0.5
+==============================================================================
+ english text see below
+ 
+ Dieser Patch filtert in der Kanalliste (Punkt 2 im Hauptmenü)
+ bei Bedarf unerwünschte Einträge, was die Übersichtlichkeit erhöhen kann.
+ Ausserdem werden in der Liste Kanalattribute angezeigt:
+  "t" = TV
+  "v" = TV ohne Ton
+  "r" = Radio
+  "d" = Dolby
+  "x" = verschlüsselt
+ 
+ Drückt man in der Liste die Taste "0 und dann die Taste "1", so werden nur noch Fernsehsender 
+ angezeigt (also keine Radiosender, keine veraltete Einträge, keine reine
+ Datenkanäle und keine Standbildersender). Nochmaliges "0" "1" blendet sie wieder ein.
+ 
+ Drückt man die Tasten "0" und dann "2" so werden nur noch Radiosender angezeigt.
+ Nochmaliges "0" "2" blendet sie wieder ein.
+ 
+ Drückt man die "0" und dann die "3", so werden alle verschlüsselten 
+ Kanäle (caid>4) ausgeblendet. Somit sind nur noch die sogenannten "free to air"-Sender sichtbar.
+ 
+ Drückt man die "0" "3" nochmal, so werden die verschlüsselten Kanäle 
+ wieder eingeblendet. Das funktioniert auch im Zusammenhang mit den 
+ anderen Filtern: Drückt man z.B. die "0" "1" und dann die "0" "3", so werden nur
+ unverschlüsselte TV-Kanäle aufgelistet.
+ 
+ Das Filtern funktioniert auch zusammen mit dem vdr-eigenen 
+ Sortieren, das mit diesem Patch aber auch den 0-Prefix benötigt: 
+ Drücken von "0" "0" sortiert die Sender alphabetisch. Nochmaliges
+ "0" "0" sortiert nach Transponder und ein weiteres "0" "0" 
+ sortiert wieder original nach Kanalnummern.
+ 
+ Die Taste "0" "9" schaltet alle Filter jederzeit aus; die Sortierung bleibt davon unberührt.
+ 
+ Der Patch ist auf vdr 1.4.3 und vdr 1.4.5 getestet. 
+ Es fehlen allerdings noch die Übersetzungen.
+ 
+ Eine Header-Datei wurde geändert, daher müssen die Plugins auch 
+ neu übersetzt werden: "make plugins".
+ 
+ Homepage www.u32.de/vdr.html#patches
+ Fehlerberichte an  vdrpatch [at] u32.de
+ 
+ 0.4: Jetzt sind in der Kanalsicht auch die Kanale erreichbar, die eine Null 
+      enthalten (101, 1230 etc.) (seit Patch 1.4.5-kw-004)
+ 0.5: Ausgabe      
+ 
+ 
+------- Alternative Channel ------ 
+ 
+Was macht der Patch?
+Der Patch erweitert VDR um die Möglichkeit, jedem Kanal einen Alternativ-Kanal für eine Aufnahme zu hinterlegen. Damit ist es möglich in einem System mit mehreren Empfangsarten (z.B. DVB-C und analoge Kanäle) einen Fallback auf einen anlogen Kanal für die Aufnahme eines qualitativ besseren DVB-C Kanals einzurichten.
+
+Was bringt mir das?
+Man kann damit für alle Aufnahmen den vermeindlich besseren DVB-C Kanal 
+im Timer hinterlegen. Ist für diesen Kanal keine DVB-C Karte beim 
+Timer-Start verfügbar, dann versucht VDR den alternativen analog-Kanal
+ für die Aufnahme zu verwenden. Ist dieser auch nicht verfügbar wird's
+  wohl nix mit der Aufnahme.  
+
+Wie nutze ich den Patch?
+[[...]]
+Nun muss man die Konfigurationsdatei anpassen. Dazu hinterlegt man in dieser
+ Datei pro Kanal für den man diese Funktion nutzen will ein ChannelID-Paar 
+ im Format ChannelID;alternativeChannelID. Diese Zeile bedeutet: wenn bei 
+ einer Aufnahme des Kanals mit der channel ID ChannelID dieser Kanal nicht
+  verfügbar ist, benutze stattdessen den Kanal mit der ID alternativeChannelID.
+
+Wie bekomme ich die ChannelIDs raus?
+Am einfachsten mit dem Perl-Skript "printchannels.pl" aus dem tvmovie2vdr-Pakets.
+
+Was macht der Patch nicht?
+Er ändert nichts am Verhalten des VDRs beim Live-TV.
+
+!!! Achtung !!!
+Dieser Patch greift aktiv in das Aufnahmeverhalten (zumindest bei den in der channel_alternative.conf aufgelisteten Kanäle) ein. Somit sollte nach der Installation des Patches das Aufnahmeverhalten für eben diese Kanäle beobachtet werden! 
+ 
+- ----------- english ------------------------------------------------------------------
+ 
+ (out of date; only valid for channelfilter 0.0.2)
+ 
+ This patch filters the channel list on demand. 
+ A additional column of channel attributes is also added:
+  "t" = TV
+  "r" = radio
+  "d" = dolby
+  "x" = encrypted
+ 
+ Pressing the key "2" in the channel list hides all non TV channels.
+ 
+ Pressing the key "3" hides all non radio channels.
+ 
+ Pressing the key "4" hides all encrypted channesls (caid>4) 
+ Pressing the "4" again shows the encrypted channels again.
+ This works also in conjunction with the other filters.
+ e.g. pressing "2" and then "4", results in a list containing only 
+ unencrypted tv channels.
+ 
+ The filtering works also together with vdr's own sorting (key "0")
+ 
+ Pressing "1" or closing and reopening the channel list
+ resets any filtering.
+ 
+ I tested the patch against vdr 1.3.31 and vdr 1.3.33. It should 
+ also works with older 1.3.x-Versions. There are no translations yet. I'll 
+ add them after final bugfixing.
+ 
+ Install it as usual in the source directory of vdr
+   patch -p1 < vdr-1.3.xx-channelfilter-0.1.diff
+   make
+   make plugins
+ (a header file was changed, so plugin needs to be rebuild too)
+ 
+ Homepage www.u32.de/vdr.html#patches
+ Reports Bugs to  vdrpatch [at] u32.de
diff -u vdr-1.6.0/recording.c vdr-1.6.0-kw-006/recording.c
--- vdr-1.6.0/recording.c	2008-02-24 11:28:53.000000000 +0100
+++ vdr-1.6.0-kw-006/recording.c	2008-03-24 21:21:36.000000000 +0100
@@ -8,6 +8,7 @@
  */
 
 #include "recording.h"
+#include "iconpatch.h"   // kw 
 #include <ctype.h>
 #include <dirent.h>
 #include <errno.h>
@@ -46,6 +47,7 @@
 #endif
 #define INFOFILESUFFIX    "/info.vdr"
 #define MARKSFILESUFFIX   "/marks.vdr"
+#define INDEXFILESUFFIX   "/index.vdr"   // tf-rlp   // moved up from cIndexFile (Line 1147, unpatched)
 
 #define MINDISKSPACE 1024 // MB
 
@@ -62,6 +64,7 @@
 #define MAX_LINK_LEVEL  6
 
 bool VfatFileSystem = false;
+bool DirOrderState = false; // kw-srsp
 
 cRecordings DeletedRecordings(true);
 
@@ -647,6 +650,8 @@
 
 char *cRecording::StripEpisodeName(char *s)
 {
+// In:   Ein_Herz_und_eine_Seele/Der_Ofen_ist_aus/2005-11-25.20.55.43.99.rec
+// Out:  Ein_Herz_und_eine_Seele//2005-11-25.20.55.43.99.rec
   char *t = s, *s1 = NULL, *s2 = NULL;
   while (*t) {
         if (*t == '/') {
@@ -659,9 +664,10 @@
               s1 = t;
            }
         t++;
-        }
+        } 
   if (s1 && s2)
-     memmove(s1 + 1, s2, t - s2 + 1);
+      memmove(s1 + 1, s2, t - s2 + 1);	
+      
   return s;
 }
 
@@ -690,7 +696,9 @@
 int cRecording::Compare(const cListObject &ListObject) const
 {
   cRecording *r = (cRecording *)&ListObject;
-  return strcasecmp(SortName(), r->SortName());
+  if (DirOrderState)  // kw-srsp
+     return strcasecmp(FileName(), r->FileName()); // kw-srsp
+  return strcasecmp(SortName(), r->SortName()) ;
 }
 
 const char *cRecording::FileName(void) const
@@ -703,11 +711,11 @@
      name = ExchangeChars(name, false);
      }
   return fileName;
-}
+}                                                                             
 
-const char *cRecording::Title(char Delimiter, bool NewIndicator, int Level) const
+const char *cRecording::Title(char Delimiter, bool NewIndicator, int Level, bool Original) const
 {
-  char New = NewIndicator && IsNew() ? '*' : ' ';
+  char New = NewIndicator && IsNew() && Setup.ShowRecNew ? Setup.WarEagleIcons ? ICON_NEU : '*' : ' ';
   free(titleBuffer);
   titleBuffer = NULL;
   if (Level < 0 || Level == HierarchyLevels()) {
@@ -718,7 +726,8 @@
         s++;
      else
         s = name;
-     titleBuffer = strdup(cString::sprintf("%02d.%02d.%02d%c%02d:%02d%c%c%s",
+     if (Original) { // tf-rlp 
+        titleBuffer = strdup(cString::sprintf("%02d.%02d.%02d%c%02d:%02d%c%c%s",
                             t->tm_mday,
                             t->tm_mon + 1,
                             t->tm_year % 100,
@@ -728,6 +737,47 @@
                             New,
                             Delimiter,
                             s));
+ // Start tf-rlp, small mods by kw 
+         }
+      else {
+         char RecLength[21], RecDate[9], RecTime[6], RecDelimiter[2];
+         snprintf(RecLength, sizeof(RecLength), "---");
+         if (Setup.ShowRecLength && FileName()) {
+            char *filename = NULL;
+            asprintf(&filename, "%s%s", FileName(), INDEXFILESUFFIX);
+            
+            if (filename) {
+               if (access(filename, R_OK) == 0) {
+                  struct stat buf;
+                  if (stat(filename, &buf) == 0) {
+                     struct tIndex { int offset; uchar type; uchar number; short reserved; };
+                     int delta = buf.st_size % sizeof(tIndex);
+                     if (delta) {
+                        delta = sizeof(tIndex) - delta;
+                        esyslog("ERROR: invalid file size (%ld) in '%s'", buf.st_size, filename);
+                        }
+                     snprintf(RecLength, sizeof(RecLength), "%ld'", (buf.st_size + delta) / sizeof(tIndex) / SecondsToFrames(60));
+                     }
+                  }
+               free(filename);
+               }
+            }
+         snprintf(RecDate, sizeof(RecDate), "%02d.%02d.%02d", t->tm_mday, t->tm_mon + 1, t->tm_year % 100);
+         snprintf(RecTime, sizeof(RecTime), "%02d:%02d", t->tm_hour, t->tm_min);
+         snprintf(RecDelimiter, sizeof(RecDelimiter), "%c", Delimiter);
+         asprintf(&titleBuffer, "%s%s%s%c%s%s%s%s",  
+                                (Setup.ShowRecDate ? RecDate                               : ""),
+                                (Setup.ShowRecDate && Setup.ShowRecTime ? RecDelimiter     : ""),
+                                (Setup.ShowRecTime ? RecTime                               : ""),
+                                New,
+ 
+                                (Setup.ShowRecTime || Setup.ShowRecDate ? RecDelimiter : ""),
+                                (Setup.ShowRecLength ? RecLength    : ""),
+                                (Setup.ShowRecLength ? RecDelimiter : ""),
+                                s);
+         }
+ // end tf-rlp         
+ 
      // let's not display a trailing '~':
      if (!NewIndicator)
         stripspace(titleBuffer);
@@ -756,6 +806,17 @@
   return titleBuffer;
 }
 
+//cuttime-patch begin
+void cRecording::SetStartTime(time_t Start) 
+{ 
+  start=Start;    
+  if (fileName) {   
+  	 free(fileName);   
+  	 fileName = NULL;   
+  	 }   
+}  
+//cuttime-patch end
+
 const char *cRecording::PrefixFileName(char Prefix)
 {
   cString p = PrefixVideoFileName(FileName(), Prefix);
@@ -830,7 +891,7 @@
      return false;
      }
   isyslog("removing recording %s", FileName());
-  return RemoveVideoFile(FileName());
+  return RemoveVideoFile(FileName());          
 }
 
 bool cRecording::Undelete(void)
@@ -864,6 +925,46 @@
   resume = RESUME_NOT_INITIALIZED;
 }
 
+bool cRecording::Rename(char *newName, int *newPriority, int *newLifetime)
+{
+  bool result = false;
+  char *newFileName;
+  struct tm tm_r;
+  struct tm *t = localtime_r(&start, &tm_r);
+#ifdef VFAT
+  char *localNewName = ExchangeChars(strdup(newName), true);
+  asprintf(&newFileName, NAMEFORMAT, VideoDirectory, localNewName, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, *newPriority, *newLifetime);
+  free (localNewName);
+#else
+  asprintf(&newFileName, NAMEFORMAT, VideoDirectory, ExchangeChars(newName, true), t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, *newPriority, *newLifetime);
+#endif
+  if (strcmp(FileName(), newFileName)) {
+     if (access(newFileName, F_OK) == 0) {
+        isyslog("recording %s already exists", newFileName);
+        }
+     else {
+        isyslog("renaming recording %s to %s", FileName(), newFileName);
+        result = MakeDirs(newFileName, true);
+        if (result)
+           result = RenameVideoFile(FileName(), newFileName);
+        if (result) {
+           priority = *newPriority;
+           lifetime = *newLifetime;
+           free(fileName);
+           fileName = strdup(newFileName);
+           free(name);
+           name = strdup(newName);
+           free(sortBuffer);
+           sortBuffer = NULL;
+           free(titleBuffer);
+           titleBuffer = NULL;
+           }
+        }
+     }
+  free(newFileName);
+  return result;
+}
+
 // --- cRecordings -----------------------------------------------------------
 
 cRecordings Recordings;
@@ -1172,8 +1273,6 @@
 //XXX+ somewhere else???
 // --- cIndexFile ------------------------------------------------------------
 
-#define INDEXFILESUFFIX     "/index.vdr"
-
 // The number of frames to stay off the end in case of time shift:
 #define INDEXSAFETYLIMIT 150 // frames
 
diff -u vdr-1.6.0/recording.h vdr-1.6.0-kw-006/recording.h
--- vdr-1.6.0/recording.h	2007-10-14 12:11:34.000000000 +0200
+++ vdr-1.6.0-kw-006/recording.h	2008-03-24 19:52:32.000000000 +0100
@@ -19,6 +19,7 @@
 #include "tools.h"
 
 extern bool VfatFileSystem;
+extern bool DirOrderState;  // kw-srsp
 
 void RemoveDeletedRecordings(void);
 void AssertFreeDiskSpace(int Priority = 0, bool Force = false);
@@ -88,8 +89,9 @@
   virtual int Compare(const cListObject &ListObject) const;
   const char *Name(void) const { return name; }
   const char *FileName(void) const;
-  const char *Title(char Delimiter = ' ', bool NewIndicator = false, int Level = -1) const;
+  const char *Title(char Delimiter = ' ', bool NewIndicator = false, int Level = -1, bool Original = false) const;
   const cRecordingInfo *Info(void) const { return info; }
+  void SetStartTime(time_t Start);  //+cuttime-patch
   const char *PrefixFileName(char Prefix);
   int HierarchyLevels(void) const;
   void ResetResume(void) const;
@@ -106,6 +108,9 @@
        // Changes the file name so that it will be visible in the "Recordings" menu again and
        // not processed by cRemoveDeletedRecordingsThread.
        // Returns false in case of error
+  bool Rename(char *newName, int *newPriority, int *newLifetime);
+       // Changes the file name
+       // Returns false in case of error
   };
 
 class cRecordings : public cList<cRecording>, public cThread {
diff -u vdr-1.6.0/remux.c vdr-1.6.0-kw-006/remux.c
--- vdr-1.6.0/remux.c	2007-11-25 14:56:03.000000000 +0100
+++ vdr-1.6.0-kw-006/remux.c	2008-03-29 14:54:42.000000000 +0100
@@ -19,6 +19,7 @@
 #include "channels.h"
 #include "shutdown.h"
 #include "tools.h"
+#include "recording.h"  //ai
 
 ePesHeader AnalyzePesHeader(const uchar *Data, int Count, int &PesPayloadOffset, bool *ContinuationHeader)
 {
@@ -238,6 +239,8 @@
   return true;
 }
 
+
+
 // --- cVideoRepacker --------------------------------------------------------
 
 class cVideoRepacker : public cCommonRepacker {
@@ -690,12 +693,15 @@
   int frameTodo;
   int frameSize;
   int cid;
-  static bool IsValidAudioHeader(uint32_t Header, bool Mpeg2, int *FrameSize = NULL);
+  static bool IsValidAudioHeader(uint32_t Header, bool Mpeg2, int *FrameSize = NULL 
+                                 , int *FrameDuration = NULL //ai
+                                 );
 public:
   cAudioRepacker(int Cid);
   virtual void Reset(void);
   virtual void Repack(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count);
   virtual int BreakAt(const uchar *Data, int Count);
+  static int GetFrameDuration(const uchar *Data, int Count, int *TrackIndex = NULL); //ai
   };
 
 int cAudioRepacker::bitRates[2][3][16] = { // all values are specified as kbits/s
@@ -711,6 +717,27 @@
   }
   };
 
+//ai start  
+int cAudioRepacker::GetFrameDuration(const uchar *Data, int Count, int *TrackIndex)
+{
+  int PesPayloadOffset = 0;
+  ePesHeader PH = AnalyzePesHeader(Data, Count, PesPayloadOffset);
+  if (PH < phMPEG1)
+     return -1;
+
+  const uchar *Payload = Data + PesPayloadOffset;
+  const int PayloadCount = Count - PesPayloadOffset;
+
+  int FrameDuration = -1;
+  if ((Data[3] & 0xE0) == 0xC0 && PayloadCount >= 4) {
+     if (IsValidAudioHeader(((Payload[0] << 8 | Payload[1]) << 8 | Payload[2]) << 8 | Payload[3], PH == phMPEG2, NULL, &FrameDuration) && TrackIndex)
+        *TrackIndex = Data[3] - 0xC0;
+     }
+
+  return FrameDuration;
+}
+//ai ende
+
 cAudioRepacker::cAudioRepacker(int Cid)
 {
   cid = Cid;
@@ -726,7 +753,7 @@
   frameSize = 0;
 }
 
-bool cAudioRepacker::IsValidAudioHeader(uint32_t Header, bool Mpeg2, int *FrameSize)
+bool cAudioRepacker::IsValidAudioHeader(uint32_t Header, bool Mpeg2, int *FrameSize, int *FrameDuration)
 {
   int syncword           = (Header & 0xFFF00000) >> 20;
   int id                 = (Header & 0x00080000) >> 19;
@@ -760,32 +787,36 @@
   if (emphasis == 2) // reserved
      return false;
 
-  if (FrameSize) {
-     if (bitrate_index == 0)
-        *FrameSize = 0;
-     else {
-        static int samplingFrequencies[2][4] = { // all values are specified in Hz
-          { 44100, 48000, 32000, -1 }, // MPEG 1
-          { 22050, 24000, 16000, -1 }  // MPEG 2
-          };
-
-        static int slots_per_frame[2][3] = {
-          { 12, 144, 144 }, // MPEG 1, Layer I, II, III
-          { 12, 144,  72 }  // MPEG 2, Layer I, II, III
-          };
-
-        int mpegIndex = 1 - id;
-        int layerIndex = 3 - layer;
-
-        // Layer I (i. e., layerIndex == 0) has a larger slot size
-        int slotSize = (layerIndex == 0) ? 4 : 1; // bytes
-
-        int br = 1000 * bitRates[mpegIndex][layerIndex][bitrate_index]; // bits/s
-        int sf = samplingFrequencies[mpegIndex][sampling_frequency];
-
-        int N = slots_per_frame[mpegIndex][layerIndex] * br / sf; // slots
+  if (FrameSize || FrameDuration) {
+     static int samplingFrequencies[2][4] = { // all values are specified in Hz
+       { 44100, 48000, 32000, -1 }, // MPEG 1
+       { 22050, 24000, 16000, -1 }  // MPEG 2
+       };
+
+     static int slots_per_frame[2][3] = {
+       { 12, 144, 144 }, // MPEG 1, Layer I, II, III
+       { 12, 144,  72 }  // MPEG 2, Layer I, II, III
+       };
+
+     int mpegIndex = 1 - id;
+     int layerIndex = 3 - layer;
+
+     // Layer I (i. e., layerIndex == 0) has a larger slot size
+     int slotSize = (layerIndex == 0) ? 4 : 1; // bytes
+     int sf = samplingFrequencies[mpegIndex][sampling_frequency];
+
+     if (FrameDuration)
+        *FrameDuration = 90000 * 8 * slotSize * slots_per_frame[mpegIndex][layerIndex] / sf;
+
+     if (FrameSize) {
+        if (bitrate_index == 0)
+           *FrameSize = 0;
+        else {
+           int br = 1000 * bitRates[mpegIndex][layerIndex][bitrate_index]; // bits/s
+           int N = slots_per_frame[mpegIndex][layerIndex] * br / sf; // slots
 
-        *FrameSize = (N + padding_bit) * slotSize; // bytes
+           *FrameSize = (N + padding_bit) * slotSize; // bytes
+           }
         }
      }
 
@@ -1086,6 +1117,7 @@
   virtual void Reset(void);
   virtual void Repack(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count);
   virtual int BreakAt(const uchar *Data, int Count);
+  static int GetFrameDuration(const uchar *Data, int Count, int *TrackIndex = NULL);
   };
 
 // frameSizes are in words, i. e. multiply them by 2 to get bytes
@@ -1112,6 +1144,33 @@
      0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
   };
 
+  
+//ai start
+int cDolbyRepacker::GetFrameDuration(const uchar *Data, int Count, int *TrackIndex)
+{
+  int PesPayloadOffset = 0;
+  ePesHeader PH = AnalyzePesHeader(Data, Count, PesPayloadOffset);
+  if (PH < phMPEG1)
+     return -1;
+
+  const uchar *Payload = Data + PesPayloadOffset;
+  const int PayloadCount = Count - PesPayloadOffset;
+
+  if (Data[3] == 0xBD && PayloadCount >= 9 && ((Payload[0] & 0xF0) == 0x80) && Payload[4] == 0x0B && Payload[5] == 0x77 && frameSizes[Payload[8]] > 0) {
+     if (TrackIndex)
+        *TrackIndex = Payload[0] - 0x80;
+
+     static int samplingFrequencies[4] = { // all values are specified in Hz
+       48000, 44100, 32000, -1
+       };
+
+     return 90000 * 1536 / samplingFrequencies[Payload[8] >> 6];
+     }
+
+  return -1;
+}
+//ai ende
+
 cDolbyRepacker::cDolbyRepacker(void)
 {
   pesHeader[0] = 0x00;
@@ -1892,6 +1951,59 @@
   return c;
 }
 
+//ai
+// --- cAudioIndexer ---------------------------------------------------------
+
+class cAudioIndexer {
+private:
+  int frameTrack;
+  int frameDuration;
+  int64_t trackTime[MAXAPIDS + MAXDPIDS];
+  int64_t nextIndexTime;
+  
+public:
+  cAudioIndexer(void);
+  void Clear(void);
+  void PrepareFrame(const uchar *Data, int Count, int Offset, uchar &PictureType);
+  void ProcessFrame(void);
+  };
+
+cAudioIndexer::cAudioIndexer(void)
+{
+  Clear();
+}
+
+void cAudioIndexer::Clear(void)
+{
+  memset(trackTime, 0, sizeof (trackTime));
+  nextIndexTime = 0;
+  frameTrack = -1;
+}
+
+void cAudioIndexer::PrepareFrame(const uchar *Data, int Count, int Offset, uchar &PictureType)
+{
+  frameDuration = cRemux::GetAudioFrameDuration(Data + Offset, Count - Offset, &frameTrack);
+  if (frameDuration <= 0)
+     return;
+
+  if (Data[Offset + 3] == 0xBD)
+     frameTrack += MAXAPIDS;
+
+  PictureType = (trackTime[frameTrack] >= nextIndexTime) ? I_FRAME : NO_PICTURE;
+}
+
+void cAudioIndexer::ProcessFrame(void)
+{
+  if (frameTrack < 0)
+     return;
+
+  if (trackTime[frameTrack] >= nextIndexTime)
+     nextIndexTime += 90000 / FRAMESPERSEC;
+
+  trackTime[frameTrack] += frameDuration;
+  frameTrack = -1;
+}
+//ai ende
 // --- cRemux ----------------------------------------------------------------
 
 #define RESULTBUFFERSIZE KILOBYTE(256)
@@ -1936,6 +2048,7 @@
      while (*SPids && numTracks < MAXTRACKS && n < MAXSPIDS)
            ts2pes[numTracks++] = new cTS2PES(*SPids++, resultBuffer, IPACKS, 0x00, 0x20 + n++);
      }
+  audioIndexer = (noVideo ? new cAudioIndexer : NULL); //ai
 }
 
 cRemux::~cRemux()
@@ -1943,7 +2056,21 @@
   for (int t = 0; t < numTracks; t++)
       delete ts2pes[t];
   delete resultBuffer;
+  delete audioIndexer; //ai
+}                      
+                       
+//ai start
+int cRemux::GetAudioFrameDuration(const uchar *Data, int Count, int *TrackIndex)
+{
+  if (Count <= 4)
+     return -1;
+
+  if (Data[3] == 0xBD)
+     return cDolbyRepacker::GetFrameDuration(Data, Count, TrackIndex);
+
+  return cAudioRepacker::GetFrameDuration(Data, Count, TrackIndex);
 }
+//ai end
 
 int cRemux::GetPid(const uchar *Data)
 {
@@ -2124,16 +2251,19 @@
                if (l < 0)
                   return resultData;
                if (noVideo) {
+                  uchar pt = NO_PICTURE;
+                  if (audioIndexer && !Count)
+                      audioIndexer->PrepareFrame(data, resultCount, i, pt); 
                   if (!synced) {
                      if (PictureType)
-                        *PictureType = I_FRAME;
+                         *PictureType = pt;
                      resultSkipped = i; // will drop everything before this position
                      synced = true;
                      }
                   else if (Count)
                      return resultData;
                   else if (PictureType)
-                     *PictureType = I_FRAME;
+                      *PictureType = pt;
                   }
                }
             if (synced) {
@@ -2154,6 +2284,8 @@
 void cRemux::Del(int Count)
 {
   resultBuffer->Del(Count);
+  if (audioIndexer && Count > 0)   //ai
+     audioIndexer->ProcessFrame(); //ai
 }
 
 void cRemux::Clear(void)
@@ -2161,6 +2293,8 @@
   for (int t = 0; t < numTracks; t++)
       ts2pes[t]->Clear();
   resultBuffer->Clear();
+  if (audioIndexer)  //ai
+     audioIndexer->Clear(); //ai
   synced = false;
   skipped = 0;
   resultSkipped = 0;
diff -u vdr-1.6.0/remux.h vdr-1.6.0-kw-006/remux.h
--- vdr-1.6.0/remux.h	2007-09-02 12:19:06.000000000 +0200
+++ vdr-1.6.0-kw-006/remux.h	2008-03-29 14:43:01.000000000 +0100
@@ -33,6 +33,7 @@
 #define MAXTRACKS 64
 
 class cTS2PES;
+class cAudioIndexer;  //ai
 
 class cRemux {
 private:
@@ -45,6 +46,7 @@
   int numTracks;
   cRingBufferLinear *resultBuffer;
   int resultSkipped;
+  cAudioIndexer *audioIndexer; //ai
   int GetPid(const uchar *Data);
 public:
   cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure = false);
@@ -79,6 +81,7 @@
   static void SetBrokenLink(uchar *Data, int Length);
   static int GetPacketLength(const uchar *Data, int Count, int Offset);
   static int ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType);
+  static int GetAudioFrameDuration(const uchar *Data, int Count, int *TrackIndex = NULL); //ai
   };
 
 #endif // __REMUX_H
diff -u vdr-1.6.0/svdrp.c vdr-1.6.0-kw-006/svdrp.c
--- vdr-1.6.0/svdrp.c	2008-02-17 14:36:01.000000000 +0100
+++ vdr-1.6.0-kw-006/svdrp.c	2008-03-24 21:23:45.000000000 +0100
@@ -293,6 +293,8 @@
   "    format defined in vdr(5) for the 'epg.data' file.  A '.' on a line\n"
   "    by itself terminates the input and starts processing of the data (all\n"
   "    entered data is buffered until the terminating '.' is seen).",
+  "RENR <number> <new name>\n"                                                     // tk-rrp
+  "    Rename recording. Number must be the Number as returned by LSTR command.",  // tk-rrp
   "REMO [ on | off ]\n"
   "    Turns the remote control on or off. Without a parameter, the current\n"
   "    status of the remote control is reported.",
@@ -1057,7 +1059,7 @@
   else if (recordings) {
      cRecording *recording = Recordings.First();
      while (recording) {
-           Reply(recording == Recordings.Last() ? 250 : -250, "%d %s", recording->Index() + 1, recording->Title(' ', true));
+           Reply(recording == Recordings.Last() ? 250 : -250, "%d %s", recording->Index() + 1, recording->Title(' ', true, -1, true));
            recording = Recordings.Next(recording);
            }
      }
@@ -1472,6 +1474,40 @@
   Reply(250, "EPG scan triggered");
 }
 
+// start tk-rrp
+void cSVDRP::CmdRENR(const char *Option)
+{
+  bool recordings = Recordings.Update(true);
+  if (recordings) {
+     if (*Option) {
+        char *tail;
+        int n = strtol(Option, &tail, 10);
+        cRecording *recording = Recordings.Get(n - 1);
+        if (recording && tail && tail != Option) {
+           int priority = recording->priority;
+           int lifetime = recording->lifetime;
+           char *oldName = strdup(recording->Name());
+           tail = skipspace(tail);
+           if (recording->Rename(tail, &priority, &lifetime)) {
+              Reply(250, "Renamed \"%s\" to \"%s\"", oldName, recording->Name());
+              Recordings.ChangeState();
+              Recordings.TouchUpdate();
+              }
+           else
+              Reply(501, "Renaming \"%s\" to \"%s\" failed", oldName, tail);
+           free(oldName);
+           }
+        else
+          Reply(501, "Recording not found or wrong syntax");
+        }
+     else
+        Reply(501, "Missing Input settings");
+     }
+  else
+     Reply(550, "No recordings available");
+}
+// end tk-rrp
+						
 void cSVDRP::CmdSTAT(const char *Option)
 {
   if (*Option) {
@@ -1587,6 +1623,7 @@
   else if (CMD("PLUG"))  CmdPLUG(s);
   else if (CMD("PUTE"))  CmdPUTE(s);
   else if (CMD("REMO"))  CmdREMO(s);
+  else if (CMD("RENR"))  CmdRENR(s);  // tk-rrp
   else if (CMD("SCAN"))  CmdSCAN(s);
   else if (CMD("STAT"))  CmdSTAT(s);
   else if (CMD("UPDT"))  CmdUPDT(s);
diff -u vdr-1.6.0/svdrp.h vdr-1.6.0-kw-006/svdrp.h
--- vdr-1.6.0/svdrp.h	2007-04-30 14:28:28.000000000 +0200
+++ vdr-1.6.0-kw-006/svdrp.h	2008-03-24 21:24:29.000000000 +0100
@@ -79,6 +79,7 @@
   void CmdPLUG(const char *Option);
   void CmdPUTE(const char *Option);
   void CmdREMO(const char *Option);
+  void CmdRENR(const char *Option);  // tk-rrp  
   void CmdSCAN(const char *Option);
   void CmdSTAT(const char *Option);
   void CmdUPDT(const char *Option);
Gemeinsame Unterverzeichnisse: vdr-1.6.0/symbols und vdr-1.6.0-kw-006/symbols.
diff -u vdr-1.6.0/vdr.c vdr-1.6.0-kw-006/vdr.c
--- vdr-1.6.0/vdr.c	2008-03-14 14:22:39.000000000 +0100
+++ vdr-1.6.0-kw-006/vdr.c	2008-03-29 14:23:50.000000000 +0100
@@ -571,7 +571,7 @@
         RecordingCommands.Load(AddDirectory(ConfigDirectory, "reccmds.conf"), true) &&
         SVDRPhosts.Load(AddDirectory(ConfigDirectory, "svdrphosts.conf"), true) &&
         Keys.Load(AddDirectory(ConfigDirectory, "remote.conf")) &&
-        KeyMacros.Load(AddDirectory(ConfigDirectory, "keymacros.conf"), true)
+        KeyMacros.Load(AddDirectory(ConfigDirectory, "keymacros.conf"), true) 
         ))
      EXIT(2);
 
