scop pushed to vdr (f22). "Update to 2.2.0"

notifications at fedoraproject.org notifications at fedoraproject.org
Mon Apr 6 11:56:43 UTC 2015


>From 52552c532d5fedc75ec84d5ddf925e722529245f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ville=20Skytt=C3=A4?= <ville.skytta at iki.fi>
Date: Thu, 19 Feb 2015 17:34:40 +0200
Subject: Update to 2.2.0


diff --git a/sources b/sources
index 2959bb4..4ab426c 100644
--- a/sources
+++ b/sources
@@ -4,10 +4,7 @@
 71f7281d55eba1957f4267f596b11e29  vdr.epgsearch-exttimeredit-0.0.2.diff
 da3a3ab8c2a42a320171b1648c3b3258  vdr-1.7.29-hlcutter-0.2.3.diff
 d76b06a7bf1f458a02f2d1169776fb7f  vdr_2.0.3-1.debian.tar.bz2
-5eb1ced307d11d94e88cf9b0ac8317c9  vdr-2.0.6-ttxtsubs.patch
-4ab8c7b2df034988632b01cb50f4ac87  opt-24_jumpplay.patch
-77a827cf356b3446d6c25ed31490b957  vdr-2.1.6-binaryskip.patch.gz
-427f940f34367f156f981921c7a9cc51  vdr-2.1.6-menuselection.patch.gz
 94dbf03ad78b10668c2aef129e254b98  vdr-2.1.5-naludump-0.1.diff
 73ff9846be32894e399b821a9da17dac  epghandler-segment-transfer.patch
