diff -ruN vdr-1.4.1/CONTRIBUTORS vdr-1.4.1-1/CONTRIBUTORS
--- vdr-1.4.1/CONTRIBUTORS	2006-06-11 11:13:20.000000000 +0200
+++ vdr-1.4.1-1/CONTRIBUTORS	2006-06-17 11:48:50.000000000 +0200
@@ -1440,6 +1440,8 @@
  for fixing handling the "Power" key in case a timer is about to start recording
  for fixing calculating the start time of repeated timers with "first day"
  for setting a timer's cached start time to 0 after a call to Skip()
+ for adding "-fPIC" to the compiler options in Make.config.template when compiling
+ plugins
 
 Sven Kreiensen <svenk@kammer.uni-hannover.de>
  for his help in keeping 'channels.conf.terr' up to date
@@ -1792,6 +1794,7 @@
 
 Patrick Cernko <errror@errror.org>
  for suggesting to add a note about "modprobe capability" to INSTALL
+ for reporting a problem with relative link targets in the ReadLink() function
 
 Philippe Gramoullé <philippe@gramoulle.com>
  for reporting a a missing '-' in the example for viewing a grabbed image on a remote
@@ -1925,6 +1928,10 @@
 
 Prakash Punnoor <prakash@punnoor.de>
  for suggesting to remove -fPIC from VDR's and libsi's Makefile
+ for adding a missing variable initialization in cRingBufferLinear::cRingBufferLinear()
 
 Anssi Hannula <anssi.hannula@gmail.com>
  for a patch that was used to implement processing the "frequency list descriptor"
+
+Antti Hartikainen <ami+vdr@ah.fi>
+ for updating 'S13E' in 'sources.conf'
diff -ruN vdr-1.4.1/HISTORY vdr-1.4.1-1/HISTORY
--- vdr-1.4.1/HISTORY	2006-06-11 11:14:22.000000000 +0200
+++ vdr-1.4.1-1/HISTORY	2006-06-18 10:50:04.000000000 +0200
@@ -4782,3 +4782,22 @@
 - Changed the log messages when grabbing an image from 'isyslog()' to 'dsyslog()'
   so that they can be suppressed in normal operation mode to avoid clogging the
   log file in case this function is used frequently (suggested by Helmut Auer).
+
+2006-06-18: Version 1.4.1-1
+
+- Added "-fPIC" to the compiler options in Make.config.template when compiling
+  plugins (thanks to Udo Richter). If you use your own Make.config file, you may
+  want to add these lines there, too.
+- Added some comment to cDevice::GetDevice() to explain how the individual
+  conditions are put together to make a decision on which device to use.
+- Updated 'S13E' in 'sources.conf' (thanks to Antti Hartikainen).
+- Now making sure VPS timers don't get stuck with outdated events, and that the
+  actual device isn't used for updating a VPS timer's event as long as other
+  free devices are available.
+- Modified rcu.c to better handle RC5 codes.
+- Added a missing variable initialization in cRingBufferLinear::cRingBufferLinear()
+  (thanks to Prakash Punnoor).
+- Fixed handling relative link targets in the ReadLink() function (reported by
+  Patrick Cernko).
+- Now making sure a VPS timer has a schedule in case the epg.data file didn't
+  contain one when VDR was started.
diff -ruN vdr-1.4.1/Make.config.template vdr-1.4.1-1/Make.config.template
--- vdr-1.4.1/Make.config.template	2006-05-26 12:41:46.000000000 +0200
+++ vdr-1.4.1-1/Make.config.template	2006-06-15 11:15:25.000000000 +0200
@@ -6,7 +6,7 @@
 # See the main source file 'vdr.c' for copyright information and
 # how to reach the author.
 #
-# $Id: Make.config.template 1.9 2006/05/26 10:41:46 kls Exp $
+# $Id: Make.config.template 1.10 2006/06/15 09:15:25 kls Exp $
 
 ### The C compiler and options:
 
@@ -16,6 +16,11 @@
 CXX      = g++
 CXXFLAGS = -g -O2 -Wall -Woverloaded-virtual
 
+ifdef PLUGIN
+CFLAGS   += -fPIC
+CXXFLAGS += -fPIC
+endif 
+
 ### The directory environment:
 
 #DVBDIR   = /usr/src/v4l-dvb/linux
diff -ruN vdr-1.4.1/config.h vdr-1.4.1-1/config.h
--- vdr-1.4.1/config.h	2006-06-11 10:57:35.000000000 +0200
+++ vdr-1.4.1-1/config.h	2006-06-15 11:23:21.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: config.h 1.260 2006/06/11 08:57:35 kls Exp $
+ * $Id: config.h 1.261 2006/06/15 09:23:21 kls Exp $
  */
 
 #ifndef __CONFIG_H
