--- ../vdr-1.4.2-plain//device.c	2006-10-01 16:34:23.000000000 +0200
+++ device.c	2006-10-01 16:35:42.000000000 +0200
@@ -581,8 +581,10 @@
      int n = CurrentChannel() + Direction;
      int first = n;
      cChannel *channel;
-     while ((channel = Channels.GetByNumber(n, Direction)) != NULL) {
+     while ((channel = Channels.GetByNumber(n, Direction)) != NULL) 
+     {
            // try only channels which are currently available
+        if (cStatus::MsgChannelProtected(0, channel) == false)      // PIN PATCH
            if (PrimaryDevice()->ProvidesChannel(channel, Setup.PrimaryLimit) || PrimaryDevice()->CanReplay() && GetDevice(channel, 0))
               break;
            n = channel->Number() + Direction;
@@ -604,6 +606,11 @@
 
 eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
 {
+  // I hope 'LiveView = false' indicates a channel switch for recording, // PIN PATCH
+  // I really don't know, but it works ...                               // PIN PATCH
+  if (LiveView && cStatus::MsgChannelProtected(this, Channel) == true)   // PIN PATCH
+     return scrNotAvailable;                                             // PIN PATCH
+   
   if (LiveView)
      StopReplay();
 
--- ../vdr-1.4.2-plain//i18n.c	2006-10-01 16:34:37.000000000 +0200
+++ i18n.c	2006-10-01 16:35:42.000000000 +0200
@@ -6126,6 +6126,27 @@
     "Ingen titel",
     "Bez názvu",
   },
+  { "Child protection",                        // PIN PATCH
+    "Kinderschutz",
+    "",//TODO
+    "",//TODO
+    "",//TODO
+    "",//TODO
+    "Adulte",
+    "",//TODO
+    "",//TODO
+    "",//TODO
+    "",//TODO
+    "",//TODO
+    "",//TODO
+    "",//TODO
+    "",//TODO
+    "",//TODO
+    "",//TODO
+    "",//TODO
+    "",//TODO
+    "",//TODO
+  },
   { NULL }
   };
 
--- ../vdr-1.4.2-plain//menu.c	2006-07-23 11:23:11.000000000 +0200
+++ menu.c	2006-10-01 16:35:42.000000000 +0200
@@ -664,6 +664,7 @@
      Add(new cMenuEditBitItem( tr("VPS"),          &data.flags, tfVps));
      Add(new cMenuEditIntItem( tr("Priority"),     &data.priority, 0, MAXPRIORITY));
      Add(new cMenuEditIntItem( tr("Lifetime"),     &data.lifetime, 0, MAXLIFETIME));
+     Add(new cMenuEditBoolItem(tr("Child protection"),&data.fskProtection));  // PIN PATCH
      Add(new cMenuEditStrItem( tr("File"),          data.file, sizeof(data.file), tr(FileNameChars)));
      SetFirstDayItem();
      }