-090c6f5b75b4710e39528734ebf2dcc8  vdr-2.0.7.tar.bz2
+b01a5d964af6379af5e7aa0f5203e1d3  vdr-2.1.9-menuselection.patch.gz
+8853f64c0fc3d41ffd3b4bfc6f0a14b7  vdr-2.2.0.tar.bz2
diff --git a/vdr-1.7.21-jumpplay-finnish.patch b/vdr-1.7.21-jumpplay-finnish.patch
deleted file mode 100644
index fb68794..0000000
--- a/vdr-1.7.21-jumpplay-finnish.patch
+++ /dev/null
@@ -1,19 +0,0 @@
-diff -up vdr-1.7.21/po/fi_FI.po~ vdr-1.7.21/po/fi_FI.po
---- vdr-1.7.21/po/fi_FI.po~	2011-10-17 21:42:33.775916357 +0300
-+++ vdr-1.7.21/po/fi_FI.po	2011-10-17 21:43:11.112400439 +0300
-@@ -1076,6 +1076,15 @@ msgstr "Käytä kovia linkkejä muokkauk
- msgid "Replay"
- msgstr "Toisto"
- 
-+msgid "Setup.Replay$Jump&Play"
-+msgstr "Jatka toistoa hypyn jälkeen"
-+
-+msgid "Setup.Replay$Play&Jump"
-+msgstr "Ohita merkityt katkot"
-+
-+msgid "Setup.Replay$Pause at last mark"
-+msgstr "Tauko viimeisessä merkinnässä"
-+
- msgid "Setup.Replay$Multi speed mode"
- msgstr "Käytä toiston moninopeustilaa"
- 
diff --git a/vdr-2.0.6-filetransfer.patch b/vdr-2.0.6-filetransfer.patch
deleted file mode 100644
index a20106b..0000000
--- a/vdr-2.0.6-filetransfer.patch
+++ /dev/null
@@ -1,1242 +0,0 @@
-diff -up vdr-2.0.6/cutter.c~ vdr-2.0.6/cutter.c
---- vdr-2.0.6/cutter.c~	2013-08-21 16:43:46.000000000 +0300
-+++ vdr-2.0.6/cutter.c	2014-03-23 11:43:03.385540419 +0200
-@@ -8,6 +8,7 @@
-  */
- 
- #include "cutter.h"
-+#include "interface.h"
- #include "menu.h"
- #include "recording.h"
- #include "remux.h"
-@@ -649,7 +650,7 @@ cCuttingThread *cCutter::cuttingThread =
- bool cCutter::error = false;
- bool cCutter::ended = false;
- 
--bool cCutter::Start(const char *FileName)
-+bool cCutter::Start(const char *FileName, const char *TargetFileName, bool Overwrite)
- {
-   cMutexLock MutexLock(&mutex);
-   if (!cuttingThread) {
-@@ -663,11 +664,16 @@ bool cCutter::Start(const char *FileName
-      if (cMark *First = FromMarks.GetNextBegin())
-         Recording.SetStartTime(Recording.Start() + (int(First->Position() / Recording.FramesPerSecond() + 30) / 60) * 60);
- 
--     const char *evn = Recording.PrefixFileName('%');
--     if (evn && RemoveVideoFile(evn) && MakeDirs(evn, true)) {
-+     cString evn = (TargetFileName && *TargetFileName) ? Recording.UpdateFileName(TargetFileName) : Recording.PrefixFileName('%');
-+     if (!Overwrite && *evn && (access(*evn, F_OK) == 0) && !Interface->Confirm(tr("File already exists - overwrite?"))) {
-+        do {
-+           evn = PrefixVideoFileName(*evn, '%');
-+        } while (*evn && (access(*evn, F_OK) == 0));
-+        }
-+     if (*evn && RemoveVideoFile(*evn) && MakeDirs(*evn, true)) {
-         // XXX this can be removed once RenameVideoFile() follows symlinks (see videodir.c)
-         // remove a possible deleted recording with the same name to avoid symlink mixups:
--        char *s = strdup(evn);
-+        char *s = strdup(*evn);
-         char *e = strrchr(s, '.');
-         if (e) {
-            if (strcmp(e, ".rec") == 0) {
-diff -up vdr-2.0.6/cutter.h~ vdr-2.0.6/cutter.h
---- vdr-2.0.6/cutter.h~	2012-02-16 14:05:33.000000000 +0200
-+++ vdr-2.0.6/cutter.h	2014-03-23 11:43:03.385540419 +0200
-@@ -24,7 +24,7 @@ private:
-   static bool error;
-   static bool ended;
- public:
--  static bool Start(const char *FileName);
-+  static bool Start(const char *FileName, const char *TargetFileName = NULL, bool Overwrite = true);
-   static void Stop(void);
-   static bool Active(const char *FileName = NULL);
-          ///< Returns true if the cutter is currently active.
-diff -up vdr-2.0.6/dvbplayer.c~ vdr-2.0.6/dvbplayer.c
---- vdr-2.0.6/dvbplayer.c~	2013-03-08 15:44:19.000000000 +0200
-+++ vdr-2.0.6/dvbplayer.c	2014-03-23 11:43:03.386540440 +0200
-@@ -374,11 +374,16 @@ bool cDvbPlayer::Save(void)
-   if (index) {
-      int Index = ptsIndex.FindIndex(DeviceGetSTC());
-      if (Index >= 0) {
--        Index -= int(round(RESUMEBACKUP * framesPerSecond));
--        if (Index > 0)
--           Index = index->GetNextIFrame(Index, false);
--        else
-+        int backup = int(round(RESUMEBACKUP * framesPerSecond));
-+        if (Index >= index->Last() - backup)
-            Index = 0;
-+        else {
-+           Index -= backup;
-+           if (Index > 0)
-+              Index = index->GetNextIFrame(Index, false);
-+           else
-+              Index = 0;
-+           }
-         if (Index >= 0)
-            return index->StoreResume(Index);
-         }
-diff -up vdr-2.0.6/filetransfer.c~ vdr-2.0.6/filetransfer.c
---- vdr-2.0.6/filetransfer.c~	2014-03-23 11:43:03.386540440 +0200
-+++ vdr-2.0.6/filetransfer.c	2014-03-23 11:43:03.386540440 +0200
-@@ -0,0 +1,281 @@
-+/*
-+ * filetransfer.c: The video file transfer facilities
-+ *
-+ * See the main source file 'vdr.c' for copyright information and
-+ * how to reach the author.
-+ *
-+ * $Id: $
-+ */
-+
-+#include "videodir.h"
-+#include "filetransfer.h"
-+
-+static cString StripLastDirectory(const char *DirName)
-+{
-+  if (DirName && *DirName) {
-+     cString s(DirName);
-+     int l = strlen(*s);
-+     const char *p = *s + l;
-+     while (l > 0) {
-+           if (*p-- == '/')
-+              break;
-+           l--;
-+           }
-+     if (l)
-+        s = s.Truncate(l);
-+     return s;
-+     }
-+  return NULL;
-+}
-+
-+// --- cCopyingThread --------------------------------------------------------
-+
-+class cCopyingThread : public cThread {
-+private:
-+  const char *error;
-+  bool deleteSource;
-+  cString source;
-+  cString target;
-+protected:
-+  virtual void Action(void);
-+public:
-+  cCopyingThread(const char *SourceName, const char *ToFileName, bool DeleteSource = false);
-+  virtual ~cCopyingThread();
-+  const char *Error(void) { return error; }
-+  };
-+
-+cCopyingThread::cCopyingThread(const char *SourceName, const char *TargetName, bool DeleteSource)
-+:cThread("copying"),
-+ error(NULL),
-+ deleteSource(DeleteSource),
-+ source(SourceName),
-+ target(TargetName)
-+{
-+  // add missing directory delimiters
-+  const char *delim = "/";
-+  if (!endswith(*source, delim))
-+     source = cString::sprintf("%s%s", *source, delim);
-+  if (!endswith(*target, delim))
-+     target = cString::sprintf("%s%s", *target, delim);
-+
-+  Start();
-+}
-+
-+cCopyingThread::~cCopyingThread()
-+{
-+  Cancel(3);
-+}
-+
-+void cCopyingThread::Action(void)
-+{
-+  SetPriority(19);
-+  SetIOPriority(7);
-+
-+  if (strcmp(*source, *target)) {
-+     // validate target directory
-+     if (strstr(*target, *source)) {
-+        error = "invalid target";
-+        return;
-+        }
-+
-+     // recordings methods require the last directory delimiter to be stripped off
-+     cString recname = target;
-+     recname.Truncate(strlen(*recname) - 1);
-+     Recordings.AddByName(*recname, false);
-+
-+     RemoveFileOrDir(*target);
-+     if (!MakeDirs(*target, true)) {
-+        error = "MakeDirs";
-+        return;
-+        }
-+
-+     if (deleteSource && EntriesOnSameFileSystem(*source, *target)) {
-+        if (rename(*source, *target) == -1) {
-+           error = "rename";
-+           return;
-+           }
-+        // delete all empty source directories
-+        recname = source;
-+        recname.Truncate(strlen(*recname) - 1);
-+        recname = StripLastDirectory(*recname);
-+        do {
-+           if (!RemoveEmptyDirectories(*recname, true))
-+              break;
-+           recname = StripLastDirectory(*recname);
-+           }
-+        while (strcmp(*recname, VideoDirectory));
-+        }
-+     else {
-+        int required = DirSizeMB(*source);
-+        int available = FreeDiskSpaceMB(*target);
-+
-+        // validate free space
-+        if (required < available) {
-+           cReadDir d(*source);
-+           struct dirent *e;
-+           bool success = true;
-+
-+           // allocate copying buffer
-+           const int len = 1024 * 1024;
-+           char *buffer = MALLOC(char, len);
-+           if (!buffer) {
-+              error = "MALLOC";
-+              return;
-+              }
-+
-+           // loop through all files, but skip all sub-directories
-+           while (Running() && (e = d.Next()) != NULL) {
-+                 // skip generic entries
-+                 if (strcmp(e->d_name, ".") && strcmp(e->d_name, "..") && strcmp(e->d_name, "lost+found")) {
-+                    cString sourceFile = cString::sprintf("%s%s", *source, e->d_name);
-+                    cString targetFile = cString::sprintf("%s%s", *target, e->d_name);
-+
-+                    // copy only regular files
-+                    struct stat sts;
-+                    if (!stat(*sourceFile, &sts) && S_ISREG(sts.st_mode)) {
-+                       int r = -1, w = -1;
-+                       cUnbufferedFile *inputFile = cUnbufferedFile::Create(*sourceFile, O_RDONLY | O_LARGEFILE);
-+                       cUnbufferedFile *outputFile = cUnbufferedFile::Create(*targetFile, O_RDWR | O_CREAT | O_LARGEFILE);
-+
-+                       // validate files
-+                       if (!inputFile || !outputFile) {
-+                          success = false;
-+                          break;
-+                          }
-+
-+                       // do actual copy
-+                       do {
-+                         r = inputFile->Read(buffer, len);
-+                         if (r > 0)
-+                            w = outputFile->Write(buffer, r);
-+                         else
-+                            w = 0;
-+                       } while (Running() && r > 0 && w > 0);
-+                       DELETENULL(inputFile);
-+                       DELETENULL(outputFile);
-+
-+                       // validate result
-+                       if (!Running() || r < 0 || w < 0) {
-+                          success = false;
-+                          break;
-+                          }
-+                       }
-+                   }
-+                }
-+
-+           // release allocated buffer
-+           free(buffer);
-+
-+           // delete all created target files and directories
-+           if (!success) {
-+              target = StripLastDirectory(*target);
-+              RemoveFileOrDir(*target, true);
-+              target = StripLastDirectory(*target);
-+              RemoveEmptyDirectories(*target, true);
-+              error = "copy failed";
-+              return;
-+              }
-+           }
-+        else {
-+           // delete all created empty target directories
-+           recname = target;
-+           recname.Truncate(strlen(*recname) - 1);
-+           recname = StripLastDirectory(*recname);
-+           do {
-+              if (!RemoveEmptyDirectories(*recname, true))
-+                 break;
-+              recname = StripLastDirectory(*recname);
-+              }
-+           while (strcmp(*recname, VideoDirectory));
-+           error = "insufficient free space";
-+           return;
-+           }
-+        }
-+
-+     if (deleteSource) {
-+        // Recordings' methods require the last directory delimiter to be stripped off
-+        source.Truncate(strlen(*source) - 1);
-+        cRecording *recording = Recordings.GetByName(*source);
-+        if (recording->Delete())
-+           Recordings.DelByName(*source, false);
-+        target.Truncate(strlen(*target) - 1);
-+        Recordings.UpdateByName(*target);
-+        }
-+
-+     // Must inform all VDR instances about the modification
-+     Recordings.TouchUpdate();
-+     }
-+}
-+
-+// --- cFileTransfer ----------------------------------------------------------------
-+
-+cMutex cFileTransfer::mutex;
-+char *cFileTransfer::copiedVersionName = NULL;
-+cCopyingThread *cFileTransfer::copyingThread = NULL;
-+bool cFileTransfer::error = false;
-+bool cFileTransfer::ended = false;
-+
-+bool cFileTransfer::Start(cRecording *Recording, const char *FileName, bool CopyOnly)
-+{
-+  cMutexLock MutexLock(&mutex);
-+  if (!copyingThread) {
-+     cString NewName = NewVideoFileName(Recording->FileName(), FileName);
-+     error = false;
-+     ended = false;
-+     if (strlen(*NewName)) {
-+        copiedVersionName = strdup(*NewName);
-+        copyingThread = new cCopyingThread(Recording->FileName(), copiedVersionName, !CopyOnly);
-+        return true;
-+        }
-+     }
-+  return false;
-+}
-+
-+void cFileTransfer::Stop(void)
-+{
-+  cMutexLock MutexLock(&mutex);
-+  bool Interrupted = copyingThread && copyingThread->Active();
-+  const char *Error = copyingThread ? copyingThread->Error() : NULL;
-+  DELETENULL(copyingThread);
-+  if (Interrupted || Error) {
-+     if (Interrupted)
-+        isyslog("file transfer has been interrupted");
-+     if (Error)
-+        esyslog("ERROR: '%s' during file transfer", Error);
-+     RemoveVideoFile(copiedVersionName); //XXX what if this file is currently being replayed?
-+     Recordings.DelByName(copiedVersionName);
-+     free(copiedVersionName);
-+     copiedVersionName = NULL;
-+     }
-+}
-+
-+bool cFileTransfer::Active(void)
-+{
-+  cMutexLock MutexLock(&mutex);
-+  if (copyingThread) {
-+     if (copyingThread->Active())
-+        return true;
-+     error = copyingThread->Error();
-+     Stop();
-+     free(copiedVersionName);
-+     copiedVersionName = NULL;
-+     ended = true;
-+     }
-+  return false;
-+}
-+
-+bool cFileTransfer::Error(void)
-+{
-+  cMutexLock MutexLock(&mutex);
-+  bool result = error;
-+  error = false;
-+  return result;
-+}
-+
-+bool cFileTransfer::Ended(void)
-+{
-+  cMutexLock MutexLock(&mutex);
-+  bool result = ended;
-+  ended = false;
-+  return result;
-+}
-diff -up vdr-2.0.6/filetransfer.h~ vdr-2.0.6/filetransfer.h
---- vdr-2.0.6/filetransfer.h~	2014-03-23 11:43:03.386540440 +0200
-+++ vdr-2.0.6/filetransfer.h	2014-03-23 11:43:03.386540440 +0200
-@@ -0,0 +1,33 @@
-+/*
-+ * filetransfer.h: The video file transfer facilities
-+ *
-+ * See the main source file 'vdr.c' for copyright information and
-+ * how to reach the author.
-+ *
-+ * $Id: $
-+ */
-+
-+#ifndef __FILETRANSFER_H
-+#define __FILETRANSFER_H
-+
-+#include "recording.h"
-+#include "thread.h"
-+
-+class cCopyingThread;
-+
-+class cFileTransfer {
-+private:
-+  static cMutex mutex;
-+  static char *copiedVersionName;
-+  static cCopyingThread *copyingThread;
-+  static bool error;
-+  static bool ended;
-+public:
-+  static bool Start(cRecording *Recording, const char *NewName, bool CopyOnly = false);
-+  static void Stop(void);
-+  static bool Active(void);
-+  static bool Error(void);
-+  static bool Ended(void);
-+  };
-+
-+#endif //__FILETRANSFER_H
-diff -up vdr-2.0.6/Makefile~ vdr-2.0.6/Makefile
---- vdr-2.0.6/Makefile~	2013-03-11 17:01:01.000000000 +0200
-+++ vdr-2.0.6/Makefile	2014-03-23 11:43:03.386540440 +0200
-@@ -67,8 +67,8 @@ endif
- SILIB    = $(LSIDIR)/libsi.a
- 
- OBJS = audio.o channels.o ci.o config.o cutter.o device.o diseqc.o dvbdevice.o dvbci.o\
--       dvbplayer.o dvbspu.o dvbsubtitle.o eit.o eitscan.o epg.o filter.o font.o i18n.o interface.o keys.o\
--       lirc.o menu.o menuitems.o nit.o osdbase.o osd.o pat.o player.o plugin.o\
-+       dvbplayer.o dvbspu.o dvbsubtitle.o eit.o eitscan.o epg.o filetransfer.o filter.o font.o i18n.o\
-+       interface.o keys.o lirc.o menu.o menuitems.o nit.o osdbase.o osd.o pat.o player.o plugin.o\
-        receiver.o recorder.o recording.o remote.o remux.o ringbuffer.o sdt.o sections.o shutdown.o\
-        skinclassic.o skinlcars.o skins.o skinsttng.o sourceparams.o sources.o spu.o status.o svdrp.o themes.o thread.o\
-        timers.o tools.o transfer.o vdr.o videodir.o
-diff -up vdr-2.0.6/menu.c~ vdr-2.0.6/menu.c
---- vdr-2.0.6/menu.c~	2014-02-26 13:42:28.000000000 +0200
-+++ vdr-2.0.6/menu.c	2014-03-23 11:43:03.387540462 +0200
-@@ -18,6 +18,7 @@
- #include "config.h"
- #include "cutter.h"
- #include "eitscan.h"
-+#include "filetransfer.h"
- #include "i18n.h"
- #include "interface.h"
- #include "plugin.h"
-@@ -2223,6 +2224,167 @@ void cMenuRecordingItem::SetMenuItem(cSk
-      DisplayMenu->SetItem(Text(), Index, Current, Selectable);
- }
- 
-+// --- cMenuEditRecording ----------------------------------------------------
-+
-+class cMenuEditRecording : public cOsdMenu {
-+private:
-+  char name[MaxFileName];
-+  cMenuEditStrItem *file;
-+  cOsdItem *marksItem, *resumeItem;
-+  bool isResume, isMarks;
-+  cRecording *recording;
-+  void SetHelpKeys(void);
-+  eOSState SetFolder(void);
-+public:
-+  cMenuEditRecording(cRecording *Recording);
-+  virtual eOSState ProcessKey(eKeys Key);
-+};
-+
-+cMenuEditRecording::cMenuEditRecording(cRecording *Recording)
-+:cOsdMenu(tr("Edit recording"), 14)
-+{
-+  cMarks marks;
-+
-+  file = NULL;
-+  recording = Recording;
-+
-+  if (recording) {
-+     Utf8Strn0Cpy(name, recording->Name(), sizeof(name));
-+     Add(file = new cMenuEditStrItem(tr("File"), name, sizeof(name)));
-+
-+     Add(new cOsdItem("", osUnknown, false));
-+
-+     Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Date"), *DayDateTime(recording->Start())), osUnknown, false));
-+
-+     cChannel *channel = Channels.GetByChannelID(((cRecordingInfo *)recording->Info())->ChannelID());
-+     if (channel)
-+        Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Channel"), *ChannelString(channel, 0)), osUnknown, false));
-+
-+     int recLen = recording->LengthInSeconds();
-+     if (recLen >= 0)
-+        Add(new cOsdItem(cString::sprintf("%s:\t%d:%02d:%02d", tr("Length"), recLen / 3600, recLen / 60 % 60, recLen % 60), osUnknown, false));
-+     else
-+        recLen = 0;
-+
-+     int dirSize = DirSizeMB(recording->FileName());
-+     cString bitRate = recLen ? cString::sprintf(" (%.2f MBit/s)", 8.0 * dirSize / recLen) : cString("");
-+     Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Format"), recording->IsPesRecording() ? tr("PES") : tr("TS")), osUnknown, false));
-+     Add(new cOsdItem((dirSize > 9999) ? cString::sprintf("%s:\t%.2f GB%s", tr("Size"), dirSize / 1024.0, *bitRate) : cString::sprintf("%s:\t%d MB%s", tr("Size"), dirSize, *bitRate), osUnknown, false));
-+
-+     Add(new cOsdItem("", osUnknown, false));
-+
-+     isMarks = marks.Load(recording->FileName(), recording->FramesPerSecond(), recording->IsPesRecording()) && marks.Count();
-+     marksItem = new cOsdItem(tr("Delete marks information?"), osUser1, isMarks);
-+     Add(marksItem);
-+
-+     cResumeFile ResumeFile(recording->FileName(), recording->IsPesRecording());
-+     isResume = (ResumeFile.Read() != -1);
-+     resumeItem = new cOsdItem(tr("Delete resume information?"), osUser2, isResume);
-+     Add(resumeItem);
-+     }
-+
-+  SetHelpKeys();
-+}
-+
-+void cMenuEditRecording::SetHelpKeys(void)
-+{
-+  SetHelp(tr("Button$Folder"), tr("Button$Cut"), tr("Button$Copy"), tr("Button$Rename/Move"));
-+}
-+
-+eOSState cMenuEditRecording::SetFolder(void)
-+{
-+  cMenuFolder *mf = (cMenuFolder *)SubMenu();
-+  if (mf) {
-+     cString Folder = mf->GetFolder();
-+     char *p = strrchr(name, FOLDERDELIMCHAR);
-+     if (p)
-+        p++;
-+     else
-+        p = name;
-+     if (!isempty(*Folder))
-+        strn0cpy(name, cString::sprintf("%s%c%s", *Folder, FOLDERDELIMCHAR, p), sizeof(name));
-+     else if (p != name)
-+        memmove(name, p, strlen(p) + 1);
-+     SetCurrent(file);
-+     Display();
-+     }
-+  return CloseSubMenu();
-+}
-+
-+eOSState cMenuEditRecording::ProcessKey(eKeys Key)
-+{
-+  eOSState state = cOsdMenu::ProcessKey(Key);
-+
-+  if (state == osUnknown) {
-+     switch (Key) {
-+       case kRed:
-+            return AddSubMenu(new cMenuFolder(tr("Select folder"), &Folders, name));
-+            break;
-+       case kGreen:
-+            if (!cCutter::Active()) {
-+               if (!isMarks)
-+                  Skins.Message(mtError, tr("No editing marks defined!"));
-+               else if (!cCutter::Start(recording->FileName(), strcmp(recording->Name(), name) ? *NewVideoFileName(recording->FileName(), name) : NULL, false))
-+                  Skins.Message(mtError, tr("Can't start editing process!"));
-+               else
-+                  Skins.Message(mtInfo, tr("Editing process started"));
-+               }
-+            else
-+               Skins.Message(mtError, tr("Editing process already active!"));
-+            return osContinue;
-+       case kYellow:
-+       case kBlue:
-+            if (strcmp(recording->Name(), name)) {
-+               if (!cFileTransfer::Active()) {
-+                  if (cFileTransfer::Start(recording, name, (Key == kYellow)))
-+                     Skins.Message(mtInfo, tr("File transfer started"));
-+                  else
-+                     Skins.Message(mtError, tr("Can't start file transfer!"));
-+                  }
-+               else
-+                  Skins.Message(mtError, tr("File transfer already active!"));
-+               }
-+            return osRecordings;
-+       default:
-+            break;
-+       }
-+     return osContinue;
-+     }
-+  else if (state == osEnd && HasSubMenu())
-+     state = SetFolder();
-+  else if (state == osUser1) {
-+     if (isMarks && Interface->Confirm(tr("Delete marks information?"))) {
-+        cMarks marks;
-+        marks.Load(recording->FileName(), recording->FramesPerSecond(), recording->IsPesRecording());
-+        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(), recording->IsPesRecording());
-+        ResumeFile.Delete();
-+        isResume = false;
-+        resumeItem->SetSelectable(isResume);
-+        SetCurrent(First());
-+        Display();
-+        }
-+     return osContinue;
-+     }
-+
-+  return state;
-+}
-+
- // --- cMenuRecordings -------------------------------------------------------
- 
- cMenuRecordings::cMenuRecordings(const char *Base, int Level, bool OpenSubMenus)
-@@ -2464,6 +2626,16 @@ eOSState cMenuRecordings::Sort(void)
-   return osContinue;
- }
- 
-+eOSState cMenuRecordings::Edit(void)
-+{
-+  if (HasSubMenu() || Count() == 0)
-+     return osContinue;
-+  cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
-+  if (ri && !ri->IsDirectory() && ri->Recording())
-+     return AddSubMenu(new cMenuEditRecording(ri->Recording()));
-+  return osContinue;
-+}
-+
- eOSState cMenuRecordings::ProcessKey(eKeys Key)
- {
-   bool HadSubMenu = HasSubMenu();
-@@ -2477,7 +2649,7 @@ eOSState cMenuRecordings::ProcessKey(eKe
-        case kRed:    return (helpKeys > 1 && RecordingCommands.Count()) ? Commands() : Play();
-        case kGreen:  return Rewind();
-        case kYellow: return Delete();
--       case kInfo:
-+       case kInfo:   return Edit();
-        case kBlue:   return Info();
-        case k0:      return Sort();
-        case k1...k9: return Commands(Key);
-@@ -3385,6 +3557,7 @@ cMenuMain::cMenuMain(eOSState State, boo
-   replaying = false;
-   stopReplayItem = NULL;
-   cancelEditingItem = NULL;
-+  cancelFileTransferItem = NULL;
-   stopRecordingItem = NULL;
-   recordControlsState = 0;
-   Set();
-@@ -3479,6 +3652,19 @@ bool cMenuMain::Update(bool Force)
-      result = true;
-      }
- 
-+  // File transfer control:
-+  bool FileTransferActive = cFileTransfer::Active();
-+  if (FileTransferActive && !cancelFileTransferItem) {
-+     // TRANSLATORS: note the leading blank!
-+     Add(cancelFileTransferItem = new cOsdItem(tr(" Cancel file transfer"), osCancelTransfer));
-+     result = true;
-+     }
-+  else if (cancelFileTransferItem && !FileTransferActive) {
-+     Del(cancelFileTransferItem->Index());
-+     cancelFileTransferItem = NULL;
-+     result = true;
-+     }
-+
-   // Record control:
-   if (cRecordControls::StateChanged(recordControlsState)) {
-      while (stopRecordingItem) {
-@@ -3527,6 +3713,12 @@ eOSState cMenuMain::ProcessKey(eKeys Key
-                           return osEnd;
-                           }
-                        break;
-+    case osCancelTransfer:
-+                       if (Interface->Confirm(tr("Cancel file transfer?"))) {
-+                          cFileTransfer::Stop();
-+                          return osEnd;
-+                          }
-+                       break;
-     case osPlugin:     {
-                          cMenuPluginItem *item = (cMenuPluginItem *)Get(Current());
-                          if (item) {
-@@ -4850,7 +5049,7 @@ void cReplayControl::EditCut(void)
-            Skins.Message(mtError, tr("No editing marks defined!"));
-         else if (!marks.GetNumSequences())
-            Skins.Message(mtError, tr("No editing sequences defined!"));
--        else if (!cCutter::Start(fileName))
-+        else if (!cCutter::Start(fileName, NULL, false))
-            Skins.Message(mtError, tr("Can't start editing process!"));
-         else
-            Skins.Message(mtInfo, tr("Editing process started"));
-diff -up vdr-2.0.6/menu.h~ vdr-2.0.6/menu.h
---- vdr-2.0.6/menu.h~	2013-10-16 12:46:15.000000000 +0300
-+++ vdr-2.0.6/menu.h	2014-03-23 11:43:03.387540462 +0200
-@@ -101,6 +101,7 @@ private:
-   bool replaying;
-   cOsdItem *stopReplayItem;
-   cOsdItem *cancelEditingItem;
-+  cOsdItem *cancelFileTransferItem;
-   cOsdItem *stopRecordingItem;
-   int recordControlsState;
-   static cOsdObject *pluginOsdObject;
-@@ -206,6 +207,7 @@ private:
-   eOSState Info(void);
-   eOSState Sort(void);
-   eOSState Commands(eKeys Key = kNone);
-+  eOSState Edit(void);
- protected:
-   cString DirectoryName(void);
- public:
-diff -up vdr-2.0.6/osdbase.h~ vdr-2.0.6/osdbase.h
---- vdr-2.0.6/osdbase.h~	2012-12-07 11:49:35.000000000 +0200
-+++ vdr-2.0.6/osdbase.h	2014-03-23 11:43:03.387540462 +0200
-@@ -30,6 +30,7 @@ enum eOSState { osUnknown,
-                 osStopRecord,
-                 osStopReplay,
-                 osCancelEdit,
-+                osCancelTransfer,
-                 osSwitchDvb,
-                 osBack,
-                 osEnd,
-diff -up vdr-2.0.6/po/de_DE.po~ vdr-2.0.6/po/de_DE.po
---- vdr-2.0.6/po/de_DE.po~	2014-03-22 12:54:15.569991437 +0200
-+++ vdr-2.0.6/po/de_DE.po	2014-03-23 11:43:03.388540484 +0200
-@@ -1398,3 +1398,70 @@ msgstr "Disk"
- 
- msgid "free"
- msgstr "frei"
-+
-+msgid "Edit recording"
-+msgstr "Aufnahme bearbeiten"
-+
-+msgid "Button$Cut"
-+msgstr "Schneiden"
-+
-+msgid "Button$Copy"
-+msgstr "Kopieren"
-+
-+msgid "Button$Rename/Move"
-+msgstr "Umbenennen/Bewegen"
-+
-+msgid "Date"
-+msgstr "Datum"
-+
-+msgid "Length"
-+msgstr "L�nge"
-+
-+msgid "Format"
-+msgstr "Format"
-+
-+msgid "PES"
-+msgstr "PES"
-+
-+msgid "TS"
-+msgstr "TS"
-+
-+msgid "Size"
-+msgstr "Gr��e"
-+
-+msgid "Delete marks information?"
-+msgstr "Gespeicherte Schnittmarken l�schen?"
-+
-+msgid "Delete resume information?"
-+msgstr "Gespeicherten Zeitpunkt der letzten Wiedergabe l�schen?"
-+
-+msgid "File transfer started"
-+msgstr "Datei�bertragung gestartet"
-+
-+msgid "Can't start file transfer!"
-+msgstr "Datei�bertragung kann nicht gestartet werden!"
-+
-+msgid "File transfer already active!"
-+msgstr "Datei�bertragung bereits aktiv!"
-+ 
-+#. TRANSLATORS: note the leading blank!
-+msgid " Cancel file transfer"
-+msgstr " Datei�bertragung beenden"
-+
-+msgid "Cancel file transfer?"
-+msgstr "Datei�bertragung beenden?"
-+
-+msgid "Transfering file - shut down anyway?"
-+msgstr "�bertrage Datei - trotzdem ausschalten?"
-+
-+msgid "Transfering file - restart anyway?"
-+msgstr "�bertrage Datei - trotzdem neustarten?"
-+
-+msgid "File transfer failed!"
-+msgstr "Datei�bertragung fehlgeschlagen!"
-+
-+msgid "File transfer finished"
-+msgstr "Datei�bertragung fertiggestellt"
-+
-+msgid "File already exists - overwrite?"
-+msgstr "Datei besteht bereits - �berschreiben?"
-diff -up vdr-2.0.6/po/fi_FI.po~ vdr-2.0.6/po/fi_FI.po
---- vdr-2.0.6/po/fi_FI.po~	2014-03-22 12:54:15.019890792 +0200
-+++ vdr-2.0.6/po/fi_FI.po	2014-03-23 11:43:03.388540484 +0200
-@@ -1402,3 +1402,70 @@ msgstr "Levy"
- 
- msgid "free"
- msgstr "vapaana"
-+
-+msgid "Edit recording"
-+msgstr "Muokkaa tallennetta"
-+
-+msgid "Button$Cut"
-+msgstr "Leikkaa"
-+
-+msgid "Button$Copy"
-+msgstr "Kopioi"
-+
-+msgid "Button$Rename/Move"
-+msgstr "Nimeä/Siirrä"
-+
-+msgid "Date"
-+msgstr "Päiväys"
-+
-+msgid "Length"
-+msgstr "Pituus"
-+
-+msgid "Format"
-+msgstr "Tiedostomuoto"
-+
-+msgid "PES"
-+msgstr "PES"
-+
-+msgid "TS"
-+msgstr "TS"
-+
-+msgid "Size"
-+msgstr "Koko"
-+
-+msgid "Delete marks information?"
-+msgstr "Poista tallenteen merkinnät?"
-+
-+msgid "Delete resume information?"
-+msgstr "Poista tallenteen paluutiedot?"
-+
-+msgid "File transfer started"
-+msgstr "Tiedoston siirto aloitettu"
-+
-+msgid "Can't start file transfer!"
-+msgstr "Tiedoston siirron aloitus epäonnistui!"
-+
-+msgid "File transfer already active!"
-+msgstr "Tiedoston siirto on jo käynnissä!"
-+ 
-+#. TRANSLATORS: note the leading blank!
-+msgid " Cancel file transfer"
-+msgstr " Peru tiedoston siirto"
-+
-+msgid "Cancel file transfer?"
-+msgstr "Perutaanko tiedoston siirto?"
-+
-+msgid "Transfering file - shut down anyway?"
-+msgstr "Tiedoston siirto kesken - sammutetaanko?"
-+
-+msgid "Transfering file - restart anyway?"
-+msgstr "Tiedoston siirto kesken - käynnistetäänkö uudelleen?"
-+
-+msgid "File transfer failed!"
-+msgstr "Tiedoston siirto epäonnistui!"
-+
-+msgid "File transfer finished"
-+msgstr "Tiedoston siirto valmis"
-+
-+msgid "File already exists - overwrite?"
-+msgstr "Tiedosto on jo olemassa - ylikirjoitetaanko?"
-diff -up vdr-2.0.6/po/hu_HU.po~ vdr-2.0.6/po/hu_HU.po
---- vdr-2.0.6/po/hu_HU.po~	2014-03-22 12:54:14.959879812 +0200
-+++ vdr-2.0.6/po/hu_HU.po	2014-03-23 11:43:03.388540484 +0200
-@@ -1402,3 +1402,70 @@ msgstr "Lemez"
- 
- msgid "free"
- msgstr "szabad"
-+
-+msgid "Edit recording"
-+msgstr "Felvétel szerkesztése"
-+
-+msgid "Button$Cut"
-+msgstr "Vágás"
-+
-+msgid "Button$Copy"
-+msgstr "Másolás"
-+
-+msgid "Button$Rename/Move"
-+msgstr "Áthelyezés"
-+
-+msgid "Date"
-+msgstr "Dátum"
-+
-+msgid "Length"
-+msgstr "Hossz"
-+
-+msgid "Format"
-+msgstr "Formátum"
-+
-+msgid "PES"
-+msgstr "PES"
-+
-+msgid "TS"
-+msgstr "TS"
-+
-+msgid "Size"
-+msgstr "Méret"
-+
-+msgid "Delete marks information?"
-+msgstr "Vágópontok törlése?"
-+
-+msgid "Delete resume information?"
-+msgstr "Lejátszott pozició törlése?"
-+
-+msgid "File transfer started"
-+msgstr "Áthelyezés folyamatban"
-+
-+msgid "Can't start file transfer!"
-+msgstr "Áthelyezés nem indítható"
-+
-+msgid "File transfer already active!"
-+msgstr "Áthelyezés már aktív!"
-+ 
-+#. TRANSLATORS: note the leading blank!
-+msgid " Cancel file transfer"
-+msgstr " Áthelyezés megszakítása"
-+
-+msgid "Cancel file transfer?"
-+msgstr "Áthelyezés megszakítása?"
-+
-+msgid "Transfering file - shut down anyway?"
-+msgstr "Áthelyezése folyamatban - biztos leállítjuk?"
-+
-+msgid "Transfering file - restart anyway?"
-+msgstr "Áthelyezés folyamatban - biztos újraindítjuk?"
-+
-+msgid "File transfer failed!"
-+msgstr "Sikertelen áthelyezés!"
-+
-+msgid "File transfer finished"
-+msgstr "Áthelyezés befejezve"
-+
-+msgid "File already exists - overwrite?"
-+msgstr "A file létezik - felülírjam?"
-diff -up vdr-2.0.6/recording.c~ vdr-2.0.6/recording.c
---- vdr-2.0.6/recording.c~	2014-03-16 13:03:18.000000000 +0200
-+++ vdr-2.0.6/recording.c	2014-03-23 11:43:03.388540484 +0200
-@@ -1089,6 +1089,16 @@ const char *cRecording::PrefixFileName(c
-   return NULL;
- }
- 
-+const char *cRecording::UpdateFileName(const char *FileName)
-+{
-+  if (FileName && *FileName) {
-+     free(fileName);
-+     fileName = strdup(FileName);
-+     return fileName;
-+     }
-+  return NULL;
-+}
-+
- int cRecording::HierarchyLevels(void) const
- {
-   const char *s = name;
-@@ -1401,7 +1411,7 @@ void cRecordings::AddByName(const char *
-      }
- }
- 
--void cRecordings::DelByName(const char *FileName)
-+void cRecordings::DelByName(const char *FileName, bool RemoveRecording)
- {
-   LOCK_THREAD;
-   cRecording *recording = GetByName(FileName);
-@@ -1409,7 +1419,7 @@ void cRecordings::DelByName(const char *
-      cThreadLock DeletedRecordingsLock(&DeletedRecordings);
-      Del(recording, false);
-      char *ext = strrchr(recording->fileName, '.');
--     if (ext) {
-+     if (ext && RemoveRecording) {
-         strncpy(ext, DELEXT, strlen(ext));
-         if (access(recording->FileName(), F_OK) == 0) {
-            recording->deleted = time(NULL);
-@@ -2437,7 +2447,7 @@ int ReadFrame(cUnbufferedFile *f, uchar
- 
- // --- Recordings Sort Mode --------------------------------------------------
- 
--eRecordingsSortMode RecordingsSortMode = rsmName;
-+eRecordingsSortMode RecordingsSortMode = rsmTime;
- 
- bool HasRecordingsSortMode(const char *Directory)
- {
-diff -up vdr-2.0.6/recording.h~ vdr-2.0.6/recording.h
---- vdr-2.0.6/recording.h~	2013-12-25 12:54:05.000000000 +0200
-+++ vdr-2.0.6/recording.h	2014-03-23 11:43:03.389540505 +0200
-@@ -120,6 +120,7 @@ public:
-   const char *Title(char Delimiter = ' ', bool NewIndicator = false, int Level = -1) const;
-   const cRecordingInfo *Info(void) const { return info; }
-   const char *PrefixFileName(char Prefix);
-+  const char *UpdateFileName(const char *FileName);
-   int HierarchyLevels(void) const;
-   void ResetResume(void) const;
-   double FramesPerSecond(void) const { return framesPerSecond; }
-@@ -131,7 +132,7 @@ public:
-   int FileSizeMB(void) const;
-        ///< Returns the total file size of this recording (in MB), or -1 if the file
-        ///< size is unknown.
--  bool IsNew(void) const { return GetResume() <= 0; }
-+  bool IsNew(void) const { return GetResume() < 0; }
-   bool IsEdited(void) const;
-   bool IsPesRecording(void) const { return isPesRecording; }
-   bool IsOnVideoDirectoryFileSystem(void) const;
-@@ -193,7 +194,7 @@ public:
-   void ClearSortNames(void);
-   cRecording *GetByName(const char *FileName);
-   void AddByName(const char *FileName, bool TriggerUpdate = true);
--  void DelByName(const char *FileName);
-+  void DelByName(const char *FileName, bool RemoveRecording = true);
-   void UpdateByName(const char *FileName);
-   int TotalFileSizeMB(void);
-   double MBperMinute(void);
-diff -up vdr-2.0.6/shutdown.c~ vdr-2.0.6/shutdown.c
---- vdr-2.0.6/shutdown.c~	2013-02-18 12:33:26.000000000 +0200
-+++ vdr-2.0.6/shutdown.c	2014-03-23 11:43:03.389540505 +0200
-@@ -17,6 +17,7 @@
- #include "channels.h"
- #include "config.h"
- #include "cutter.h"
-+#include "filetransfer.h"
- #include "i18n.h"
- #include "interface.h"
- #include "menu.h"
-@@ -171,6 +172,10 @@ bool cShutdownHandler::ConfirmShutdown(b
-      if (!Interactive || !Interface->Confirm(tr("Editing - shut down anyway?")))
-         return false;
-      }
-+  if (cFileTransfer::Active()) {
-+     if (!Interactive || !Interface->Confirm(tr("Transfering file - shut down anyway?")))
-+        return false;
-+     }
- 
-   cTimer *timer = Timers.GetNextActiveTimer();
-   time_t Next = timer ? timer->StartTime() : 0;
-@@ -214,6 +219,10 @@ bool cShutdownHandler::ConfirmRestart(bo
-      if (!Interactive || !Interface->Confirm(tr("Editing - restart anyway?")))
-         return false;
-      }
-+  if (cFileTransfer::Active()) {
-+     if (!Interactive || !Interface->Confirm(tr("Transfering file - restart anyway?")))
-+        return false;
-+     }
- 
-   cTimer *timer = Timers.GetNextActiveTimer();
-   time_t Next  = timer ? timer->StartTime() : 0;
-diff -up vdr-2.0.6/svdrp.c~ vdr-2.0.6/svdrp.c
---- vdr-2.0.6/svdrp.c~	2013-02-17 15:18:01.000000000 +0200
-+++ vdr-2.0.6/svdrp.c	2014-03-23 11:43:03.389540505 +0200
-@@ -31,6 +31,7 @@
- #include "cutter.h"
- #include "device.h"
- #include "eitscan.h"
-+#include "filetransfer.h"
- #include "keys.h"
- #include "menu.h"
- #include "plugin.h"
-@@ -193,6 +194,11 @@ const char *HelpPages[] = {
-   "    After a CLRE command, no further EPG processing is done for 10\n"
-   "    seconds, so that data sent with subsequent PUTE commands doesn't\n"
-   "    interfere with data from the broadcasters.",
-+  "CPYR <number> <new name>\n"
-+  "    Copy the recording with the given number. Before a recording can be\n"
-+  "    copied, an LSTR command must have been executed in order to retrieve\n"
-+  "    the recording numbers. The numbers don't change during subsequent CPYR\n"
-+  "    commands.",
-   "DELC <number>\n"
-   "    Delete channel.",
-   "DELR <number>\n"
-@@ -258,6 +264,11 @@ const char *HelpPages[] = {
-   "    used to easily activate or deactivate a timer.",
-   "MOVC <number> <to>\n"
-   "    Move a channel to a new position.",
-+  "MOVR <number> <new name>\n"
-+  "    Move the recording with the given number. Before a recording can be\n"
-+  "    moved, an LSTR command must have been executed in order to retrieve\n"
-+  "    the recording numbers. The numbers don't change during subsequent MOVR\n"
-+  "    commands.",
-   "NEWC <settings>\n"
-   "    Create a new channel. Settings must be in the same format as returned\n"
-   "    by the LSTC command.",
-@@ -612,6 +623,32 @@ void cSVDRP::CmdCLRE(const char *Option)
-      }
- }
- 
-+void cSVDRP::CmdCPYR(const char *Option)
-+{
-+  if (*Option) {
-+     char *tail;
-+     int n = strtol(Option, &tail, 10);
-+     cRecording *recording = Recordings.Get(n - 1);
-+     if (recording && tail && tail != Option) {
-+        char *oldName = strdup(recording->Name());
-+        tail = skipspace(tail);
-+        if (!cFileTransfer::Active()) {
-+           if (cFileTransfer::Start(recording, tail, true))
-+              Reply(250, "Copying recording \"%s\" to \"%s\"", oldName, tail);
-+           else
-+              Reply(554, "Can't start file transfer");
-+           }
-+        else
-+           Reply(554, "File transfer already active");
-+        free(oldName);
-+        }
-+     else
-+        Reply(550, "Recording \"%d\" not found%s", n, Recordings.Count() ? "" : " (use LSTR before copying)");
-+     }
-+  else
-+     Reply(501, "Invalid Option \"%s\"", Option);
-+}
-+
- void cSVDRP::CmdDELC(const char *Option)
- {
-   if (*Option) {
-@@ -1320,6 +1357,32 @@ void cSVDRP::CmdMOVC(const char *Option)
-      Reply(501, "Missing channel number");
- }
- 
-+void cSVDRP::CmdMOVR(const char *Option)
-+{
-+  if (*Option) {
-+     char *tail;
-+     int n = strtol(Option, &tail, 10);
-+     cRecording *recording = Recordings.Get(n - 1);
-+     if (recording && tail && tail != Option) {
-+        char *oldName = strdup(recording->Name());
-+        tail = skipspace(tail);
-+        if (!cFileTransfer::Active()) {
-+           if (cFileTransfer::Start(recording, tail))
-+              Reply(250, "Moving recording \"%s\" to \"%s\"", oldName, tail);
-+           else
-+              Reply(554, "Can't start file transfer");
-+           }
-+        else
-+           Reply(554, "File transfer already active");
-+        free(oldName);
-+        }
-+     else
-+        Reply(550, "Recording \"%d\" not found%s", n, Recordings.Count() ? "" : " (use LSTR before moving)");
-+     }
-+  else
-+     Reply(501, "Invalid Option \"%s\"", Option);
-+}
-+
- void cSVDRP::CmdNEWC(const char *Option)
- {
-   if (*Option) {
-@@ -1644,6 +1707,7 @@ void cSVDRP::Execute(char *Cmd)
-   s = skipspace(s);
-   if      (CMD("CHAN"))  CmdCHAN(s);
-   else if (CMD("CLRE"))  CmdCLRE(s);
-+  else if (CMD("CPYR"))  CmdCPYR(s);
-   else if (CMD("DELC"))  CmdDELC(s);
-   else if (CMD("DELR"))  CmdDELR(s);
-   else if (CMD("DELT"))  CmdDELT(s);
-@@ -1659,6 +1723,7 @@ void cSVDRP::Execute(char *Cmd)
-   else if (CMD("MODC"))  CmdMODC(s);
-   else if (CMD("MODT"))  CmdMODT(s);
-   else if (CMD("MOVC"))  CmdMOVC(s);
-+  else if (CMD("MOVR"))  CmdMOVR(s);
-   else if (CMD("NEWC"))  CmdNEWC(s);
-   else if (CMD("NEWT"))  CmdNEWT(s);
-   else if (CMD("NEXT"))  CmdNEXT(s);
-diff -up vdr-2.0.6/svdrp.h~ vdr-2.0.6/svdrp.h
---- vdr-2.0.6/svdrp.h~	2012-04-26 13:30:06.000000000 +0300
-+++ vdr-2.0.6/svdrp.h	2014-03-23 11:43:03.389540505 +0200
-@@ -56,6 +56,7 @@ private:
-   void PrintHelpTopics(const char **hp);
-   void CmdCHAN(const char *Option);
-   void CmdCLRE(const char *Option);
-+  void CmdCPYR(const char *Option);
-   void CmdDELC(const char *Option);
-   void CmdDELR(const char *Option);
-   void CmdDELT(const char *Option);
-@@ -71,6 +72,7 @@ private:
-   void CmdMODC(const char *Option);
-   void CmdMODT(const char *Option);
-   void CmdMOVC(const char *Option);
-+  void CmdMOVR(const char *Option);
-   void CmdNEWC(const char *Option);
-   void CmdNEWT(const char *Option);
-   void CmdNEXT(const char *Option);
-diff -up vdr-2.0.6/vdr.c~ vdr-2.0.6/vdr.c
---- vdr-2.0.6/vdr.c~	2014-01-26 14:45:00.000000000 +0200
-+++ vdr-2.0.6/vdr.c	2014-03-23 11:43:03.389540505 +0200
-@@ -45,6 +45,7 @@
- #include "dvbdevice.h"
- #include "eitscan.h"
- #include "epg.h"
-+#include "filetransfer.h"
- #include "i18n.h"
- #include "interface.h"
- #include "keys.h"
-@@ -1322,6 +1323,12 @@ int main(int argc, char *argv[])
-               else
-                  Skins.Message(mtInfo, tr("Editing process finished"));
-               }
-+           if (!cFileTransfer::Active() && cFileTransfer::Ended()) {
-+              if (cFileTransfer::Error())
-+                 Skins.Message(mtError, tr("File transfer failed!"));
-+              else
-+                 Skins.Message(mtInfo, tr("File transfer finished"));
-+              }
-            }
- 
-         // SIGHUP shall cause a restart:
-@@ -1337,7 +1344,7 @@ int main(int argc, char *argv[])
-               ShutdownHandler.countdown.Cancel();
-            }
- 
--        if ((Now - LastInteract) > ACTIVITYTIMEOUT && !cRecordControls::Active() && !cCutter::Active() && !Interface->HasSVDRPConnection() && (Now - cRemote::LastActivity()) > ACTIVITYTIMEOUT) {
-+        if ((Now - LastInteract) > ACTIVITYTIMEOUT && !cRecordControls::Active() && !cCutter::Active() && !cFileTransfer::Active() && !Interface->HasSVDRPConnection() && (Now - cRemote::LastActivity()) > ACTIVITYTIMEOUT) {
-            // Handle housekeeping tasks
- 
-            // Shutdown:
-@@ -1387,6 +1394,7 @@ Exit:
- 
-   PluginManager.StopPlugins();
-   cRecordControls::Shutdown();
-+  cFileTransfer::Stop();
-   cCutter::Stop();
-   delete Menu;
-   cControl::Shutdown();
-diff -up vdr-2.0.6/videodir.c~ vdr-2.0.6/videodir.c
---- vdr-2.0.6/videodir.c~	2012-09-30 15:06:33.000000000 +0300
-+++ vdr-2.0.6/videodir.c	2014-03-23 11:43:03.390540526 +0200
-@@ -229,6 +229,22 @@ cString PrefixVideoFileName(const char *
-   return NULL;
- }
- 
-+cString NewVideoFileName(const char *FileName, const char *NewDirName)
-+{
-+  char *NewDir = ExchangeChars(strdup(NewDirName), true);
-+  if (NewDir) {
-+     const char *p = FileName + strlen(FileName); // p points at the terminating 0
-+     while (p-- > FileName) {
-+           if (*p == '/')
-+              break;
-+           }
-+     cString NewName = cString::sprintf("%s/%s%s", VideoDirectory, NewDir, p);
-+     free(NewDir);
-+     return NewName;
-+     }
-+  return NULL;
-+}
-+
- void RemoveEmptyVideoDirectories(const char *IgnoreFiles[])
- {
-   cVideoDirectory Dir;
-diff -up vdr-2.0.6/videodir.h~ vdr-2.0.6/videodir.h
---- vdr-2.0.6/videodir.h~	2012-09-30 14:01:15.000000000 +0300
-+++ vdr-2.0.6/videodir.h	2014-03-23 11:43:03.390540526 +0200
-@@ -23,6 +23,7 @@ bool RemoveVideoFile(const char *FileNam
- bool VideoFileSpaceAvailable(int SizeMB);
- int VideoDiskSpace(int *FreeMB = NULL, int *UsedMB = NULL); // returns the used disk space in percent
- cString PrefixVideoFileName(const char *FileName, char Prefix);
-+cString NewVideoFileName(const char *FileName, const char *NewDirName);
- void RemoveEmptyVideoDirectories(const char *IgnoreFiles[] = NULL);
- bool IsOnVideoDirectoryFileSystem(const char *FileName);
- 
diff --git a/vdr-2.2.0-ttxtsubs.patch b/vdr-2.2.0-ttxtsubs.patch
new file mode 100644
index 0000000..929210f
--- /dev/null
+++ b/vdr-2.2.0-ttxtsubs.patch
@@ -0,0 +1,1016 @@
+diff --git a/MANUAL b/MANUAL
+index 3c4003e..e8de3ad 100644
+--- a/MANUAL
++++ b/MANUAL
+@@ -810,6 +810,9 @@ Version 2.2
+                          background transparency. By default the values as broadcast
+                          are used.
+ 
++  Enable teletext support = yes
++                         If set to 'yes', enables teletext subtitles.
++
+   LNB:
+ 
+   Use DiSEqC = no        Generally turns DiSEqC support on or off.
+diff --git a/Makefile b/Makefile
+index 9722036..92db319 100644
+--- a/Makefile
++++ b/Makefile
+@@ -74,6 +74,8 @@ OBJS = args.o audio.o channels.o ci.o config.o cutter.o device.o diseqc.o dvbdev
+        skinclassic.o skinlcars.o skins.o skinsttng.o sourceparams.o sources.o spu.o status.o svdrp.o themes.o thread.o\
+        timers.o tools.o transfer.o vdr.o videodir.o
+ 
++OBJS += vdrttxtsubshooks.o
++
+ DEFINES  += $(CDEFINES)
+ INCLUDES += $(CINCLUDES)
+ 
+diff --git a/channels.c b/channels.c
+index 564088f..d0fc3d8 100644
+--- a/channels.c
++++ b/channels.c
+@@ -421,6 +421,26 @@ void cChannel::SetSubtitlingDescriptors(uchar *SubtitlingTypes, uint16_t *Compos
+      }
+ }
+ 
++void cChannel::SetTeletextSubtitlePages(tTeletextSubtitlePage pages[], int numberOfPages)
++{
++  int mod = CHANNELMOD_NONE;
++  if (totalTtxtSubtitlePages != (fixedTtxtSubtitlePages + numberOfPages))
++     mod |= CHANNELMOD_PIDS;
++  totalTtxtSubtitlePages = fixedTtxtSubtitlePages;
++  for (int i = 0; (i < numberOfPages) && (totalTtxtSubtitlePages < MAXTXTPAGES); i++) {
++      if (teletextSubtitlePages[totalTtxtSubtitlePages].ttxtMagazine != pages[i].ttxtMagazine ||
++          teletextSubtitlePages[totalTtxtSubtitlePages].ttxtPage != pages[i].ttxtPage ||
++          teletextSubtitlePages[totalTtxtSubtitlePages].ttxtType != pages[i].ttxtType ||
++          strcmp(teletextSubtitlePages[totalTtxtSubtitlePages].ttxtLanguage, pages[i].ttxtLanguage)) {
++         mod |= CHANNELMOD_PIDS;
++         teletextSubtitlePages[totalTtxtSubtitlePages] = pages[i];
++         }
++      totalTtxtSubtitlePages++;
++      }
++  modification |= mod;
++  Channels.SetModified();
++}
++
+ void cChannel::SetSeen(void)
+ {
+   seen = time(NULL);
+@@ -556,10 +576,17 @@ cString cChannel::ToText(const cChannel *Channel)
+         q += IntArrayToString(q, Channel->dpids, 10, Channel->dlangs, Channel->dtypes);
+         }
+      *q = 0;
+-     const int TBufferSize = MAXSPIDS * (5 + 1 + MAXLANGCODE2) + 10; // 5 digits plus delimiting ',' or ';' plus optional '=cod+cod', +10: paranoia and tpid
++     const int TBufferSize = (MAXTXTPAGES * MAXSPIDS) * (5 + 1 + MAXLANGCODE2) + 10; // 5 digits plus delimiting ',' or ';' plus optional '=cod+cod', +10: paranoia and tpid
+      char tpidbuf[TBufferSize];
+      q = tpidbuf;
+      q += snprintf(q, sizeof(tpidbuf), "%d", Channel->tpid);
++     if (Channel->fixedTtxtSubtitlePages > 0) {
++        *q++ = '+';
++        for (int i = 0; i < Channel->fixedTtxtSubtitlePages; ++i) {
++            tTeletextSubtitlePage page = Channel->teletextSubtitlePages[i];
++            q += snprintf(q, sizeof(tpidbuf) - (q - tpidbuf), "%d=%s", page.PageNumber(), page.ttxtLanguage);
++            }
++        }
+      if (Channel->spids[0]) {
+         *q++ = ';';
+         q += IntArrayToString(q, Channel->spids, 10, Channel->slangs);
+@@ -730,6 +757,32 @@ bool cChannel::Parse(const char *s)
+                     }
+               spids[NumSpids] = 0;
+               }
++           fixedTtxtSubtitlePages = 0;
++           if ((p = strchr(tpidbuf, '+')) != NULL) {
++              *p++ = 0;
++              char *q;
++              char *strtok_next;
++              while ((q = strtok_r(p, ",", &strtok_next)) != NULL) {
++                    if (fixedTtxtSubtitlePages < MAXTXTPAGES) {
++                       int page;
++                       char *l = strchr(q, '=');
++                       if (l)
++                          *l++ = 0;
++                       if (sscanf(q, "%d", &page) == 1) {
++                          teletextSubtitlePages[fixedTtxtSubtitlePages] = tTeletextSubtitlePage(page);
++                          if (l)
++                             strn0cpy(teletextSubtitlePages[fixedTtxtSubtitlePages].ttxtLanguage, l, MAXLANGCODE2);
++                          fixedTtxtSubtitlePages++;
++                          }
++                       else
++                          esyslog("ERROR: invalid Teletext page!"); // no need to set ok to 'false'
++                       }
++                    else
++                       esyslog("ERROR: too many Teletext pages!"); // no need to set ok to 'false'
++                    p = NULL;
++                    }
++              totalTtxtSubtitlePages = fixedTtxtSubtitlePages;
++              }
+            if (sscanf(tpidbuf, "%d", &tpid) != 1)
+               return false;
+            if (caidbuf) {
+diff --git a/channels.h b/channels.h
+index 3323882..c62fdec 100644
+--- a/channels.h
++++ b/channels.h
+@@ -36,6 +36,7 @@
+ #define MAXDPIDS 16 // dolby (AC3 + DTS)
+ #define MAXSPIDS 32 // subtitles
+ #define MAXCAIDS 12 // conditional access
++#define MAXTXTPAGES 8 // teletext pages
+ 
+ #define MAXLANGCODE1 4 // a 3 letter language code, zero terminated
+ #define MAXLANGCODE2 8 // up to two 3 letter language codes, separated by '+' and zero terminated
+@@ -72,6 +73,16 @@ public:
+   static const tChannelID InvalidID;
+   };
+ 
++struct tTeletextSubtitlePage {
++  tTeletextSubtitlePage(void) { ttxtPage = ttxtMagazine = 0; ttxtType = 0x02; strcpy(ttxtLanguage, "und"); }
++  tTeletextSubtitlePage(int page) { ttxtMagazine = (page / 100) & 0x7; ttxtPage = (((page % 100) / 10) << 4) + (page % 10); ttxtType = 0x02; strcpy(ttxtLanguage, "und"); }
++  char ttxtLanguage[MAXLANGCODE1];
++  uchar ttxtPage;
++  uchar ttxtMagazine;
++  uchar ttxtType;
++  int PageNumber(void) const { return BCDCHARTOINT(ttxtMagazine) * 100 + BCDCHARTOINT(ttxtPage); }
++  };
++
+ class cChannel;
+ 
+ class cLinkChannel : public cListObject {
+@@ -116,6 +127,9 @@ private:
+   uint16_t compositionPageIds[MAXSPIDS];
+   uint16_t ancillaryPageIds[MAXSPIDS];
+   int tpid;
++  int fixedTtxtSubtitlePages;
++  int totalTtxtSubtitlePages;
++  tTeletextSubtitlePage teletextSubtitlePages[MAXTXTPAGES];
+   int caids[MAXCAIDS + 1]; // list is zero-terminated
+   int nid;
+   int tid;
+@@ -169,6 +183,8 @@ public:
+   uint16_t CompositionPageId(int i) const { return (0 <= i && i < MAXSPIDS) ? compositionPageIds[i] : uint16_t(0); }
+   uint16_t AncillaryPageId(int i) const { return (0 <= i && i < MAXSPIDS) ? ancillaryPageIds[i] : uint16_t(0); }
+   int Tpid(void) const { return tpid; }
++  const tTeletextSubtitlePage *TeletextSubtitlePages() const { return teletextSubtitlePages; }
++  int TotalTeletextSubtitlePages() const { return totalTtxtSubtitlePages; }
+   const int *Caids(void) const { return caids; }
+   int Ca(int Index = 0) const { return Index < MAXCAIDS ? caids[Index] : 0; }
+   int Nid(void) const { return nid; }
+@@ -198,6 +214,7 @@ public:
+   void SetName(const char *Name, const char *ShortName, const char *Provider);
+   void SetPortalName(const char *PortalName);
+   void SetPids(int Vpid, int Ppid, int Vtype, int *Apids, int *Atypes, char ALangs[][MAXLANGCODE2], int *Dpids, int *Dtypes, char DLangs[][MAXLANGCODE2], int *Spids, char SLangs[][MAXLANGCODE2], int Tpid);
++  void SetTeletextSubtitlePages(tTeletextSubtitlePage pages[], int numberOfPages);
+   void SetCaIds(const int *CaIds); // list must be zero-terminated
+   void SetCaDescriptors(int Level);
+   void SetLinkChannels(cLinkChannels *LinkChannels);
+diff --git a/ci.c b/ci.c
+index ffc7ff7..b6c5753 100644
+--- a/ci.c
++++ b/ci.c
+@@ -2155,6 +2155,8 @@ void cCamSlot::AddChannel(const cChannel *Channel)
+          AddPid(Channel->Sid(), *Dpid, STREAM_TYPE_PRIVATE);
+      for (const int *Spid = Channel->Spids(); *Spid; Spid++)
+          AddPid(Channel->Sid(), *Spid, STREAM_TYPE_PRIVATE);
++     if (Channel->Tpid() && Setup.SupportTeletext)
++        AddPid(Channel->Sid(), Channel->Tpid(), STREAM_TYPE_PRIVATE);
+      }
+ }
+ 
+@@ -2178,6 +2180,9 @@ bool cCamSlot::CanDecrypt(const cChannel *Channel)
+          CaPmt.AddPid(*Dpid, STREAM_TYPE_PRIVATE);
+      for (const int *Spid = Channel->Spids(); *Spid; Spid++)
+          CaPmt.AddPid(*Spid, STREAM_TYPE_PRIVATE);
++     if (Channel->Tpid() && Setup.SupportTeletext) {
++        CaPmt.AddPid(Channel->Tpid(), STREAM_TYPE_PRIVATE);
++        }
+      cas->SendPMT(&CaPmt);
+      cTimeMs Timeout(QUERY_REPLY_TIMEOUT);
+      do {
+diff --git a/config.c b/config.c
+index 9c6b71e..83e2e6f 100644
+--- a/config.c
++++ b/config.c
+@@ -403,6 +403,7 @@ cSetup::cSetup(void)
+   MarginStop = 10;
+   AudioLanguages[0] = -1;
+   DisplaySubtitles = 0;
++  SupportTeletext = 1;
+   SubtitleLanguages[0] = -1;
+   SubtitleOffset = 0;
+   SubtitleFgTransparency = 0;
+@@ -625,6 +626,7 @@ bool cSetup::Parse(const char *Name, const char *Value)
+   else if (!strcasecmp(Name, "MarginStop"))          MarginStop         = atoi(Value);
+   else if (!strcasecmp(Name, "AudioLanguages"))      return ParseLanguages(Value, AudioLanguages);
+   else if (!strcasecmp(Name, "DisplaySubtitles"))    DisplaySubtitles   = atoi(Value);
++  else if (!strcasecmp(Name, "SupportTeletext"))     SupportTeletext    = atoi(Value);
+   else if (!strcasecmp(Name, "SubtitleLanguages"))   return ParseLanguages(Value, SubtitleLanguages);
+   else if (!strcasecmp(Name, "SubtitleOffset"))      SubtitleOffset     = atoi(Value);
+   else if (!strcasecmp(Name, "SubtitleFgTransparency")) SubtitleFgTransparency = atoi(Value);
+@@ -751,6 +753,7 @@ bool cSetup::Save(void)
+   Store("MarginStop",         MarginStop);
+   StoreLanguages("AudioLanguages", AudioLanguages);
+   Store("DisplaySubtitles",   DisplaySubtitles);
++  Store("SupportTeletext",    SupportTeletext);
+   StoreLanguages("SubtitleLanguages", SubtitleLanguages);
+   Store("SubtitleOffset",     SubtitleOffset);
+   Store("SubtitleFgTransparency", SubtitleFgTransparency);
+diff --git a/config.h b/config.h
+index d1bae04..db1cbe1 100644
+--- a/config.h
++++ b/config.h
+@@ -280,6 +280,7 @@ public:
+   int MarginStart, MarginStop;
+   int AudioLanguages[I18N_MAX_LANGUAGES + 1];
+   int DisplaySubtitles;
++  int SupportTeletext;
+   int SubtitleLanguages[I18N_MAX_LANGUAGES + 1];
+   int SubtitleOffset;
+   int SubtitleFgTransparency, SubtitleBgTransparency;
+diff --git a/device.c b/device.c
+index 14ab07d..d4a6f5d 100644
+--- a/device.c
++++ b/device.c
+@@ -19,6 +19,7 @@
+ #include "receiver.h"
+ #include "status.h"
+ #include "transfer.h"
++#include "vdrttxtsubshooks.h"
+ 
+ // --- cLiveSubtitle ---------------------------------------------------------
+ 
+@@ -1321,6 +1322,13 @@ int cDevice::PlayPesPacket(const uchar *Data, int Length, bool VideoOnly)
+                   }
+                break;
+           case 0xBD: { // private stream 1
++               // EBU Teletext data, ETSI EN 300 472
++               // if PES data header length = 24 and data_identifier = 0x10..0x1F (EBU Data)
++               if (Data[8] == 0x24 && Data[45] >= 0x10 && Data[45] < 0x20) {
++                  cVDRTtxtsubsHookListener::Hook()->PlayerTeletextData((uint8_t*)Data, Length);
++                  break;
++                  }
++
+                int PayloadOffset = Data[8] + 9;
+ 
+                // Compatibility mode for old subtitles plugin:
+@@ -1480,6 +1488,7 @@ int cDevice::PlayTs(const uchar *Data, int Length, bool VideoOnly)
+      tsToPesVideo.Reset();
+      tsToPesAudio.Reset();
+      tsToPesSubtitle.Reset();
++     tsToPesTeletext.Reset();
+      }
+   else if (Length < TS_SIZE) {
+      esyslog("ERROR: skipped %d bytes of TS fragment", Length);
+@@ -1524,6 +1533,17 @@ int cDevice::PlayTs(const uchar *Data, int Length, bool VideoOnly)
+                     if (!VideoOnly || HasIBPTrickSpeed())
+                        PlayTsSubtitle(Data, TS_SIZE);
+                     }
++                 else if (Pid == patPmtParser.Tpid()) {
++                    if (!VideoOnly || HasIBPTrickSpeed()) {
++                       int l;
++                       tsToPesTeletext.PutTs(Data, Length);
++                       if (const uchar *p = tsToPesTeletext.GetPes(l)) {
++                          if ((l > 45) && (p[0] == 0x00) && (p[1] == 0x00) && (p[2] == 0x01) && (p[3] == 0xbd) && (p[8] == 0x24) && (p[45] >= 0x10) && (p[45] < 0x20))
++                             cVDRTtxtsubsHookListener::Hook()->PlayerTeletextData((uchar *)p, l, false, patPmtParser.TeletextSubtitlePages(), patPmtParser.TotalTeletextSubtitlePages());
++                          tsToPesTeletext.Reset();
++                          }
++                       }
++                    }
+                  }
+               }
+            else if (Pid == patPmtParser.Ppid()) {
+diff --git a/device.h b/device.h
+index b06d977..25a7bbe 100644
+--- a/device.h
++++ b/device.h
+@@ -602,6 +602,7 @@ private:
+   cTsToPes tsToPesVideo;
+   cTsToPes tsToPesAudio;
+   cTsToPes tsToPesSubtitle;
++  cTsToPes tsToPesTeletext;
+   bool isPlayingVideo;
+ protected:
+   const cPatPmtParser *PatPmtParser(void) const { return &patPmtParser; }
+diff --git a/menu.c b/menu.c
+index ae61c64..a0dba1b 100644
+--- a/menu.c
++++ b/menu.c
+@@ -3326,6 +3326,7 @@ void cMenuSetupDVB::Setup(void)
+      Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle foreground transparency"), &data.SubtitleFgTransparency, 0, 9));
+      Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle background transparency"), &data.SubtitleBgTransparency, 0, 10));
+      }
++  Add(new cMenuEditBoolItem(tr("Setup.DVB$Enable teletext support"), &data.SupportTeletext));
+ 
+   SetCurrent(Get(current));
+   Display();
+diff --git a/pat.c b/pat.c
+index 98d306e..4ca0d5a 100644
+--- a/pat.c
++++ b/pat.c
+@@ -12,6 +12,7 @@
+ #include "channels.h"
+ #include "libsi/section.h"
+ #include "libsi/descriptor.h"
++#include "vdrttxtsubshooks.h"
+ 
+ #define PMT_SCAN_TIMEOUT  1000 // ms
+ 
+@@ -426,6 +427,8 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
+         char DLangs[MAXDPIDS][MAXLANGCODE2] = { "" };
+         char SLangs[MAXSPIDS][MAXLANGCODE2] = { "" };
+         int Tpid = 0;
++        tTeletextSubtitlePage TeletextSubtitlePages[MAXTXTPAGES];
++        int NumTPages = 0;
+         int NumApids = 0;
+         int NumDpids = 0;
+         int NumSpids = 0;
+@@ -517,8 +520,21 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
+                                     NumSpids++;
+                                     }
+                                  break;
+-                            case SI::TeletextDescriptorTag:
++                            case SI::TeletextDescriptorTag: {
+                                  Tpid = esPid;
++                                 SI::TeletextDescriptor *sd = (SI::TeletextDescriptor *)d;
++                                 SI::TeletextDescriptor::Teletext ttxt;
++                                 for (SI::Loop::Iterator it; sd->teletextLoop.getNext(ttxt, it); ) {
++                                     bool isSubtitlePage = (ttxt.getTeletextType() == 0x02) || (ttxt.getTeletextType() == 0x05);
++                                     if ((NumTPages < MAXTXTPAGES) && ttxt.languageCode[0] && isSubtitlePage) {
++                                        strn0cpy(TeletextSubtitlePages[NumTPages].ttxtLanguage, I18nNormalizeLanguageCode(ttxt.languageCode), MAXLANGCODE1);
++                                        TeletextSubtitlePages[NumTPages].ttxtPage = ttxt.getTeletextPageNumber();
++                                        TeletextSubtitlePages[NumTPages].ttxtMagazine = ttxt.getTeletextMagazineNumber();
++                                        TeletextSubtitlePages[NumTPages].ttxtType = ttxt.getTeletextType();
++                                        NumTPages++;
++                                        }
++                                     }
++                                 }
+                                  break;
+                             case SI::ISO639LanguageDescriptorTag: {
+                                  SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d;
+@@ -630,6 +646,12 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
+             }
+         if (Setup.UpdateChannels >= 2) {
+            Channel->SetPids(Vpid, Ppid, Vtype, Apids, Atypes, ALangs, Dpids, Dtypes, DLangs, Spids, SLangs, Tpid);
++           if (NumTPages < MAXTXTPAGES) {
++              int manualPageNumber = cVDRTtxtsubsHookListener::Hook()->ManualPageNumber(Channel);
++              if (manualPageNumber)
++                 TeletextSubtitlePages[NumTPages++] = tTeletextSubtitlePage(manualPageNumber);
++              }
++           Channel->SetTeletextSubtitlePages(TeletextSubtitlePages, NumTPages);
+            Channel->SetCaIds(CaDescriptors->CaIds());
+            Channel->SetSubtitlingDescriptors(SubtitlingTypes, CompositionPageIds, AncillaryPageIds);
+            }
+diff --git a/po/ca_ES.po b/po/ca_ES.po
+index 8ea7bd3..5554051 100644
+--- a/po/ca_ES.po
++++ b/po/ca_ES.po
+@@ -1059,6 +1059,9 @@ msgstr "Transpar
+ msgid "Setup.DVB$Subtitle background transparency"
+ msgstr "Transpar�ncia fons subt�tols"
+ 
++msgid "Setup.DVB$Enable teletext support"
++msgstr ""
++
+ msgid "LNB"
+ msgstr "Configuraci� de l'LNB"
+ 
+diff --git a/po/cs_CZ.po b/po/cs_CZ.po
+index 6c5ac1b..91625a8 100644
+--- a/po/cs_CZ.po
++++ b/po/cs_CZ.po
+@@ -1059,6 +1059,9 @@ msgstr "Průhlednost písma titulků"
+ msgid "Setup.DVB$Subtitle background transparency"
+ msgstr "Průhlednost pozadí titulků"
+ 
++msgid "Setup.DVB$Enable teletext support"
++msgstr ""
++
+ msgid "LNB"
+ msgstr "LNB"
+ 
+diff --git a/po/da_DK.po b/po/da_DK.po
+index d0fbbf8..6504096 100644
+--- a/po/da_DK.po
++++ b/po/da_DK.po
+@@ -1056,6 +1056,9 @@ msgstr "Undertekst forgrundsgennemsigtighed"
+ msgid "Setup.DVB$Subtitle background transparency"
+ msgstr "Undertekst baggrundsgennemsigtighed"
+ 
++msgid "Setup.DVB$Enable teletext support"
++msgstr ""
++
+ msgid "LNB"
+ msgstr "LNB"
+ 
+diff --git a/po/de_DE.po b/po/de_DE.po
+index 762c6fa..0e28962 100644
+--- a/po/de_DE.po
++++ b/po/de_DE.po
+@@ -1057,6 +1057,9 @@ msgstr "Untertitel-Transparenz Vordergrund"
+ msgid "Setup.DVB$Subtitle background transparency"
+ msgstr "Untertitel-Transparenz Hintergrund"
+ 
++msgid "Setup.DVB$Enable teletext support"
++msgstr "Videotext-Unterst�tzung aktivieren"
++
+ msgid "LNB"
+ msgstr "LNB"
+ 
+diff --git a/po/el_GR.po b/po/el_GR.po
+index a131cd7..6f131a3 100644
+--- a/po/el_GR.po
++++ b/po/el_GR.po
+@@ -1056,6 +1056,9 @@ msgstr ""
+ msgid "Setup.DVB$Subtitle background transparency"
+ msgstr ""
+ 
++msgid "Setup.DVB$Enable teletext support"
++msgstr ""
++
+ msgid "LNB"
+ msgstr "LNB"
+ 
+diff --git a/po/es_ES.po b/po/es_ES.po
+index b2827b5..139da7a 100644
+--- a/po/es_ES.po
++++ b/po/es_ES.po
+@@ -1057,6 +1057,9 @@ msgstr "Transparencia primer plano subt
+ msgid "Setup.DVB$Subtitle background transparency"
+ msgstr "Transparencia fondo subt�tulos"
+ 
++msgid "Setup.DVB$Enable teletext support"
++msgstr ""
++
+ msgid "LNB"
+ msgstr "LNB"
+ 
+diff --git a/po/et_EE.po b/po/et_EE.po
+index 8bf931a..a4c9a09 100644
+--- a/po/et_EE.po
++++ b/po/et_EE.po
+@@ -1056,6 +1056,9 @@ msgstr "Subtiitri läbipaistvus"
+ msgid "Setup.DVB$Subtitle background transparency"
+ msgstr "Subtiitri tausta läbipaistvus"
+ 
++msgid "Setup.DVB$Enable teletext support"
++msgstr "Teleteksti tugi"
++
+ msgid "LNB"
+ msgstr "LNB"
+ 
+diff --git a/po/fi_FI.po b/po/fi_FI.po
+index 05d4b0f..9d55f39 100644
+--- a/po/fi_FI.po
++++ b/po/fi_FI.po
+@@ -1060,6 +1060,9 @@ msgstr "Tekstityksen läpinäkyvyys"
+ msgid "Setup.DVB$Subtitle background transparency"
+ msgstr "Tekstityksen taustan läpinäkyvyys"
+ 
++msgid "Setup.DVB$Enable teletext support"
++msgstr "Salli teksti-TV-tuki"
++
+ msgid "LNB"
+ msgstr "LNB"
+ 
+diff --git a/po/fr_FR.po b/po/fr_FR.po
+index 06bb125..d3276f5 100644
+--- a/po/fr_FR.po
++++ b/po/fr_FR.po
+@@ -1067,6 +1067,9 @@ msgstr "Transparence de l'avant-plan des sous-titres"
+ msgid "Setup.DVB$Subtitle background transparency"
+ msgstr "Transparence du fond des sous-titres"
+ 
++msgid "Setup.DVB$Enable teletext support"
++msgstr ""
++
+ msgid "LNB"
+ msgstr "LNB"
+ 
+diff --git a/po/hr_HR.po b/po/hr_HR.po
+index 0424a44..109af41 100644
+--- a/po/hr_HR.po
++++ b/po/hr_HR.po
+@@ -1058,6 +1058,9 @@ msgstr "Transparentnost titla"
+ msgid "Setup.DVB$Subtitle background transparency"
+ msgstr "Transparentnost pozadine titla"
+ 
++msgid "Setup.DVB$Enable teletext support"
++msgstr ""
++
+ msgid "LNB"
+ msgstr "LNB"
+ 
+diff --git a/po/hu_HU.po b/po/hu_HU.po
+index c34bc0e..32a0ee3 100644
+--- a/po/hu_HU.po
++++ b/po/hu_HU.po
+@@ -1061,6 +1061,9 @@ msgstr "Felirat transzparenciája"
+ msgid "Setup.DVB$Subtitle background transparency"
+ msgstr "Felirat hátterének transzparenciája"
+ 
++msgid "Setup.DVB$Enable teletext support"
++msgstr ""
++
+ msgid "LNB"
+ msgstr "LNB"
+ 
+diff --git a/po/it_IT.po b/po/it_IT.po
+index 79946ff..0b93c4a 100644
+--- a/po/it_IT.po
++++ b/po/it_IT.po
+@@ -1062,6 +1062,9 @@ msgstr "Trasparenza sottotitoli"
+ msgid "Setup.DVB$Subtitle background transparency"
+ msgstr "Trasparenza sfondo sottotitoli"
+ 
++msgid "Setup.DVB$Enable teletext support"
++msgstr ""
++
+ msgid "LNB"
+ msgstr "LNB"
+ 
+diff --git a/po/lt_LT.po b/po/lt_LT.po
+index a77dfcc..3ad927d 100644
+--- a/po/lt_LT.po
++++ b/po/lt_LT.po
+@@ -1056,6 +1056,9 @@ msgstr "Subtitrų fonto permatomumas"
+ msgid "Setup.DVB$Subtitle background transparency"
+ msgstr "Subtitrų fono permatomumas"
+ 
++msgid "Setup.DVB$Enable teletext support"
++msgstr ""
++
+ msgid "LNB"
+ msgstr "Konverteris (LNB)"
+ 
+diff --git a/po/nl_NL.po b/po/nl_NL.po
+index ab3fabd..b6e1a10 100644
+--- a/po/nl_NL.po
++++ b/po/nl_NL.po
+@@ -1062,6 +1062,9 @@ msgstr "Transparantie voorgrond ondertiteling"
+ msgid "Setup.DVB$Subtitle background transparency"
+ msgstr "Transparantie achtergrond ondertiteling"
+ 
++msgid "Setup.DVB$Enable teletext support"
++msgstr ""
++
+ msgid "LNB"
+ msgstr "LNB"
+ 
+diff --git a/po/nn_NO.po b/po/nn_NO.po
+index ba20fc6..11ce81e 100644
+--- a/po/nn_NO.po
++++ b/po/nn_NO.po
+@@ -1057,6 +1057,9 @@ msgstr ""
+ msgid "Setup.DVB$Subtitle background transparency"
+ msgstr ""
+ 
++msgid "Setup.DVB$Enable teletext support"
++msgstr ""
++
+ msgid "LNB"
+ msgstr "LNB"
+ 
+diff --git a/po/pl_PL.po b/po/pl_PL.po
+index becb8cb..9addb46 100644
+--- a/po/pl_PL.po
++++ b/po/pl_PL.po
+@@ -1059,6 +1059,9 @@ msgstr "Prze
+ msgid "Setup.DVB$Subtitle background transparency"
+ msgstr "Prze�rocze podtytu��w: T�o"
+ 
++msgid "Setup.DVB$Enable teletext support"
++msgstr ""
++
+ msgid "LNB"
+ msgstr "LNB"
+ 
+diff --git a/po/pt_PT.po b/po/pt_PT.po
+index 9a0f792..6a11cda 100644
+--- a/po/pt_PT.po
++++ b/po/pt_PT.po
+@@ -1057,6 +1057,9 @@ msgstr "Transpar
+ msgid "Setup.DVB$Subtitle background transparency"
+ msgstr "Transpar�ncia de fundo das legendas"
+ 
++msgid "Setup.DVB$Enable teletext support"
++msgstr ""
++
+ msgid "LNB"
+ msgstr "LNB"
+ 
+diff --git a/po/ro_RO.po b/po/ro_RO.po
+index c88dd0a..4f67d1c 100644
+--- a/po/ro_RO.po
++++ b/po/ro_RO.po
+@@ -1058,6 +1058,9 @@ msgstr "Transparenţa prim-planului subtitrării"
+ msgid "Setup.DVB$Subtitle background transparency"
+ msgstr "Transparenţa fundalului subtitrării"
+ 
++msgid "Setup.DVB$Enable teletext support"
++msgstr ""
++
+ msgid "LNB"
+ msgstr "LNB"
+ 
+diff --git a/po/ru_RU.po b/po/ru_RU.po
+index 3e5057d..5d50264 100644
+--- a/po/ru_RU.po
++++ b/po/ru_RU.po
+@@ -1057,6 +1057,9 @@ msgstr "
+ msgid "Setup.DVB$Subtitle background transparency"
+ msgstr "������������ ���� ���������"
+ 
++msgid "Setup.DVB$Enable teletext support"
++msgstr ""
++
+ msgid "LNB"
+ msgstr "���������"
+ 
+diff --git a/po/sk_SK.po b/po/sk_SK.po
+index cfc9bde..4fa36d0 100644
+--- a/po/sk_SK.po
++++ b/po/sk_SK.po
+@@ -1057,6 +1057,9 @@ msgstr "Prieh
+ msgid "Setup.DVB$Subtitle background transparency"
+ msgstr "Prieh�adnos� pozadia titulkov"
+ 
++msgid "Setup.DVB$Enable teletext support"
++msgstr ""
++
+ msgid "LNB"
+ msgstr "LNB (n�zko �umov� jednotka)"
+ 
+diff --git a/po/sl_SI.po b/po/sl_SI.po
+index d12ccb2..dd86028 100644
+--- a/po/sl_SI.po
++++ b/po/sl_SI.po
+@@ -1057,6 +1057,9 @@ msgstr "Transparentnost podnapisov"
+ msgid "Setup.DVB$Subtitle background transparency"
+ msgstr "Transparentnost ozadja podnapisov"
+ 
++msgid "Setup.DVB$Enable teletext support"
++msgstr ""
++
+ msgid "LNB"
+ msgstr "LNB"
+ 
+diff --git a/po/sv_SE.po b/po/sv_SE.po
+index c164fa1..1c07570 100644
+--- a/po/sv_SE.po
++++ b/po/sv_SE.po
+@@ -1061,6 +1061,9 @@ msgstr "Transparent f
+ msgid "Setup.DVB$Subtitle background transparency"
+ msgstr "Transparent bakgrund textremsa"
+ 
++msgid "Setup.DVB$Enable teletext support"
++msgstr ""
++
+ msgid "LNB"
+ msgstr "LNB"
+ 
+diff --git a/po/tr_TR.po b/po/tr_TR.po
+index 46a6a08..b4a8c55 100644
+--- a/po/tr_TR.po
++++ b/po/tr_TR.po
+@@ -1056,6 +1056,9 @@ msgstr "Altyaz
+ msgid "Setup.DVB$Subtitle background transparency"
+ msgstr "Altyaz� arka �effafl�k"
+ 
++msgid "Setup.DVB$Enable teletext support"
++msgstr ""
++
+ msgid "LNB"
+ msgstr "LNB"
+ 
+diff --git a/po/uk_UA.po b/po/uk_UA.po
+index 9d7328b..feba2ca 100644
+--- a/po/uk_UA.po
++++ b/po/uk_UA.po
+@@ -1057,6 +1057,9 @@ msgstr "Прозорість переднього плану субтитрів"
+ msgid "Setup.DVB$Subtitle background transparency"
+ msgstr "Прозорість заднього плану субтитрів"
+ 
++msgid "Setup.DVB$Enable teletext support"
++msgstr ""
++
+ msgid "LNB"
+ msgstr "Конвертер"
+ 
+diff --git a/po/zh_CN.po b/po/zh_CN.po
+index 0dfbd6c..9c16c46 100644
+--- a/po/zh_CN.po
++++ b/po/zh_CN.po
+@@ -1058,6 +1058,9 @@ msgstr "字幕前景透明度"
+ msgid "Setup.DVB$Subtitle background transparency"
+ msgstr "字幕背景透明度"
+ 
++msgid "Setup.DVB$Enable teletext support"
++msgstr ""
++
+ msgid "LNB"
+ msgstr "切换器设置"
+ 
+diff --git a/receiver.c b/receiver.c
+index d8f51e6..7e1c252 100644
+--- a/receiver.c
++++ b/receiver.c
+@@ -72,7 +72,8 @@ bool cReceiver::SetPids(const cChannel *Channel)
+             (Channel->Ppid() == Channel->Vpid() || AddPid(Channel->Ppid())) &&
+             AddPids(Channel->Apids()) &&
+             AddPids(Channel->Dpids()) &&
+-            AddPids(Channel->Spids());
++            AddPids(Channel->Spids()) &&
++            (!Setup.SupportTeletext || AddPid(Channel->Tpid()));
+      }
+   return true;
+ }
+diff --git a/remux.c b/remux.c
+index 23e8387..f1bf562 100644
+--- a/remux.c
++++ b/remux.c
+@@ -416,6 +416,29 @@ int cPatPmtGenerator::MakeSubtitlingDescriptor(uchar *Target, const char *Langua
+   return i;
+ }
+ 
++int cPatPmtGenerator::MakeTeletextDescriptor(uchar *Target, const tTeletextSubtitlePage *pages, int pageCount)
++{
++  int i = 0, j = 0;
++  Target[i++] = SI::TeletextDescriptorTag;
++  int l = i;
++  Target[i++] = 0x00; // length
++  for (int n = 0; n < pageCount; n++) {
++      const char* Language = pages[n].ttxtLanguage;
++      Target[i++] = *Language++;
++      Target[i++] = *Language++;
++      Target[i++] = *Language++;
++      Target[i++] = (pages[n].ttxtType << 3) + pages[n].ttxtMagazine;
++      Target[i++] = pages[n].ttxtPage;
++      j++;
++      }
++  if (j > 0) {
++     Target[l] = j * 5; // update length
++     IncEsInfoLength(i);
++     return i;
++     }
++  return 0;
++}
++
+ int cPatPmtGenerator::MakeLanguageDescriptor(uchar *Target, const char *Language)
+ {
+   int i = 0;
+@@ -503,6 +526,7 @@ void cPatPmtGenerator::GeneratePmt(const cChannel *Channel)
+   if (Channel) {
+      int Vpid = Channel->Vpid();
+      int Ppid = Channel->Ppid();
++     int Tpid = Channel->Tpid();
+      uchar *p = buf;
+      int i = 0;
+      p[i++] = 0x02; // table id
+@@ -535,6 +559,10 @@ void cPatPmtGenerator::GeneratePmt(const cChannel *Channel)
+          i += MakeStream(buf + i, 0x06, Channel->Spid(n));
+          i += MakeSubtitlingDescriptor(buf + i, Channel->Slang(n), Channel->SubtitlingType(n), Channel->CompositionPageId(n), Channel->AncillaryPageId(n));
+          }
++     if (Tpid) {
++        i += MakeStream(buf + i, 0x06, Tpid);
++        i += MakeTeletextDescriptor(buf + i, Channel->TeletextSubtitlePages(), Channel->TotalTeletextSubtitlePages());
++        }
+ 
+      int sl = i - SectionLength - 2 + 4; // -2 = SectionLength storage, +4 = length of CRC
+      buf[SectionLength] |= (sl >> 8) & 0x0F;
+@@ -608,6 +636,7 @@ void cPatPmtParser::Reset(void)
+   pmtPids[0] = 0;
+   vpid = vtype = 0;
+   ppid = 0;
++  tpid = 0;
+ }
+ 
+ void cPatPmtParser::ParsePat(const uchar *Data, int Length)
+@@ -696,11 +725,13 @@ void cPatPmtParser::ParsePmt(const uchar *Data, int Length)
+      int NumSpids = 0;
+      vpid = vtype = 0;
+      ppid = 0;
++     tpid = 0;
+      apids[0] = 0;
+      dpids[0] = 0;
+      spids[0] = 0;
+      atypes[0] = 0;
+      dtypes[0] = 0;
++     totalTtxtSubtitlePages = 0;
+      SI::PMT::Stream stream;
+      for (SI::Loop::Iterator it; Pmt.streamLoop.getNext(stream, it); ) {
+          dbgpatpmt("     stream type = %02X, pid = %d", stream.getStreamType(), stream.getPid());
+@@ -799,6 +830,28 @@ void cPatPmtParser::ParsePmt(const uchar *Data, int Length)
+                                     spids[NumSpids] = 0;
+                                     }
+                                  break;
++                            case SI::TeletextDescriptorTag: {
++                                 dbgpatpmt(" teletext");
++                                 tpid = stream.getPid();
++                                 SI::TeletextDescriptor *sd = (SI::TeletextDescriptor *)d;
++                                 SI::TeletextDescriptor::Teletext ttxt;
++                                 if (totalTtxtSubtitlePages < MAXTXTPAGES) {
++                                    for (SI::Loop::Iterator it; sd->teletextLoop.getNext(ttxt, it); ) {
++                                        bool isSubtitlePage = (ttxt.getTeletextType() == 0x02) || (ttxt.getTeletextType() == 0x05);
++                                        if (isSubtitlePage && ttxt.languageCode[0]) {
++                                           dbgpatpmt(" '%s:%x.%x'", ttxt.languageCode, ttxt.getTeletextMagazineNumber(), ttxt.getTeletextPageNumber());
++                                           strn0cpy(teletextSubtitlePages[totalTtxtSubtitlePages].ttxtLanguage, I18nNormalizeLanguageCode(ttxt.languageCode), MAXLANGCODE1);
++                                           teletextSubtitlePages[totalTtxtSubtitlePages].ttxtPage = ttxt.getTeletextPageNumber();
++                                           teletextSubtitlePages[totalTtxtSubtitlePages].ttxtMagazine = ttxt.getTeletextMagazineNumber();
++                                           teletextSubtitlePages[totalTtxtSubtitlePages].ttxtType = ttxt.getTeletextType();
++                                           totalTtxtSubtitlePages++;
++                                           if (totalTtxtSubtitlePages >= MAXTXTPAGES)
++                                              break;
++                                           }
++                                        }
++                                    }
++                                 }
++                                 break;
+                             case SI::ISO639LanguageDescriptorTag: {
+                                  SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d;
+                                  dbgpatpmt(" '%s'", ld->languageCode);
+diff --git a/remux.h b/remux.h
+index 6bc91ad..039525d 100644
+--- a/remux.h
++++ b/remux.h
+@@ -302,6 +302,7 @@ protected:
+   int MakeStream(uchar *Target, uchar Type, int Pid);
+   int MakeAC3Descriptor(uchar *Target, uchar Type);
+   int MakeSubtitlingDescriptor(uchar *Target, const char *Language, uchar SubtitlingType, uint16_t CompositionPageId, uint16_t AncillaryPageId);
++  int MakeTeletextDescriptor(uchar *Target, const tTeletextSubtitlePage *pages, int pageCount);
+   int MakeLanguageDescriptor(uchar *Target, const char *Language);
+   int MakeCRC(uchar *Target, const uchar *Data, int Length);
+   void GeneratePmtPid(const cChannel *Channel);
+@@ -349,6 +350,7 @@ private:
+   int vpid;
+   int ppid;
+   int vtype;
++  int tpid;
+   int apids[MAXAPIDS + 1]; // list is zero-terminated
+   int atypes[MAXAPIDS + 1]; // list is zero-terminated
+   char alangs[MAXAPIDS][MAXLANGCODE2];
+@@ -361,6 +363,8 @@ private:
+   uint16_t compositionPageIds[MAXSPIDS];
+   uint16_t ancillaryPageIds[MAXSPIDS];
+   bool updatePrimaryDevice;
++  int totalTtxtSubtitlePages;
++  tTeletextSubtitlePage teletextSubtitlePages[MAXTXTPAGES];
+ protected:
+   int SectionLength(const uchar *Data, int Length) { return (Length >= 3) ? ((int(Data[1]) & 0x0F) << 8)| Data[2] : 0; }
+ public:
+@@ -397,6 +401,9 @@ public:
+   int Vtype(void) const { return vtype; }
+        ///< Returns the video stream type as defined by the current PMT, or 0 if no video
+        ///< stream type has been detected, yet.
++  int Tpid(void) { return tpid; }
++       ///< Returns the teletext pid as defined by the current PMT, or 0 if no teletext
++       ///< pid has been detected, yet.
+   const int *Apids(void) const { return apids; }
+   const int *Dpids(void) const { return dpids; }
+   const int *Spids(void) const { return spids; }
+@@ -411,6 +418,8 @@ public:
+   uchar SubtitlingType(int i) const { return (0 <= i && i < MAXSPIDS) ? subtitlingTypes[i] : uchar(0); }
+   uint16_t CompositionPageId(int i) const { return (0 <= i && i < MAXSPIDS) ? compositionPageIds[i] : uint16_t(0); }
+   uint16_t AncillaryPageId(int i) const { return (0 <= i && i < MAXSPIDS) ? ancillaryPageIds[i] : uint16_t(0); }
++  const tTeletextSubtitlePage *TeletextSubtitlePages() const { return teletextSubtitlePages; }
++  int TotalTeletextSubtitlePages() const { return totalTtxtSubtitlePages; }
+   };
+ 
+ // TS to PES converter:
+diff --git a/vdr.5 b/vdr.5
+index fa233d7..cc06655 100644
+--- a/vdr.5
++++ b/vdr.5
+@@ -249,6 +249,12 @@ by an '=' sign, as in
+ 
+ .B ...:201;2001=deu,2002=eng:...
+ 
++Manual teletext subtitling pages can be defined separated by a '+' sign.
++The pages (separated by commas) can contain language codes, delimited by a '='
++sign, as in
++
++.B ...:201+150=deu,151=fin;2001,2002:...
++
+ .TP
+ .B Conditional access
+ A hexadecimal integer defining how this channel can be accessed:
+diff --git a/vdrttxtsubshooks.c b/vdrttxtsubshooks.c
+new file mode 100644
+index 0000000..2471788
+--- /dev/null
++++ b/vdrttxtsubshooks.c
+@@ -0,0 +1,63 @@
++/*
++ * vdr-ttxtsubs - A plugin for the Linux Video Disk Recorder
++ * Copyright (c) 2003 - 2008 Ragnar Sundblad <ragge at nada.kth.se>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
++ * details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <stdint.h>
++
++#include "vdrttxtsubshooks.h"
++
++// XXX Really should be a list...
++static cVDRTtxtsubsHookListener *gListener;
++
++// ------ class cVDRTtxtsubsHookProxy ------
++
++class cVDRTtxtsubsHookProxy : public cVDRTtxtsubsHookListener
++{
++ public:
++  virtual void HideOSD(void) { if(gListener) gListener->HideOSD(); };
++  virtual void ShowOSD(void) { if(gListener) gListener->ShowOSD(); };
++  virtual void PlayerTeletextData(uint8_t *p, int length, bool IsPesRecording, const struct tTeletextSubtitlePage teletextSubtitlePages[] = NULL, int pageCount = 0)
++    { if(gListener) gListener->PlayerTeletextData(p, length, IsPesRecording, teletextSubtitlePages, pageCount); };
++  virtual int ManualPageNumber(const cChannel *channel)
++    { if(gListener) return gListener->ManualPageNumber(channel); else return 0; };
++};
++
++
++// ------ class cVDRTtxtsubsHookListener ------
++
++cVDRTtxtsubsHookListener::~cVDRTtxtsubsHookListener()
++{
++  gListener = 0;
++}
++
++void cVDRTtxtsubsHookListener::HookAttach(void)
++{
++  gListener = this;
++  //printf("cVDRTtxtsubsHookListener::HookAttach\n");
++}
++
++static cVDRTtxtsubsHookProxy gProxy;
++
++cVDRTtxtsubsHookListener *cVDRTtxtsubsHookListener::Hook(void)
++{
++  return &gProxy;
++}
++
+diff --git a/vdrttxtsubshooks.h b/vdrttxtsubshooks.h
+new file mode 100644
+index 0000000..2f97969
+--- /dev/null
++++ b/vdrttxtsubshooks.h
+@@ -0,0 +1,46 @@
++/*
++ * vdr-ttxtsubs - A plugin for the Linux Video Disk Recorder
++ * Copyright (c) 2003 - 2008 Ragnar Sundblad <ragge at nada.kth.se>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
++ * details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#ifndef __VDRTTXTSUBSHOOKS_H
++#define __VDRTTXTSUBSHOOKS_H
++
++#define TTXTSUBSVERSNUM 2
++
++class cDevice;
++class cChannel;
++struct tTeletextSubtitlePage;
++
++class cVDRTtxtsubsHookListener {
++ public:
++  cVDRTtxtsubsHookListener(void) {};
++  virtual ~cVDRTtxtsubsHookListener();
++
++  void HookAttach(void);
++
++  virtual void HideOSD(void) {};
++  virtual void ShowOSD(void) {};
++  virtual void PlayerTeletextData(uint8_t *p, int length, bool IsPesRecording = true, const struct tTeletextSubtitlePage teletextSubtitlePages[] = NULL, int pageCount = 0) {};
++  virtual int ManualPageNumber(const cChannel *channel) { return 0; };
++
++  // used by VDR to call hook listeners
++  static cVDRTtxtsubsHookListener *Hook(void);
++};
++
++#endif
diff --git a/vdr-timer-info-1.7.28.patch b/vdr-timer-info-1.7.28.patch
deleted file mode 100644
index 4c79ab8..0000000
--- a/vdr-timer-info-1.7.28.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff -up vdr-1.7.28/menu.c~ vdr-1.7.28/menu.c
---- vdr-1.7.28/menu.c~	2012-06-03 21:50:53.576250772 +0300
-+++ vdr-1.7.28/menu.c	2012-06-03 21:51:27.215801834 +0300
-@@ -1304,7 +1304,7 @@ void cMenuTimers::ActualiseDiskStatus(vo
-   // compute free disk space
-   int freeMB, freeMinutes, runshortMinutes;
-   VideoDiskSpace(&freeMB);
--  freeMinutes = int(double(freeMB) * 1.1 / MB_PER_MINUTE); // overestimate by 10 percent
-+  freeMinutes = int(double(freeMB) * 1.1 / 25.75); // overestimate by 10 percent
-   runshortMinutes = freeMinutes / 5; // 20 Percent
- 
-   // fill entries list
diff --git a/vdr-timer-info-2.2.0.patch b/vdr-timer-info-2.2.0.patch
new file mode 100644
index 0000000..5f9fe2e
--- /dev/null
+++ b/vdr-timer-info-2.2.0.patch
@@ -0,0 +1,15 @@
+diff --git a/menu.c b/menu.c
+index 14be0ed..9c6a0ff 100644
+--- a/menu.c
++++ b/menu.c
+@@ -1377,8 +1377,8 @@ void cMenuTimers::ActualiseDiskStatus(void)
+ 
+   // compute free disk space
+   int freeMB, freeMinutes, runshortMinutes;
+-  VideoDiskSpace(&freeMB);
+-  freeMinutes = int(double(freeMB) * 1.1 / MB_PER_MINUTE); // overestimate by 10 percent
++  cVideoDirectory::VideoDiskSpace(&freeMB);
++  freeMinutes = int(double(freeMB) * 1.1 / 25.75); // overestimate by 10 percent
+   runshortMinutes = freeMinutes / 5; // 20 Percent
+ 
+   // fill entries list
diff --git a/vdr.spec b/vdr.spec
index c23329f..918838a 100644
--- a/vdr.spec
+++ b/vdr.spec
@@ -20,10 +20,10 @@
 %global vdr_user  vdr
 %global vdr_group video
 # From APIVERSION in config.h
-%global apiver    2.0.6
+%global apiver    2.2.0
 
 Name:           vdr
-Version:        2.0.7
+Version:        2.2.0
 Release:        1%{?dist}
 Summary:        Video Disk Recorder
 
@@ -53,18 +53,13 @@ Source20:       %{name}-rcu.conf
 Source21:       %{name}-set-wakeup.sh
 Patch0:         %{name}-channel+epg.patch
 Patch1:         http://zap.tartarus.org/~ds/debian/dists/stable/main/source/vdr_1.4.5-2.ds.diff.gz
-# Extracted from original at http://www.saunalahti.fi/~rahrenbe/vdr/patches/vdr-2.0.3-vasarajanauloja.patch.gz
-Patch2:         %{name}-2.0.6-filetransfer.patch
 # Extracted from http://copperhead.htpc-forum.de/downloads/extensionpatch/extpngvdr1.7.21v1.diff.gz
 Patch3:         %{name}-1.7.21-plugin-missing.patch
 Patch4:         %{name}-1.7.41-paths.patch
 Patch5:         http://toms-cafe.de/vdr/download/vdr-timer-info-0.5-1.7.13.diff
 # http://article.gmane.org/gmane.linux.vdr/36097
 Patch6:         %{name}-1.5.18-syncearly.patch
-Patch7:         http://projects.vdr-developer.org/projects/plg-ttxtsubs/repository/revisions/master/raw/patches/vdr-2.0.6-ttxtsubs.patch
-# Extracted from http://copperhead.htpc-forum.de/downloads/extensionpatch/extpngvdr1.7.21v1.diff.gz
-# Original at http://toms-cafe.de/vdr/download/vdr-jumpplay-1.0-1.7.6.diff
-Patch8:         https://raw.githubusercontent.com/flensrocker/vdr-yavdr/master/debian/patches/opt-24_jumpplay.patch
+Patch7:         http://projects.vdr-developer.org/projects/plg-ttxtsubs/repository/revisions/master/raw/patches/vdr-2.2.0-ttxtsubs.patch
 # http://www.udo-richter.de/vdr/patches.en.html#hlcutter
 Patch9:         http://www.udo-richter.de/vdr/files/vdr-1.7.29-hlcutter-0.2.3.diff
 # http://www.udo-richter.de/vdr/naludump.en.html
@@ -75,12 +70,10 @@ Patch11:        %{name}-2.0.4-mainmenuhooks101.patch
 # Modified so that it applies over the timer-info patch
 Patch12:        %{name}-1.7.21-timercmd.patch
 Patch13:        http://projects.vdr-developer.org/git/vdr-plugin-epgsearch.git/plain/patches/vdr-1.5.17-progressbar-support-0.0.1.diff
-Patch14:        http://www.saunalahti.fi/~rahrenbe/vdr/patches/vdr-2.1.6-binaryskip.patch.gz
 Patch15:        %{name}-1.7.37-fedora-pkgconfig.patch
-Patch16:        %{name}-1.7.21-jumpplay-finnish.patch
 Patch17:        http://projects.vdr-developer.org/git/vdr-plugin-epgsearch.git/plain/patches/vdr.epgsearch-exttimeredit-0.0.2.diff
-Patch18:        %{name}-timer-info-1.7.28.patch
-Patch19:        http://www.saunalahti.fi/~rahrenbe/vdr/patches/vdr-2.1.6-menuselection.patch.gz
+Patch18:        %{name}-timer-info-2.2.0.patch
+Patch19:        http://www.saunalahti.fi/~rahrenbe/vdr/patches/vdr-2.1.9-menuselection.patch.gz
 Patch20:        http://projects.vdr-developer.org/git/vdr-plugin-epg2vdr.git/plain/patches/epghandler-segment-transfer.patch
 
 BuildRequires:  libjpeg-devel
@@ -182,7 +175,6 @@ patch -F 2 -i debian/patches/07_blockify_define.dpatch
 # TODO: does not apply
 #patch -F 0 -i debian/patches/10_livelock.dpatch
 patch -F 0 -i debian/patches/12_osdbase-maxitems.patch
-%patch2 -p1
 %patch3 -p1
 sed \
     -e 's|__CACHEDIR__|%{cachedir}|'   \
@@ -195,16 +187,13 @@ sed \
 # TODO: does not apply
 #patch6 -p0
 %patch7 -p1
-%patch8 -p1
 #TODO: patch9 -p1 -F 2
 %patch10 -p1
 %patch11 -p1
 %patch12 -p1
 # TODO: does not apply
 #patch13 -p1
-%patch14 -p1
 %patch15 -p1
-%patch16 -p1
 # TODO: build failure
 #patch17 -p0 -F 3
 %patch18 -p1
@@ -569,6 +558,9 @@ useradd -r -g %{vdr_group} -d %{vardir} -s /sbin/nologin -M -N \
 
 
 %changelog
+* Thu Feb 19 2015 Ville Skyttä <ville.skytta at iki.fi> - 2.2.0-1
+- Update to 2.2.0
+
 * Wed Jan 21 2015 Ville Skyttä <ville.skytta at iki.fi> - 2.0.7-1
 - Update to 2.0.7
 - Mark license files as %%license where available
-- 
cgit v0.10.2


	http://pkgs.fedoraproject.org/cgit/vdr.git/commit/?h=f22&id=52552c532d5fedc75ec84d5ddf925e722529245f


More information about the scm-commits mailing list