@@ -21,7 +21,7 @@
 
 // VDR's own version number:
 
-#define VDRVERSION  "1.4.1"
+#define VDRVERSION  "1.4.1-1"
 #define VDRVERSNUM   10401  // Version * 10000 + Major * 100 + Minor
 
 // The plugin API's version number:
diff -ruN vdr-1.4.1/device.c vdr-1.4.1-1/device.c
--- vdr-1.4.1/device.c	2006-05-27 13:14:42.000000000 +0200
+++ vdr-1.4.1-1/device.c	2006-06-15 11:59:40.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: device.c 1.130 2006/05/27 11:14:42 kls Exp $
+ * $Id: device.c 1.131 2006/06/15 09:59:40 kls Exp $
  */
 
 #include "device.h"
@@ -281,19 +281,26 @@
 cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers)
 {
   cDevice *d = NULL;
-  uint Impact = 0xFFFFFFFF;
+  uint Impact = 0xFFFFFFFF; // we're looking for a device with the least impact
   for (int i = 0; i < numDevices; i++) {
       bool ndr;
       if (device[i]->ProvidesChannel(Channel, Priority, &ndr)) { // this device is basicly able to do the job
+         // Put together an integer number that reflects the "impact" using
+         // this device would have on the overall system. Each condition is represented
+         // by one bit in the number (or several bits, if the condition is actually
+         // a numeric value). The sequence in which the conditions are listed corresponds
+         // to their individual severity, where the one listed first will make the most
+         // difference, because it results in the most significant bit of the result.
          uint imp = 0;
-         imp <<= 1; imp |= !device[i]->Receiving() || ndr;
-         imp <<= 1; imp |= device[i]->Receiving();
-         imp <<= 1; imp |= device[i] == ActualDevice();
-         imp <<= 1; imp |= device[i]->IsPrimaryDevice();
-         imp <<= 1; imp |= device[i]->HasDecoder();
-         imp <<= 8; imp |= min(max(device[i]->Priority() + MAXPRIORITY, 0), 0xFF);
-         imp <<= 8; imp |= min(max(device[i]->ProvidesCa(Channel), 0), 0xFF);
+         imp <<= 1; imp |= !device[i]->Receiving() || ndr;                         // use receiving devices if we don't need to detach existing receivers
+         imp <<= 1; imp |= device[i]->Receiving();                                 // avoid devices that are receiving
+         imp <<= 1; imp |= device[i] == ActualDevice();                            // avoid the actual device (in case of Transfer Mode)
+         imp <<= 1; imp |= device[i]->IsPrimaryDevice();                           // avoid the primary device
+         imp <<= 1; imp |= device[i]->HasDecoder();                                // avoid full featured cards
+         imp <<= 8; imp |= min(max(device[i]->Priority() + MAXPRIORITY, 0), 0xFF); // use the device with the lowest priority (+MAXPRIORITY to assure that values -99..99 can be used)
+         imp <<= 8; imp |= min(max(device[i]->ProvidesCa(Channel), 0), 0xFF);      // use the device that provides the lowest number of conditional access methods
          if (imp < Impact) {
+            // This device has less impact than any previous one, so we take it.
             Impact = imp;
             d = device[i];
             if (NeedsDetachReceivers)
diff -ruN vdr-1.4.1/device.h vdr-1.4.1-1/device.h
--- vdr-1.4.1/device.h	2006-05-28 17:04:24.000000000 +0200
+++ vdr-1.4.1-1/device.h	2006-06-15 11:32:48.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: device.h 1.78 2006/05/28 15:04:24 kls Exp $
+ * $Id: device.h 1.79 2006/06/15 09:32:48 kls Exp $
  */
 
 #ifndef __DEVICE_H
@@ -130,7 +130,8 @@
          ///< \return A pointer to the device, or NULL if the Index was invalid.
   static cDevice *GetDevice(const cChannel *Channel, int Priority = -1, bool *NeedsDetachReceivers = NULL);
          ///< Returns a device that is able to receive the given Channel at the
-         ///< given Priority.
+         ///< given Priority, with the least impact on active recordings and
+         ///< live viewing.
          ///< See ProvidesChannel() for more information on how
          ///< priorities are handled, and the meaning of NeedsDetachReceivers.
   static void Shutdown(void);
diff -ruN vdr-1.4.1/rcu.c vdr-1.4.1-1/rcu.c
--- vdr-1.4.1/rcu.c	2006-06-11 11:08:52.000000000 +0200
+++ vdr-1.4.1-1/rcu.c	2006-06-16 11:29:24.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: rcu.c 1.13 2006/01/08 11:40:09 kls Exp $
+ * $Id: rcu.c 1.14 2006/06/16 09:29:24 kls Exp $
  */
 
 #include "rcu.h"
@@ -13,8 +13,9 @@
 #include <unistd.h>
 #include "tools.h"
 
-#define REPEATLIMIT  20 // ms
-#define REPEATDELAY 350 // ms
+#define REPEATLIMIT      150 // ms
+#define REPEATDELAY      350 // ms
+#define HANDSHAKETIMEOUT  20 // ms
 
 cRcuRemote::cRcuRemote(const char *DeviceName)
 :cRemote("RCU")
@@ -96,7 +97,7 @@
   time_t LastCodeRefresh = 0;
   cTimeMs FirstTime;
   unsigned char LastCode = 0, LastMode = 0;
-  uint64 LastCommand = 0;
+  uint64 LastCommand = ~0; // 0x00 might be a valid command
   unsigned int LastData = 0;
   bool repeat = false;
 
@@ -136,7 +137,7 @@
         else if (repeat) { // the last one was a repeat, so let's generate a release
            Put(LastCommand, false, true);
            repeat = false;
-           LastCommand = 0;
+           LastCommand = ~0;
            }
         else {
            unsigned int d = data;
@@ -154,9 +155,9 @@
               SendCommand(m);
               LastMode = m;
               }
-           LastCommand = 0;
+           LastCommand = ~0;
            }
-        if (code && time(NULL) - LastCodeRefresh > 60) {
+        if (!repeat && code && time(NULL) - LastCodeRefresh > 60) {
            SendCommand(code); // in case the PIC listens to the wrong code
            LastCodeRefresh = time(NULL);
            }
@@ -181,7 +182,7 @@
   if (f >= 0) {
      int w = write(f, &c, 1);
      if (w == 1) {
-        for (int reply = ReceiveByte(REPEATLIMIT); reply >= 0;) {
+        for (int reply = ReceiveByte(HANDSHAKETIMEOUT); reply >= 0;) {
             if (reply == c)
                return true;
             else if (reply == 'X') {
diff -ruN vdr-1.4.1/ringbuffer.c vdr-1.4.1-1/ringbuffer.c
--- vdr-1.4.1/ringbuffer.c	2005-12-30 16:42:08.000000000 +0100
+++ vdr-1.4.1-1/ringbuffer.c	2006-06-16 11:32:13.000000000 +0200
@@ -7,7 +7,7 @@
  * Parts of this file were inspired by the 'ringbuffy.c' from the
  * LinuxDVB driver (see linuxtv.org).
  *
- * $Id: ringbuffer.c 1.23 2005/12/30 15:42:08 kls Exp $
+ * $Id: ringbuffer.c 1.24 2006/06/16 09:32:13 kls Exp $
  */
 
 #include "ringbuffer.h"
@@ -156,6 +156,7 @@
 {
   description = Description ? strdup(Description) : NULL;
   tail = head = margin = Margin;
+  gotten = 0;
   buffer = NULL;
   if (Size > 1) { // 'Size - 1' must not be 0!
      if (Margin <= Size / 2) {
diff -ruN vdr-1.4.1/sources.conf vdr-1.4.1-1/sources.conf
--- vdr-1.4.1/sources.conf	2006-05-01 11:34:18.000000000 +0200
+++ vdr-1.4.1-1/sources.conf	2006-06-15 12:02:28.000000000 +0200
@@ -22,7 +22,7 @@
 S5E     Sirius 2/3
 S7E     Eutelsat W3A
 S10E    Eutelsat W1
-S13E    Hotbird 1-(5)-6
+S13E    Hotbird 1-3/6/7A
 S16E    Eutelsat W2
 S19.2E  Astra 1B/C/E/F/G/H/2C
 S21.0E  Afristar 1
diff -ruN vdr-1.4.1/tools.c vdr-1.4.1-1/tools.c
--- vdr-1.4.1/tools.c	2006-05-26 12:10:31.000000000 +0200
+++ vdr-1.4.1-1/tools.c	2006-06-17 11:45:32.000000000 +0200
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: tools.c 1.118 2006/05/26 10:10:31 kls Exp $
+ * $Id: tools.c 1.119 2006/06/17 09:45:32 kls Exp $
  */
 
 #include "tools.h"
@@ -480,22 +480,16 @@
 
 char *ReadLink(const char *FileName)
 {
-  char RealName[PATH_MAX];
-  const char *TargetName = NULL;
-  int n = readlink(FileName, RealName, sizeof(RealName) - 1);
-  if (n < 0) {
-     if (errno == ENOENT || errno == EINVAL) // file doesn't exist or is not a symlink
-        TargetName = FileName;
+  if (!FileName)
+     return NULL;
+  char *TargetName = canonicalize_file_name(FileName);
+  if (!TargetName) {
+     if (errno == ENOENT) // file doesn't exist
+        TargetName = strdup(FileName);
      else // some other error occurred
         LOG_ERROR_STR(FileName);
      }
-  else if (n < int(sizeof(RealName))) { // got it!
-     RealName[n] = 0;
-     TargetName = RealName;
-     }
-  else
-     esyslog("ERROR: symlink's target name too long: %s", FileName);
-  return TargetName ? strdup(TargetName) : NULL;
+  return TargetName;
 }
 
 bool SpinUpDisk(const char *FileName)
diff -ruN vdr-1.4.1/vdr.c vdr-1.4.1-1/vdr.c
--- vdr-1.4.1/vdr.c	2006-06-04 11:04:47.000000000 +0200
+++ vdr-1.4.1-1/vdr.c	2006-06-18 10:49:20.000000000 +0200
@@ -22,7 +22,7 @@
  *
  * The project's page is at http://www.cadsoft.de/vdr
  *
- * $Id: vdr.c 1.274 2006/06/04 09:04:47 kls Exp $
+ * $Id: vdr.c 1.276 2006/06/18 08:49:20 kls Exp $
  */
 
 #include <getopt.h>
@@ -47,6 +47,7 @@
 #include "i18n.h"
 #include "interface.h"
 #include "keys.h"
+#include "libsi/si.h"
 #include "lirc.h"
 #include "menu.h"
 #include "osdbase.h"
@@ -773,15 +774,20 @@
                   bool NeedsTransponder = false;
                   if (Timer->HasFlags(tfActive) && !Timer->Recording()) {
                      if (Timer->HasFlags(tfVps)) {
-                        if (Timer->Matches(Now, true, Setup.VpsMargin))
+                        if (Timer->Matches(Now, true, Setup.VpsMargin)) {
                            InVpsMargin = true;
-                        else if (Timer->Event())
+                           Timer->SetInVpsMargin(InVpsMargin);
+                           }
+                        else if (Timer->Event()) {
+                           InVpsMargin = Timer->Event()->StartTime() <= Now && Timer->Event()->RunningStatus() == SI::RunningStatusUndefined;
                            NeedsTransponder = Timer->Event()->StartTime() - Now < VPSLOOKAHEADTIME * 3600 && !Timer->Event()->SeenWithin(VPSUPTODATETIME);
+                           }
                         else {
                            cSchedulesLock SchedulesLock;
                            const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock);
                            if (Schedules) {
                               const cSchedule *Schedule = Schedules->GetSchedule(Timer->Channel());
+                              InVpsMargin = !Schedule; // we must make sure we have the schedule
                               NeedsTransponder = Schedule && !Schedule->PresentSeenWithin(VPSUPTODATETIME);
                               }
                            }
@@ -790,10 +796,10 @@
                      else
                         NeedsTransponder = Timer->Matches(Now, true, TIMERLOOKAHEADTIME);
                      }
-                  Timer->SetInVpsMargin(InVpsMargin);
                   if (NeedsTransponder || InVpsMargin) {
                      // Find a device that provides the required transponder:
                      cDevice *Device = NULL;
+                     bool DeviceAvailable = false;
                      for (int i = 0; i < cDevice::NumDevices(); i++) {
                          cDevice *d = cDevice::GetDevice(i);
                          if (d && d->ProvidesTransponder(Timer->Channel())) {
@@ -802,18 +808,17 @@
                                Device = d;
                                break;
                                }
-                            else if (Now - DeviceUsed[d->DeviceNumber()] > TIMERDEVICETIMEOUT) {
-                               // only check other devices if they have been left alone for a while
-                               if (d->MaySwitchTransponder())
-                                  // this one can be switched without disturbing anything else
-                                  Device = d;
-                               else if (!Device && InVpsMargin && !d->Receiving() && d->ProvidesTransponderExclusively(Timer->Channel()))
-                                  // use this one only if no other with less impact can be found
-                                  Device = d;
+                            bool timeout = Now - DeviceUsed[d->DeviceNumber()] > TIMERDEVICETIMEOUT; // only check other devices if they have been left alone for a while
+                            if (d->MaySwitchTransponder()) {
+                               DeviceAvailable = true; // avoids using the actual device below
+                               if (timeout)
+                                  Device = d; // only check other devices if they have been left alone for a while
                                }
+                            else if (timeout && !Device && InVpsMargin && !d->Receiving() && d->ProvidesTransponderExclusively(Timer->Channel()))
+                               Device = d; // use this one only if no other with less impact can be found
                             }
                          }
-                     if (!Device && InVpsMargin) {
+                     if (!Device && InVpsMargin && !DeviceAvailable) {
                         cDevice *d = cDevice::ActualDevice();
                         if (!d->Receiving() && d->ProvidesTransponder(Timer->Channel()) && Now - DeviceUsed[d->DeviceNumber()] > TIMERDEVICETIMEOUT)
                            Device = d; // use the actual device as a last resort