@@ -1963,6 +1964,9 @@
 {
   cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
   if (ri) {
+     if (cStatus::MsgReplayProtected(GetRecording(ri), ri->Name(), base,
+                                     ri->IsDirectory()) == true)    // PIN PATCH
+        return osContinue;                                          // PIN PATCH
      if (ri->IsDirectory())
         Open();
      else {
@@ -2952,6 +2956,7 @@
                          if (item) {
                             cPlugin *p = cPluginManager::GetPlugin(item->PluginIndex());
                             if (p) {
+                               if (!cStatus::MsgPluginProtected(p)) {  // PIN PATCH
                                cOsdObject *menu = p->MainMenuAction();
                                if (menu) {
                                   if (menu->IsMenu())
@@ -2963,6 +2968,7 @@
                                   }
                                }
                             }
+                         }
                          state = osEnd;
                        }
                        break;
@@ -3126,6 +3132,7 @@
   if (Direction) {
      while (Channel) {
            Channel = Direction > 0 ? Channels.Next(Channel) : Channels.Prev(Channel);
+	if (cStatus::MsgChannelProtected(0, Channel) == false)                     // PIN PATCH
            if (Channel && !Channel->GroupSep() && (cDevice::PrimaryDevice()->ProvidesChannel(Channel, Setup.PrimaryLimit) || cDevice::GetDevice(Channel, 0)))
               return Channel;
            }
@@ -3663,6 +3670,7 @@
            for (int i = 0; i < MAXRECORDCONTROLS; i++) {
                if (!RecordControls[i]) {
                   RecordControls[i] = new cRecordControl(device, Timer, Pause);
+                  cStatus::MsgRecordingFile(RecordControls[i]->FileName());  // PIN PATCH
                   return RecordControls[i]->Process(time(NULL));
                   }
                }
--- ../vdr-1.4.2-plain//osd.c	2006-02-26 15:31:31.000000000 +0100
+++ osd.c	2006-10-01 16:35:42.000000000 +0200
@@ -594,6 +594,7 @@
 // --- cOsd ------------------------------------------------------------------
 
 int cOsd::isOpen = 0;
+bool cOsd::pinValid = false;   // PIN PATCH
 
 cOsd::cOsd(int Left, int Top)
 {
--- ../vdr-1.4.2-plain//osd.h	2006-02-26 15:45:05.000000000 +0100
+++ osd.h	2006-10-01 16:35:42.000000000 +0200
@@ -324,6 +324,7 @@
        ///< 7: vertical,   falling, upper
   virtual void Flush(void);
        ///< Actually commits all data to the OSD hardware.
+  static bool pinValid;   // PIN PATCH
   };
 
 class cOsdProvider {
--- ../vdr-1.4.2-plain//status.c	2005-12-31 16:10:10.000000000 +0100
+++ status.c	2006-10-01 16:35:42.000000000 +0200
@@ -112,3 +112,49 @@
   for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
       sm->OsdProgramme(PresentTime, PresentTitle, PresentSubtitle, FollowingTime, FollowingTitle, FollowingSubtitle);
 }
+
+bool cStatus::MsgChannelProtected(const cDevice* Device, const cChannel* Channel)     // PIN PATCH
+{
+  for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
+      if (sm->ChannelProtected(Device, Channel) == true)
+ 	 return true;
+
+  return false;
+}
+
+bool cStatus::MsgReplayProtected(const cRecording* Recording, const char* Name, 
+                                 const char* Base, bool isDirectory)             // PIN PATCH
+{
+  for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
+     if (sm->ReplayProtected(Recording, Name, Base, isDirectory) == true)
+       return true;
+
+  return false;
+}
+
+void cStatus::MsgRecordingFile(const char* FileName)
+{
+  for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))   // PIN PATCH
+      sm->RecordingFile(FileName);
+}
+
+void cStatus::MsgTimerCreation(cTimer* Timer, const cEvent *Event)
+{
+  for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))   // PIN PATCH
+     sm->TimerCreation(Timer, Event);
+}
+
+bool cStatus::MsgPluginProtected(cPlugin* Plugin)   // PIN PATCH
+{
+  for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
+    if (sm->PluginProtected(Plugin) == true)
+      return true;
+
+  return false;
+}
+
+void cStatus::MsgUserAction(const eKeys key, const cOsdObject* Interact)         // PIN PATCH
+{
+  for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
+     sm->UserAction(key, Interact);
+}
--- ../vdr-1.4.2-plain//status.h	2005-12-31 16:15:25.000000000 +0100
+++ status.h	2006-10-01 16:35:42.000000000 +0200
@@ -14,6 +14,7 @@
 #include "device.h"
 #include "player.h"
 #include "tools.h"
+#include "plugin.h"
 
 class cStatus : public cListObject {
 private:
@@ -67,6 +68,22 @@
                // The OSD displays the single line Text with the current channel information.
   virtual void OsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle) {}
                // The OSD displays the given programme information.
+  virtual bool ChannelProtected(const cDevice *Device, const cChannel* Channel)  { return false; }        // PIN PATCH
+               // Checks if a channel is protected.
+  virtual bool ReplayProtected(const cRecording* Recording, const char* Name, 
+                               const char* Base, bool isDirectory) { return false; }                      // PIN PATCH 
+               // Checks if a recording is protected.
+  virtual void RecordingFile(const char* FileName) {}                                                     // PIN PATCH
+               // The given DVB device has started recording to FileName. FileName is the name of the
+               // recording directory
+  virtual void TimerCreation(cTimer* Timer, const cEvent *Event) {}                                       // PIN PATCH
+               // The given timer is created
+  virtual bool PluginProtected(cPlugin* Plugin)  { return false; }                                        // PIN PATCH
+               // Checks if a plugin is protected.
+  virtual void UserAction(const eKeys key, const cOsdObject* Interact) {}                                 // PIN PATCH
+               // report user action
+
+
 public:
   cStatus(void);
   virtual ~cStatus();
@@ -86,6 +103,13 @@
   static void MsgOsdTextItem(const char *Text,  bool Scroll = false);
   static void MsgOsdChannel(const char *Text);
   static void MsgOsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle);
+  static bool MsgChannelProtected(const cDevice* Device, const cChannel* Channel);                 // PIN PATCH
+  static bool MsgReplayProtected(const cRecording* Recording, const char* Name, 
+                                 const char* Base, bool isDirectory);                              // PIN PATCH
+  static void MsgRecordingFile(const char* FileName);                                              // PIN PATCH
+  static void MsgTimerCreation(cTimer* Timer, const cEvent *Event);                                // PIN PATCH
+  static bool MsgPluginProtected(cPlugin* Plugin);                                                 // PIN PATCH
+  static void MsgUserAction(const eKeys key, const cOsdObject* Interact);                          // PIN PATCH
   };
 
 #endif //__STATUS_H
--- ../vdr-1.4.2-plain//timers.c	2006-10-01 16:34:37.000000000 +0200
+++ timers.c	2006-10-01 16:36:10.000000000 +0200
@@ -14,6 +14,7 @@
 #include "i18n.h"
 #include "libsi/si.h"
 #include "remote.h"
+#include "status.h"             // PIN PATCH
 
 // 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
@@ -42,6 +43,7 @@
      stop -= 2400;
   priority = Pause ? Setup.PausePriority : Setup.DefaultPriority;
   lifetime = Pause ? Setup.PauseLifetime : Setup.DefaultLifetime;
+  fskProtection = 0;                                        // PIN PATCH
   *file = 0;
   aux = NULL;
   event = NULL;
@@ -75,12 +77,14 @@
      stop -= 2400;
   priority = Setup.DefaultPriority;
   lifetime = Setup.DefaultLifetime;
+  fskProtection = 0;                                        // PIN PATCH
   *file = 0;
   const char *Title = Event->Title();
   if (!isempty(Title))
      strn0cpy(file, Event->Title(), sizeof(file));
   aux = NULL;
   event = NULL; // let SetEvent() be called to get a log message
+  cStatus::MsgTimerCreation(this, Event);                   // PIN PATCH
 }
 
 cTimer::cTimer(const cTimer &Timer)
@@ -113,6 +117,7 @@
      stop         = Timer.stop;
      priority     = Timer.priority;
      lifetime     = Timer.lifetime;
+     fskProtection = Timer.fskProtection;    // PIN PATCH
      strncpy(file, Timer.file, sizeof(file));
      free(aux);
      aux = Timer.aux ? strdup(Timer.aux) : NULL;
@@ -288,6 +293,7 @@
         result = false;
         }
      }
+  fskProtection = aux && strstr(aux, "<pin-plugin><protected>yes</protected></pin-plugin>");  // PIN PATCH
   free(channelbuffer);
   free(daybuffer);
   free(filebuffer);
@@ -597,6 +603,33 @@
   Matches(); // refresh start and end time
 }
 
+void cTimer::SetFskProtection(int aFlag)                 // PIN PATCH
+{ 
+   char* p;
+   char* tmp = 0;
+
+   fskProtection = aFlag;
+
+   if (fskProtection && (!aux || !strstr(aux, "<pin-plugin><protected>yes</protected></pin-plugin>")))
+   {
+      // add protection info to aux
+
+      if (aux) { tmp = strdup(aux); free(aux); }
+      asprintf(&aux,"%s<pin-plugin><protected>yes</protected></pin-plugin>", tmp ? tmp : "");
+   }
+   else if (!fskProtection && aux && (p = strstr(aux, "<pin-plugin><protected>yes</protected></pin-plugin>")))
+   {
+      // remove protection info to aux
+
+      asprintf(&tmp, "%.*s%s", p-aux, aux, p+strlen("<pin-plugin><protected>yes</protected></pin-plugin>"));
+      free(aux);
+      aux = strdup(tmp);
+   }
+
+   if (tmp) 
+      free(tmp);  
+}
+
 // -- cTimers ----------------------------------------------------------------
 
 cTimers Timers;
--- ../vdr-1.4.2-plain//timers.h	2006-10-01 16:34:30.000000000 +0200
+++ timers.h	2006-10-01 16:36:10.000000000 +0200
@@ -37,6 +37,7 @@
   int start;
   int stop;
   int priority;
+  int fskProtection;                                               // PIN PATCH
   int lifetime;
   char file[MaxFileName];
   char *aux;
@@ -58,6 +59,7 @@
   int Start(void) const { return start; }
   int Stop(void) const { return stop; }
   int Priority(void) const { return priority; }
+  int FskProtection(void) const { return fskProtection; }          // PIN PATCH
   int Lifetime(void) const { return lifetime; }
   const char *File(void) const { return file; }
   time_t FirstDay(void) const { return weekdays ? day : 0; }
@@ -86,6 +88,7 @@
   void SetInVpsMargin(bool InVpsMargin);
   void SetPriority(int Priority);
   void SetFlags(uint Flags);
+  void SetFskProtection(int aFlag);                                // PIN PATCH
   void ClrFlags(uint Flags);
   void InvFlags(uint Flags);
   bool HasFlags(uint Flags) const;
--- ../vdr-1.4.2-plain//vdr.c	2006-10-01 16:34:27.000000000 +0200
+++ vdr.c	2006-10-01 16:35:42.000000000 +0200
@@ -865,6 +865,7 @@
         cOsdObject *Interact = Menu ? Menu : cControl::Control();
         eKeys key = Interface->GetKey((!Interact || !Interact->NeedsFastResponse()) && time(NULL) - LastCamMenu > LASTCAMMENUTIMEOUT);
         if (NORMALKEY(key) != kNone) {
+           cStatus::MsgUserAction(key, Interact);          // PIN PATCH
            EITScanner.Activity();
            LastActivity = time(NULL);
            }
@@ -928,10 +929,12 @@
                   cControl::Control()->Hide();
                cPlugin *plugin = cPluginManager::GetPlugin(cRemote::GetPlugin());
                if (plugin) {
+                  if (!cStatus::MsgPluginProtected(plugin)) {    // PIN PATCH
                   Menu = plugin->MainMenuAction();
                   if (Menu)
                      Menu->Show();
                   }
+               }
                else
                   esyslog("ERROR: unknown plugin '%s'", cRemote::GetPlugin());
                key = kNone; // nobody else needs to see these keys
