[vdr-plugin-remotetimers] 01/05: Imported Upstream version 1.0.1

Tobias Grimm tiber-guest at moszumanska.debian.org
Sat Feb 14 10:11:48 UTC 2015


This is an automated email from the git hooks/post-receive script.

tiber-guest pushed a commit to branch master
in repository vdr-plugin-remotetimers.

commit 1b35e982cf7b647f0b2de1a2b8c5f250a81c44b1
Author: etobi <git at e-tobi.net>
Date:   Tue Feb 10 09:44:50 2015 +0100

    Imported Upstream version 1.0.1
---
 HISTORY                                            |   32 +-
 Makefile                                           |   89 +-
 README                                             |  107 +-
 conflict.c                                         |  137 ++
 conflict.h                                         |   81 +
 i18n.c                                             | 2340 --------------------
 i18n.h                                             |    6 -
 include/epgsearch.h                                |  202 ++
 menu.c                                             | 1272 +++--------
 menu.h                                             |   84 +-
 menuitems.c                                        |    2 -
 moverec.c                                          |    2 -
 ...dr-1.4.x-1.7.27-remote_instant_recordings.patch |  124 --
 .../vdr-1.5.15-1.7.9-video_on_networkshare.diff    |   33 -
 ...-skinlcars.patch => vdr-1.7.29-skinlcars.patch} |   12 +-
 po/de_DE.po                                        |  104 +-
 po/it_IT.po                                        |  101 +-
 po/sk_SK.po                                        |  115 +-
 remotetimers.c                                     |   58 +-
 remotetimers.h                                     |   49 +-
 setup.c                                            |   61 +-
 setup.h                                            |    5 +
 svdrp.c                                            |   17 +-
 svdrp.h                                            |    7 +-
 svdrpservice.h                                     |   40 +
 25 files changed, 1271 insertions(+), 3809 deletions(-)

diff --git a/HISTORY b/HISTORY
index 6d1e83b..ad639b0 100644
--- a/HISTORY
+++ b/HISTORY
@@ -1,6 +1,34 @@
 VDR Plugin 'remotetimers' Revision History
 ------------------------------------------
 
+2013-08-12: Version 1.0.1
+
+- Fixed channel name width in schedule menus (reported by hummel99 at vdrportal)
+- Added custom schedule times in addition to "Now" and "Next" as in epgsearch
+  (suggested by hummel99 at vdrportal)
+- Show timer conflicts reported by epgsearch in timers menu (suggested by
+  Manfred Heindl)
+
+2013-06-07: Version 1.0.0
+
+- Updated the menu parts copied from VDR to 2.0.2
+- Added service call to open schedule or timers menu
+- Updated Makefile for VDR 1.7.36 and dropped compatibility with older VDR
+  versions
+- Updated the menu parts copied from VDR to 2.0.1
+- Updated Slovak translations (thanks to Milan Hrala)
+- Included a copy of svdrpservice.h
+- Updated skin LCARS patch for 1.7.29 and above
+- New setup options to control if the plugin's schedule, timers and recordings
+  menus should indicate the correct menu category (since VDR 1.7.28) and call
+  SetItemEvent/Timer/Recording (since VDR 1.7.34). Some skins will then use
+  their own way to display the item. However the skin is not aware of multiuser
+  or local and remote timers. So it will display all items the same way (thanks
+  to seahawk1986 at vdrportal for tuning and debugging this for skinnopacity).
+- Set menu category of main menu to mcMain (thanks to seahawk1986 at vdrportal)
+- Updated the menu parts copied from VDR to 1.7.35 including support for
+  sorting recordings with VDR 1.7.29 and above.
+
 2012-06-27: Version 0.1.7
 
 - If server recordings are mounted in a subdirectory of local video dir,
@@ -9,8 +37,8 @@ VDR Plugin 'remotetimers' Revision History
   mtime and device id of .update file already in SetupParse(), i.e. before VDR
   starts to scan recordings.
 - Updated Slovak translations (thanks to Milan Hrala)
-- Added vdr-1.7.28-remote_instant_recordings.patch to display remote timers
-  in skin LCARS' main menu view
+- Added vdr-1.7.28-skinlcars.patch to display remote timers in skin LCARS'
+  main menu view
 - Fixed RemoteTimers::ForEach service call
 - With 1.7.28 or newer, show remaining disk space in minutes based on size and
   length of currently selected recording in menus "Recording info" and "Edit
diff --git a/Makefile b/Makefile
index db45d64..af91f44 100644
--- a/Makefile
+++ b/Makefile
@@ -6,107 +6,110 @@
 # The official name of this plugin.
 # This name will be used in the '-P...' option of VDR to load the plugin.
 # By default the main source file also carries this name.
-#
+
 PLUGIN = remotetimers
 
 ### The version number of this plugin (taken from the main source file):
 
 VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g')
 
-### The C++ compiler and options:
-
-CXX      ?= g++
-CXXFLAGS ?= -fPIC -g -O2 -Wall -Woverloaded-virtual
-
 ### The directory environment:
 
-VDRDIR = ../../..
-LIBDIR = ../../lib
-TMPDIR = /tmp
+# Use package data if installed...otherwise assume we're under the VDR source directory:
+PKGCFG = $(if $(VDRDIR),$(shell pkg-config --variable=$(1) $(VDRDIR)/vdr.pc),$(shell pkg-config --variable=$(1) vdr || pkg-config --variable=$(1) ../../../vdr.pc))
+LIBDIR = $(call PKGCFG,libdir)
+LOCDIR = $(call PKGCFG,locdir)
+PLGCFG = $(call PKGCFG,plgcfg)
+#
+TMPDIR ?= /tmp
 
-### Allow user defined options to overwrite defaults:
+### The compiler options:
 
--include $(VDRDIR)/Make.config
+export CFLAGS   = $(call PKGCFG,cflags)
+export CXXFLAGS = $(call PKGCFG,cxxflags)
 
-### The version number of VDR's plugin API (taken from VDR's "config.h"):
+### The version number of VDR's plugin API:
 
-APIVERSION = $(shell sed -ne '/define APIVERSION/s/^.*"\(.*\)".*$$/\1/p' $(VDRDIR)/config.h)
+APIVERSION = $(call PKGCFG,apiversion)
+
+### Allow user defined options to overwrite defaults:
 
-### Test whether VDR has locale support
-VDRLOCALE = $(shell grep '^LOCALEDIR' $(VDRDIR)/Makefile)
+-include $(PLGCFG)
 
 ### The name of the distribution archive:
 
 ARCHIVE = $(PLUGIN)-$(VERSION)
 PACKAGE = vdr-$(ARCHIVE)
 
+### The name of the shared object file:
+
+SOFILE = libvdr-$(PLUGIN).so
+
 ### Includes and Defines (add further entries here):
 
-INCLUDES += -I$(VDRDIR)/include
+INCLUDES +=
 
-DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
+DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
 
 ### The object files (add further files here):
 
-OBJS = $(PLUGIN).o svdrp.o menu.o menuitems.o setup.o moverec.o watcher.o i18n.o
+OBJS = $(PLUGIN).o svdrp.o conflict.o menu.o menuitems.o setup.o moverec.o watcher.o
 
-.PHONY: all i18n dist clean
-all: libvdr-$(PLUGIN).so i18n
+### The main target:
+
+all: $(SOFILE) i18n
 
 ### Implicit rules:
 
 %.o: %.c
-	$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
+	$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
 
-# Dependencies:
+### Dependencies:
 
 MAKEDEP = $(CXX) -MM -MG
 DEPFILE = .dependencies
 $(DEPFILE): Makefile
-	@$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+	@$(MAKEDEP) $(CXXFLAGS) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
 
 -include $(DEPFILE)
 
 ### Internationalization (I18N):
 
 PODIR     = po
-
-ifneq ($(strip $(VDRLOCALE)),)
-
-LOCALEDIR = $(VDRDIR)/locale
 I18Npo    = $(wildcard $(PODIR)/*.po)
-I18Nmsgs  = $(addprefix $(LOCALEDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file))))))
+I18Nmo    = $(addsuffix .mo, $(foreach file, $(I18Npo), $(basename $(file))))
+I18Nmsgs  = $(addprefix $(DESTDIR)$(LOCDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file))))))
 I18Npot   = $(PODIR)/$(PLUGIN).pot
 
 %.mo: %.po
 	msgfmt -c -o $@ $<
 
 $(I18Npot): $(wildcard *.c) menu.h
-	xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktrREMOTETIMERS -ktrNOOP --msgid-bugs-address='<vdrdev at schmirler.de>' -o $@ $^
+	xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktrREMOTETIMERS -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<vdrdev at schmirler.de>' -o $@ `ls $^`
 
 %.po: $(I18Npot)
-	msgmerge -U --no-wrap --no-location --backup=none -q $@ $<
+	msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
 	@touch $@
 
-$(I18Nmsgs): $(LOCALEDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
-	@mkdir -p $(dir $@)
-	cp $< $@
-
-i18n: $(I18Nmsgs)
+$(I18Nmsgs): $(DESTDIR)$(LOCDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
+	install -D -m644 $< $@
 
-else
+.PHONY: i18n
+i18n: $(I18Nmo) $(I18Npot)
 
-i18n:
-	@### nothing to do
-endif
+install-i18n: $(I18Nmsgs)
 
 ### Targets:
 
-libvdr-$(PLUGIN).so: $(OBJS)
-	$(CXX) $(CXXFLAGS) -shared $(OBJS) -o $@
-	@cp $@ $(LIBDIR)/$@.$(APIVERSION)
+$(SOFILE): $(OBJS)
+	$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
+
+install-lib: $(SOFILE)
+	install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
+
+install: install-lib install-i18n
 
-dist: clean
+dist: $(I18Npo) clean
 	@-rm -rf $(TMPDIR)/$(ARCHIVE)
 	@mkdir $(TMPDIR)/$(ARCHIVE)
 	@cp -a * $(TMPDIR)/$(ARCHIVE)
diff --git a/README b/README
index cbeedcc..2c02280 100644
--- a/README
+++ b/README
@@ -42,7 +42,7 @@ Straightforward:
 - tar xzf vdr-remotetimers-<VERSION>.tgz
 - ln -sf remotetimers-<VERSION> remotetimers
 
-If you didn't do that already (otherwise svdrpservice.h is missing):
+If you didn't do that already:
 - tar xzf vdr-svdrpservice-<VERSION>.tgz
 - ln -sf svdrpservice-<VERSION> svdrpservice
 
@@ -55,10 +55,7 @@ work just fine without them, but add support for some additional features:
 - MainMenuHooks: replace the VDR menus "Schedule", "Timers" and "Recordings"
   with the corresponding plugin menus.
 - remote_instant_recordings: redirects instant recordings to the server VDR
-- video_on_networkshare: fixes a bug in VDR < 1.7.10. Apply if your local
-  video directory and at least one of its subdirectories are network mounts
-  of different shares. Without the patch the calculated amount of free
-  diskspace will not always be accurate.
+- skinlcars: show remote timers in mainmenu
 
 A detailed description of the patches and instructions how to apply them can
 be found in the patch files.
@@ -120,17 +117,6 @@ same channel numbers for corresponding DVB-T/DVB-S channels.
 - Hide mainmenu entry
 Should be obvious ;-)
 
-- Replace mainmenu "Schedule"
-When enabled, each call to the local VDR Schedule menu will give you
-the remotetimers Schedule menu instead. Only available if MainMenuHooks
-patch has been applied to VDR before compiling remotetimers.
-
-- Replace mainmenu "Timers"
-Dito for Timers menu.
-
-- Replace mainmenu "Recordings"
-Dito for Recordings menu.
-
 *** Defaults for new timers ***
 
 - Location
@@ -154,28 +140,77 @@ value "0" to indicate a timer which is always visible, i.e. belongs to
 everyone. If you select "Resume ID", remotetimers will assign the ID of
 the user who is current at the moment the timer is created.
 
-*** Settings for menu ***
+*** Settings for menu "Schedule" ***
 
-- Binding of Ok/Blue in "What's on" menus
-Vanilla VDR shows the EPG details with "Ok" and switches to the selected
-channel with "Blue". Swap it if you like.
+- Replace mainmenu
+When enabled, each call to the local VDR Schedule menu will give you
+the remotetimers Schedule menu instead. Only available if MainMenuHooks
+patch has been applied to VDR before compiling remotetimers.
+
+- List style
+Some skins display events in a more sophisticated way. With the default
+"Plugin" you will get a simple list. Select "Skin" if you want the skin
+to draw the list. The downside is that skins are not aware of multiuser,
+so it will display events with normal and private timers the same way
+(see "User ID filter" below).
 
 - Show progress bar in menu "Schedule"
 Adds progress bars to the "What's on now?" menu.
 
-- User ID filter in menu "Schedule"
+- What's on at ...? 1-4
+You can define up to 4 custom times which will show up in the "Schedule"
+menu in addition to "Now" and "Next". Hit the "Green" button in the
+"Schedule" menu multiple times to cycle through all views. The special
+value 00:00 disables the custom times. Use 00:01 or 23:59 to get the
+EPG for around midnight.
+
+- Key binding of Ok/Blue
+Vanilla VDR shows the EPG details with "Ok" and switches to the selected
+channel with "Blue". Swap it if you like.
+
+- User ID filter
 If set to "0", all timers will be shown. Private timers (as opposed to
 timers of user "0") are indicated with the character "P". If set to a
 specific ID, only timers of user "0" and the selected ID will be marked.
 Select "Resume ID" to filter by the current user.
 
-- User ID filter in menu "Timers"
+*** Settings for menu "Timers" ***
+
+- Replace mainmenu
+When enabled, each call to the local VDR Timers menu will give you
+the remotetimers Timers menu instead. Only available if MainMenuHooks
+patch has been applied to VDR before compiling remotetimers.
+
+- List style
+Some skins display timers in a more sophisticated way. With the default
+"Plugin" you will get a simple list. Select "Skin" if you want the skin
+to draw the list. The downside is that skins will display local and
+remote timers the same way.
+
+- User ID filter
 If set to "0", all timers will be listed. When set to a specific ID, only
 timers of this specific user and timers of user "0" will be visible. Select
 "Resume ID" to filter by the current user.
 
-- User ID filter in menu "Recordings"
-Dito for recordings. A recording inherits the user IDs of the timer.
+*** Settings for menu "Recordings" ***
+
+- Replace mainmenu
+When enabled, each call to the local VDR Recordings menu will give you
+the remotetimers Recordings menu instead. Only available if MainMenuHooks
+patch has been applied to VDR before compiling remotetimers.
+
+- List style
+Some skins display recordings in a more sophisticated way. With the
+default "Plugin" you will get a simple list. Select "Skin" if you want
+the skin to draw the list. With some skins you will get two free disk
+space indications in the title bar. Remotetimers shows it for the
+current partition, VDR for the main video directory.
+
+- User ID filter
+If set to "0", all recordings will be listed. When set to a specific ID,
+only recordings of this specific user and recordings of user "0" will be
+visible. Select "Resume ID" to filter by the current user. A recording
+inherits the user IDs of the timer.
 
 - Move recording bandwidth limit (Mbit/s)
 If you rename a recording and the new name points to a different filesystem,
@@ -281,9 +316,18 @@ the location moves the timer from the local to the remote VDR or vice versa.
 Note that you cannot move a running timer. It has to be stopped first. With
 "Red" you can select a folder for the recording.
 
+If a "%" is shown as the second character in the timer list, there's a timer
+conflict. Edit the timer to see the conflicting timers. The conflict check
+relies on the epgsearch plugin. It must be installed on the server to report
+remote timer conflicts and it must be installed on the client to report local
+timer conflicts.
+
 5.4. Recordings menu:
 ---------------------
 As in the timers menu, hit the number keys to change the user ID filter.
+In VDR you can change the sort order of recordings with "0". In remotetimers
+hit the current user ID.
+
 The "red" button will neither start to replay a recording nor will it open
 the recording commands menu. Instead it allows you to edit the recording.
 You can change the priority, lifetime, user IDs and the name. "Red" lets
@@ -301,19 +345,12 @@ In contrast to VDR's original recordings menu, the disk space information
 in the title bar always corresponds to the filesystem of the currently
 selected directory. So if there are subdirectories in your video directory
 which live on a different partition or on a network share, the disk space
-information changes when descending into this directory (requires at least
-VDR 1.5.15). Unfortunately there's a problem with the way VDR tests for
-directories on different filesystems. It will fail, if the base video
-directory itself is a network mount (e.g. NFS or CIFS). From the patches
-subdirectory, apply vdr-1.5.15-1.7.9-video_on_networkshare.diff to fix
-this. The patch is not required if the video directory is on a local
-harddrive and subdirectories are network mounts or if VDR is at least
-version 1.7.10.
+information changes when descending into this directory.
 
 The titles of the "Recording info" and "Edit recording" menus include
-the recording's size and length. Since VDR 1.7.28 it will also display the
-remaining disk space in minutes based on size and length of the currently
-selected recording.
+the recording's size and length. It will also display the remaining disk
+space in minutes based on size and length of the currently selected
+recording.
 
 6. Credits:
 -----------
diff --git a/conflict.c b/conflict.c
new file mode 100644
index 0000000..a2ccced
--- /dev/null
+++ b/conflict.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2008-2013 Frank Schmirler <vdr at schmirler.de>
+ *
+ * This file is part of VDR Plugin remotetimers.
+ *
+ * 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
+ * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <vdr/tools.h>
+#include <vdr/plugin.h>
+#include "conflict.h"
+#include "i18n.h"
+
+cLocalTimerConflicts LocalConflicts;
+cRemoteTimerConflicts RemoteConflicts;
+
+// cTimerConflict -------------------------------------------------
+
+cTimerConflict::cTimerConflict(time_t Time, const char *Conflict, const char *Text):
+		time(Time), text(Text) {
+	char* ids = NULL;
+	if (sscanf(Conflict, "%d|%d|%a[0-9#]", &id, &percent, &ids) == 3) {
+		char *p;
+
+		// number of IDs is one more than number of '#'
+		int count = 1;
+		for (p = ids; *p; ++p) {
+			if (*p == '#')
+				++count;
+		}
+
+		timerIds = (int*) malloc(sizeof(int) * (count + 1));
+		// convert IDs into numbers
+		p = ids;
+		for (int i = 0; i < count; ++i) {
+			timerIds[i] = strtol(p, &p, 10);
+			++p;
+		}
+		timerIds[count] = 0;
+
+		free(ids);
+	}
+	else {
+		id = 0;
+		percent = 0;
+		timerIds = NULL;
+	}
+}
+
+cTimerConflict::~cTimerConflict()
+{	free(timerIds); }
+
+// cTimerConflicts -------------------------------------------------
+cTimerConflicts::cTimerConflicts() {
+	needsUpdate = false;
+}
+
+void cTimerConflicts::AddConflicts(const char *Line) {
+	char *p = NULL;
+	const char *l = Line;
+	time_t time = (time_t) strtol(l, &p, 10);
+	while (p && p != l && *p == ':') {
+		l = ++p;
+		p = strchr(p, ':');
+		Add(new cTimerConflict(time, l, Line));
+		// multiple conflicts for same time: store Line only once
+		Line = NULL;
+	}
+}
+
+bool cTimerConflicts::HasConflict(int TimerId) const
+{
+	for (cTimerConflict *c = First(); c; c = Next(c)) {
+		if (c->Id() == TimerId)
+			return true;
+	}
+	return false;
+}
+
+// cLocalTimerConflicts -------------------------------------------------
+cLocalTimerConflicts::cLocalTimerConflicts() {
+	hasEpgsearch = true;
+	pluginEpgsearch = NULL;
+}
+
+void cLocalTimerConflicts::Update() {
+	Epgsearch_services_v1_1 epgsearch;
+	if (hasEpgsearch) {
+		if (!pluginEpgsearch) {
+			pluginEpgsearch = cPluginManager::CallFirstService("Epgsearch-services-v1.1", &epgsearch);
+			hasEpgsearch = pluginEpgsearch != NULL;
+		}
+		else
+			pluginEpgsearch->Service("Epgsearch-services-v1.1", &epgsearch);
+	}
+	if (hasEpgsearch) {
+		
+		needsUpdate = false;
+		Clear();
+		std::list<std::string> conflicts = epgsearch.handler->TimerConflictList();
+		for (std::list<std::string>::iterator it = conflicts.begin(); it != conflicts.end(); it++)
+			AddConflicts((*it).c_str());
+	}
+}
+
+// cRemoteTimerConflicts -------------------------------------------------
+cRemoteTimerConflicts::cRemoteTimerConflicts() {
+	cmd.command = "PLUG epgsearch LSCC\r\n";
+}
+
+void cRemoteTimerConflicts::Update() {
+	needsUpdate = false;
+	Clear();
+	if (!cSvdrp::GetInstance()->Offline())
+	{
+		cSvdrp::GetInstance()->Send(&cmd);
+		if (cmd.responseCode == 900) {
+			for (cLine *line = cmd.reply.First(); line; line = cmd.reply.Next(line))
+				AddConflicts(line->Text());
+		}
+	}
+}
diff --git a/conflict.h b/conflict.h
new file mode 100644
index 0000000..8462c5a
--- /dev/null
+++ b/conflict.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2008-2013 Frank Schmirler <vdr at schmirler.de>
+ *
+ * This file is part of VDR Plugin remotetimers.
+ *
+ * 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
+ * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ */
+
+#ifndef _REMOTETIMERS_CONFLICT__H
+#define _REMOTETIMERS_CONFLICT__H
+
+#include <vdr/tools.h>
+#include "svdrp.h"
+#include "include/epgsearch.h"
+
+class cTimerConflict: public cListObject {
+private:
+	time_t time;
+	int id;
+	int percent;
+	int* timerIds;
+	cString text;
+public:
+	time_t Time() const { return time; }
+	int Id() const { return id; }
+	int Percent() const { return percent; }
+	const int* With() const { return timerIds; }
+	// Raw string as received from epgsearch.
+	// In case of multiple conflicts at the same time, a string with all conflicts is returned with the first conflict.
+	// It is NULL for all further conflicts.
+	const char* Text() const { return text; }
+	cTimerConflict(time_t Time, const char *Conflict, const char *Text);
+	virtual ~cTimerConflict();
+};
+
+class cTimerConflicts: public cList<cTimerConflict> {
+protected:
+        bool needsUpdate;
+	void AddConflicts(const char *Line);
+public:
+	bool NeedsUpdate() const { return needsUpdate; }
+	void SetNeedsUpdate() { needsUpdate = true; }
+	virtual void Update() = 0;
+	bool HasConflict(int TimerId) const;
+	cTimerConflicts();
+};
+
+class cLocalTimerConflicts: public cTimerConflicts {
+private:
+	bool hasEpgsearch;
+	cPlugin* pluginEpgsearch;
+public:
+	virtual void Update();
+	cLocalTimerConflicts();
+};
+
+class cRemoteTimerConflicts: public cTimerConflicts {
+private:
+	SvdrpCommand_v1_0 cmd;
+public:
+	virtual void Update();
+	cRemoteTimerConflicts();
+};
+
+extern cLocalTimerConflicts LocalConflicts;
+extern cRemoteTimerConflicts RemoteConflicts;
+
+#endif //_REMOTETIMERS_CONFLICT__H
diff --git a/i18n.c b/i18n.c
deleted file mode 100644
index f2221ac..0000000
--- a/i18n.c
+++ /dev/null
@@ -1,2340 +0,0 @@
-/*
- * Copyright (C) 2008-2011 Frank Schmirler <vdr at schmirler.de>
- *
- * This file is part of VDR Plugin remotetimers.
- *
- * 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
- * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
- */
-
-#include "i18n.h"
-
-#if VDRVERSNUM < 10507
-const tI18nPhrase Phrases[] = {
-// START I18N - automatically generated by po2i18n.pl
-  { " tTpP",
-    " tTpP",
-    "",
-    " tTpP",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Abort moving recording",
-    "Aufzeichnung verschieben abbrechen",
-    "",
-    "Spostamento registrazione annullato",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Binding of %s/%s in \"What's on\" menus",
-    "Funktion von %s/%s in \"Was l�uft\"-Men�s",
-    "",
-    "Associazione %s/%s nel menu \"Adesso\"",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Button$Folder",
-    "Verzeichnis",
-    "",
-    "Cartella",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Button$Select",
-    "Ausw�hlen",
-    "",
-    "Seleziona",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Cancel",
-    "Abmelden",
-    "",
-    "Annulla",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Cut",
-    "Schneiden",
-    "",
-    "Taglia",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Defaults for new timers",
-    "Voreinstellungen f�r neue Timer",
-    "",
-    "Valori predefiniti per i nuovi timer",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Delete folder and all sub folders?",
-    "Verzeichnis und alle Unterverzeichnisse l�schen?",
-    "",
-    "Eliminare la cartella e tutte le sottocartelle?",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Delete folder?",
-    "Verzeichnis l�schen?",
-    "",
-    "Eliminare la cartella?",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Edit folder",
-    "Verzeichnis editieren",
-    "",
-    "Modifica cartella",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Edit recording",
-    "Aufzeichnung editieren",
-    "",
-    "Modifica registrazione",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Edit timers on remote VDR",
-    "Timer eines anderen VDR bearbeiten",
-    "",
-    "Modifica timer di VDR remoto",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Failed to move recording!",
-    "Fehler beim Verschieben der Aufzeichnung!",
-    "",
-    "Impossibile spostare la registrazione!",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Finished moving recording",
-    "Aufzeichnung verschoben",
-    "",
-    "Spostamento registrazione completato",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Folder name already exists!",
-    "Verzeichnisname existiert bereits!",
-    "",
-    "Nome cartella gi� esistente!",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Folder name must not contain '%c'!",
-    "Verzeichnisname darf kein '%c' enthalten!",
-    "",
-    "Il nome cartella non pu� contenere '%c'!",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Hide mainmenu entry",
-    "Hauptmen�eintrag verstecken",
-    "",
-    "Nascondi voce menu principale",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Instant recordings",
-    "Direktaufzeichnungen",
-    "",
-    "Registrazioni immediate",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Location",
-    "Aufnahmeort",
-    "",
-    "Posizione",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Lost SVDRP connection - please check remote timers",
-    "SVDRP-Verbindung verloren - bitte Timer auf Server pr�fen",
-    "",
-    "Persa connessione SVDRP - verifica i timer remoti",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Lost SVDRP connection - unable to start remote cutter",
-    "SVDRP-Verbindung verloren - kann Schnitt auf Server nicht starten",
-    "",
-    "Persa connessione SVDRP - impossibile avviare taglio remoto",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Map channels using",
-    "Kan�le zuordnen anhand",
-    "",
-    "Mappa canali usando",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Monitor update file",
-    "Update-Datei beobachten",
-    "",
-    "Controlla file update",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Mounted on subdirectory",
-    "Unterverzeichnis",
-    "",
-    "Montate nella sotto directory",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Move recording bandwidth limit (Mbit/s)",
-    "Bandbreite Aufzeichnung verschieben (Mbit/s)",
-    "",
-    "Limite banda spostamento registrazione (Mbit/s)",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Move to other filesystem in background?",
-    "Im Hintergrund auf anderes Dateisystem verschieben?",
-    "",
-    "Spostare verso un altro filesystem in sottofondo?",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Moving recording",
-    "Verschiebe Aufzeichnung",
-    "",
-    "Spostamento registrazione",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "New folder",
-    "Neues Verzeichnis",
-    "",
-    "Nuova cartella",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Pause recordings",
-    "Live-Signal anhalten",
-    "",
-    "Pausa registrazioni",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "RL",
-    "SL",
-    "",
-    "RL",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Recording not found on remote VDR - use local cutter",
-    "Aufzeichnung auf dem Server nicht gefunden - schneide lokal",
-    "",
-    "Registrazione non trovata su VDR remoto - usa taglio locale",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Release",
-    "Freigeben",
-    "",
-    "Rilascia",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Remote Timers",
-    "Server Timer",
-    "",
-    "Timer remoti",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Remote cutter already active or no marks defined",
-    "Keine Schnittmarken oder am Server l�uft ein Schneidevorgang",
-    "",
-    "Taglio remoto gi� attivo o nessun marcatore definito",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Remote editing process started",
-    "Serverseitiger Schnitt gestartet",
-    "",
-    "Processo modifica remoto avviato",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Remote recording failed. Start local recording?",
-    "Serverseitige Aufzeichnung fehlgeschlagen. Lokal aufnehmen?",
-    "",
-    "Registrazione remota fallita. Avviare registrazione locale?",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Remote recordings",
-    "Server Aufzeichnungen",
-    "",
-    "Registrazioni remote",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Remote timers not available",
-    "Timer des Servers nicht verf�gbar",
-    "",
-    "Timer remoti non disponibili",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Replace mainmenu \"%s\"",
-    "Hauptmen� \"%s\" ersetzen",
-    "",
-    "Sostituisci \"%s\" menu principale",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Select folder",
-    "Verzeichnis w�hlen",
-    "",
-    "Seleziona cartella",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Server IP",
-    "Server IP",
-    "",
-    "IP server",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Server port",
-    "Server Port",
-    "",
-    "Porta server",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Settings for menu",
-    "Einstellungen f�r das Men�",
-    "",
-    "Impostazioni menu",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Show progress bar in menu \"%s\"",
-    "Fortschrittsanzeige im Men� \"%s\"",
-    "",
-    "Mostra barra avanzamento nel menu \"%s\"",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Sub folder",
-    "Unterverzeichnis",
-    "",
-    "Sottocartella",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Timer already defined",
-    "Timer existiert bereits",
-    "",
-    "Timer gi� definito",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Timer is recording - can't move it to server",
-    "Timer nimmt gerade auf - auf Server verschieben nicht m�glich",
-    "",
-    "Timer in registrazione - impossibile spostarlo sul server",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Timer is recording - please deactivate it first",
-    "Timer nimmt gerade auf - bitte erst deaktivieren",
-    "",
-    "Timer in registrazione - disattivarlo prima",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Timers are being edited remotely - please try again",
-    "Timerliste auf Server gesperrt - bitte nochmal",
-    "",
-    "I timer sono stati modificati da remoto - prova ancora",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Timers modified remotely - please check remote timers",
-    "Timer auf Server ver�ndert - bitte pr�fen",
-    "",
-    "Timer modificati da remoto - verifica i timer remoti",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Unable to change priority/lifetime",
-    "Fehler beim �ndern der Priorit�t/Lebensdauer",
-    "",
-    "Impossibile aggiornare priorit�/scadenza",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Unable to rename recording",
-    "Fehler beim Umbenennen der Aufzeichnung",
-    "",
-    "Impossibile rinominare registrazione",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Unable to update user ID",
-    "Fehler beim �ndern der Benutzer-ID",
-    "",
-    "Impossibile aggiornare ID utente",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Unexpected error - please check remote timers",
-    "Unerwarteter Fehler - bitte Timer auf Server pr�fen",
-    "",
-    "Errore inatteso - verifica i timer remoti",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Unexpected error - unable to start remote cutter",
-    "Unerwarteter Fehler - kann Schnitt auf Server nicht starten",
-    "",
-    "Errore inatteso - impossibile avviare taglio remoto",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "Updated remote timers list",
-    "Timerliste wurde neu geladen",
-    "",
-    "Elenco timer remoti aggiornati",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "User",
-    "Benutzer",
-    "",
-    "Utente",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "User ID",
-    "Benutzer-ID",
-    "",
-    "ID utente",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "User ID filter in menu \"%s\"",
-    "Benutzer-Filter im Men� \"%s\"",
-    "",
-    "Filtra per ID utente nel menu \"%s\"",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "channel ID",
-    "Kanal-ID",
-    "",
-    "ID canale",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "channel number",
-    "Kanalnummer",
-    "",
-    "Numero canale",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "from svdrpservice",
-    "aus svdrpservice",
-    "",
-    "da svdrpservice",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "local",
-    "lokal",
-    "",
-    "locale",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "remote",
-    "Server",
-    "",
-    "remoto",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-  { "unlimited",
-    "unbegrenzt",
-    "",
-    "illimitato",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-    "",
-#if VDRVERSNUM >= 10302
-    "",
-#endif
-#if VDRVERSNUM >= 10307
-    "",
-#endif
-#if VDRVERSNUM >= 10313
-    "",
-#endif
-#if VDRVERSNUM >= 10316
-    "",
-#endif
-#if VDRVERSNUM >= 10342
-    "",
-#endif
-#if VDRVERSNUM >= 10502
-    "",
-#endif
-  },
-// END I18N - automatically generated by po2i18n.pl
-{	NULL }
-};
-#endif
diff --git a/i18n.h b/i18n.h
index 82bce7e..9d46010 100644
--- a/i18n.h
+++ b/i18n.h
@@ -25,14 +25,8 @@
 #include <vdr/config.h>
 #include <vdr/i18n.h>
 
-#if VDRVERSNUM < 10507
-#define trNOOP(s) (s)
-#define trREMOTETIMERS(s) tr(s)
-extern const tI18nPhrase Phrases[];
-#else
 #undef tr
 #define tr(s) I18nTranslate(s)
 #define trREMOTETIMERS(s) I18nTranslate(s, "vdr-" PLUGIN_NAME_I18N)
-#endif
 
 #endif //_REMOTETIMERS_I18N__H
diff --git a/include/epgsearch.h b/include/epgsearch.h
new file mode 100644
index 0000000..2669da4
--- /dev/null
+++ b/include/epgsearch.h
@@ -0,0 +1,202 @@
+/*                                                                  -*- c++ -*-
+Copyright (C) 2004-2013 Christian Wieninger
+
+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
+Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+
+The author can be reached at cwieninger at gmx.de
+
+The project's page is at http://winni.vdr-developer.org/epgsearch
+*/
+
+#ifndef EPGSEARCHSERVICES_INC
+#define EPGSEARCHSERVICES_INC
+
+#include <string>
+#include <list>
+#include <memory>
+#include <set>
+#include <vdr/osdbase.h>
+
+// Data structure for service "Epgsearch-search-v1.0"
+struct Epgsearch_search_v1_0
+{
+// in
+      char* query;               // search term
+      int mode;                  // search mode (0=phrase, 1=and, 2=or, 3=regular expression)
+      int channelNr;             // channel number to search in (0=any)
+      bool useTitle;             // search in title
+      bool useSubTitle;          // search in subtitle
+      bool useDescription;       // search in description
+// out
+      cOsdMenu* pResultMenu;   // pointer to the menu of results
+};
+
+// Data structure for service "Epgsearch-exttimeredit-v1.0"
+struct Epgsearch_exttimeredit_v1_0
+{
+// in
+      cTimer* timer;             // pointer to the timer to edit
+      bool bNew;                 // flag that indicates, if this is a new timer or an existing one
+      const cEvent* event;             // pointer to the event corresponding to this timer (may be NULL)
+// out
+      cOsdMenu* pTimerMenu;   // pointer to the menu of results
+};
+
+// Data structure for service "Epgsearch-enablesearchtimers-v1.0"
+struct Epgsearch_enablesearchtimers_v1_0
+{
+// in
+      bool enable;           // enable search timer thread?
+};
+
+// Data structure for service "Epgsearch-updatesearchtimers-v1.0"
+struct Epgsearch_updatesearchtimers_v1_0
+{
+// in
+      bool showMessage;           // inform via osd when finished?
+};
+
+// Data structure for service "Epgsearch-osdmessage-v1.0"
+struct Epgsearch_osdmessage_v1_0
+{
+// in
+      char* message;             // the message to display
+      eMessageType type;
+};
+
+// Data structure for service "EpgsearchMenu-v1.0"
+struct EpgSearchMenu_v1_0
+{
+// in
+// out
+      cOsdMenu* Menu;   // pointer to the menu
+};
+
+// Data structure for service "Epgsearch-lastconflictinfo-v1.0"
+struct Epgsearch_lastconflictinfo_v1_0
+{
+// in
+// out
+      time_t nextConflict;       // next conflict date, 0 if none
+      int relevantConflicts;     // number of relevant conflicts
+      int totalConflicts;        // total number of conflicts
+};
+
+// Data structure for service "Epgsearch-searchresults-v1.0"
+struct Epgsearch_searchresults_v1_0
+{
+// in
+      char* query;               // search term
+      int mode;                  // search mode (0=phrase, 1=and, 2=or, 3=regular expression)
+      int channelNr;             // channel number to search in (0=any)
+      bool useTitle;             // search in title
+      bool useSubTitle;          // search in subtitle
+      bool useDescription;       // search in description
+// out
+
+      class cServiceSearchResult : public cListObject
+      {
+        public:
+         const cEvent* event;
+         cServiceSearchResult(const cEvent* Event) : event(Event) {}
+      };
+
+      cList<cServiceSearchResult>* pResultList;   // pointer to the results
+};
+
+// Data structure for service "Epgsearch-switchtimer-v1.0"
+struct Epgsearch_switchtimer_v1_0
+{
+// in
+      const cEvent* event;
+      int mode;                  // mode (0=query existence, 1=add/modify, 2=delete)
+// in/out
+      int switchMinsBefore;
+      int announceOnly;
+// out
+      bool success;              // result
+};
+
+// Data structures for service "Epgsearch-services-v1.0"
+class cServiceHandler
+{
+  public:
+   virtual std::list<std::string> SearchTimerList() = 0;
+   // returns a list of search timer entries in the same format as used in epgsearch.conf
+   virtual int AddSearchTimer(const std::string&) = 0;
+   // adds a new search timer and returns its ID (-1 on error)
+   virtual bool ModSearchTimer(const std::string&) = 0;
+   // edits an existing search timer and returns success
+   virtual bool DelSearchTimer(int) = 0;
+   // deletes search timer with given ID and returns success
+   virtual std::list<std::string> QuerySearchTimer(int) = 0;
+   // returns the search result of the searchtimer with given ID in the same format as used in SVDRP command 'QRYS' (->MANUAL)
+   virtual std::list<std::string> QuerySearch(std::string) = 0;
+   // returns the search result of the searchtimer with given settings in the same format as used in SVDRP command 'QRYS' (->MANUAL)
+   virtual std::list<std::string> ExtEPGInfoList() = 0;
+   // returns a list of extended EPG categories in the same format as used in epgsearchcats.conf
+   virtual std::list<std::string> ChanGrpList() = 0;
+   // returns a list of channel groups maintained by epgsearch
+   virtual std::list<std::string> BlackList() = 0;
+   // returns a list of blacklists in the same format as used in epgsearchblacklists.conf
+   virtual std::set<std::string> DirectoryList() = 0;
+   // List of all recording directories used in recordings, timers, search timers or in epgsearchdirs.conf
+   virtual ~cServiceHandler() {}
+   // Read a setup value
+   virtual std::string ReadSetupValue(const std::string& entry) = 0;
+   // Write a setup value
+   virtual bool WriteSetupValue(const std::string& entry, const std::string& value) = 0;
+};
+
+struct Epgsearch_services_v1_0
+{
+// in/out
+      std::auto_ptr<cServiceHandler> handler;
+};
+
+// Data structures for service "Epgsearch-services-v1.1"
+class cServiceHandler_v1_1 : public cServiceHandler
+{
+  public:
+   // Get timer conflicts
+   virtual std::list<std::string> TimerConflictList(bool relOnly=false) = 0;
+   // Check if a conflict check is advised
+   virtual bool IsConflictCheckAdvised() = 0;
+};
+
+struct Epgsearch_services_v1_1
+{
+// in/out
+      std::auto_ptr<cServiceHandler_v1_1> handler;
+};
+
+// Data structures for service "Epgsearch-services-v1.2"
+class cServiceHandler_v1_2 : public cServiceHandler_v1_1
+{
+  public:
+  // List of all recording directories used in recordings, timers (and optionally search timers or in epgsearchdirs.conf)
+  virtual std::set<std::string> ShortDirectoryList() = 0;
+  // Evaluate an expression against an event
+  virtual std::string Evaluate(const std::string& expr, const cEvent* event) = 0;
+};
+
+struct Epgsearch_services_v1_2
+{
+// in/out
+      std::auto_ptr<cServiceHandler_v1_2> handler;
+};
+
+#endif
diff --git a/menu.c b/menu.c
index a964d65..2b5cd3c 100644
--- a/menu.c
+++ b/menu.c
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 2008-2011 Frank Schmirler <vdr at schmirler.de>
+ * Copyright (C) 2008-2013 Frank Schmirler <vdr at schmirler.de>
  *
  * Major parts copied from VDR's menu.c
- * $Id: menu.c 2.54 2012/05/12 13:08:23 kls Exp $
+ * $Id: menu.c 2.82.1.2 2013/04/27 10:32:28 kls Exp $
  * Copyright (C) 2000, 2003, 2006, 2008 Klaus Schmidinger
  *
  * This file is part of VDR Plugin remotetimers.
@@ -27,6 +27,7 @@
 #include "setup.h"
 #include "moverec.h"
 #include "i18n.h"
+#include "conflict.h"
 #include <vdr/menu.h>
 #include "menuitems.h"
 //#include <ctype.h>
@@ -73,11 +74,7 @@ namespace PluginRemoteTimers {
 #define MAXCHNAMWIDTH      16
 
 #define CHNUMWIDTH  (numdigits(Channels.MaxNumber()) + 1)
-#if VDRVERSNUM < 10728
-#define CHNAMWIDTH  7
-#else
 #define CHNAMWIDTH  (min(MAXCHNAMWIDTH, Channels.MaxShortChannelNameLength() + 1))
-#endif
 
 #define AUX_STARTTAG "<remotetimers>"
 #define AUX_ENDTAG "</remotetimers>"
@@ -119,14 +116,14 @@ cString UpdateUser(const char *s, int User) {
       return cString::sprintf("%.*s" AUX_STARTTAG "%s" AUX_ENDTAG "%.*s", lenPrefix, s, *cMenuEditUserItem::ToString(User), lenPostfix, end);
 }
 
-cTimer* GetBestMatch(const cEvent *Event, int UserMask, int *Match, int *Type, bool *Remote)
+cTimer* GetBestMatch(const cEvent *Event, int UserMask, eTimerMatch *Match, int *Type, bool *Remote)
 {
 	cTimer *localTimer = NULL, *remoteTimer = NULL;
-	int localMatch = tmNone, remoteMatch = tmNone;
+	eTimerMatch localMatch = tmNone, remoteMatch = tmNone;
 	int localUser = 0, remoteUser = 0;
 
 	for (cTimer *t = Timers.First(); t; t = Timers.Next(t)) {
-		int tm = t->Matches(Event);
+		eTimerMatch tm = t->Matches(Event);
 		if (tm > localMatch) {
 			int user = ParseUser(t->Aux());
 			if (UserMask == 0 || user == 0 || (user & UserMask)) {
@@ -139,7 +136,7 @@ cTimer* GetBestMatch(const cEvent *Event, int UserMask, int *Match, int *Type, b
 		}
 	}
 	for (cRemoteTimer *t = RemoteTimers.First(); t; t = RemoteTimers.Next(t)) {
-		int tm = t->Matches(Event);
+		eTimerMatch tm = t->Matches(Event);
 		if (tm > remoteMatch) {
 			int user = ParseUser(t->Aux());
 			if (UserMask == 0 || user == 0 || (user & UserMask)) {
@@ -171,24 +168,14 @@ private:
   static time_t lastDiskSpaceCheck;
   static int lastFreeMB;
   static cString freeDiskSpaceString;
-#if VDRVERSNUM >= 10515
   static cString lastPath;
   static int VideoDiskSpace(const char *Dir, int *FreeMB);
   static int DeletedFileSizeMB(const char *Dir);
-#endif
-#if VDRVERSNUM >= 10728
   static double MBperMinute(const char* Dir);
-#endif
 public:
-#if VDRVERSNUM >= 10515
   static bool HasChanged(const char *SubDir, bool ForceCheck = false);
-#else
-  static bool HasChanged(bool ForceCheck = false);
-#endif
   static const char *FreeDiskSpaceString() { return freeDiskSpaceString; }
-#if VDRVERSNUM >= 10728
   static cString FreeDiskSpaceString(const cRecording* recording);
-#endif
   };
 
 time_t cFreeDiskSpace::lastDiskSpaceCheck = 0;
@@ -197,7 +184,6 @@ cString cFreeDiskSpace::freeDiskSpaceString;
 
 cFreeDiskSpace FreeDiskSpace;
 
-#if VDRVERSNUM >= 10515
 cString cFreeDiskSpace::lastPath("/");
 
 bool cFreeDiskSpace::HasChanged(const char *SubDir, bool ForceCheck)
@@ -211,33 +197,19 @@ bool cFreeDiskSpace::HasChanged(const char *SubDir, bool ForceCheck)
      lastPath = path;
      if (IsOnVideoDirectoryFileSystem(path)) {
         Percent = ::VideoDiskSpace(&FreeMB);
-#if VDRVERSNUM >= 10728
         MBperMinute = Recordings.MBperMinute();
-#endif
      }
      else {
         Percent = VideoDiskSpace(path, &FreeMB);
-#if VDRVERSNUM >= 10728
         MBperMinute = cFreeDiskSpace::MBperMinute(path);
-#endif
      }
 
-#else
-
-bool cFreeDiskSpace::HasChanged(bool ForceCheck)
-{
-  if (ForceCheck || time(NULL) - lastDiskSpaceCheck > DISKSPACECHEK) {
-     int FreeMB;
-     int Percent = VideoDiskSpace(&FreeMB);
-#endif
      lastDiskSpaceCheck = time(NULL);
      if (ForceCheck || FreeMB != lastFreeMB) {
         int Minutes;
-#if VDRVERSNUM >= 10728
         if (MBperMinute > 0)
            Minutes = int(double(FreeMB) / MBperMinute);
         else
-#endif
            Minutes = int(double(FreeMB) / MB_PER_MINUTE);
         int Hours = Minutes / 60;
         Minutes %= 60;
@@ -249,7 +221,6 @@ bool cFreeDiskSpace::HasChanged(bool ForceCheck)
   return false;
 }
 
-#if VDRVERSNUM >= 10515
 int cFreeDiskSpace::VideoDiskSpace(const char *Dir, int *FreeMB)
 {
   int used = 0;
@@ -275,8 +246,7 @@ int cFreeDiskSpace::DeletedFileSizeMB(const char *Dir)
       }
   return size;
 }
-#endif
-#if VDRVERSNUM >= 10728
+
 double cFreeDiskSpace::MBperMinute(const char* Dir)
 {
   int size = 0;
@@ -314,433 +284,6 @@ cString cFreeDiskSpace::FreeDiskSpaceString(const cRecording* recording)
      freeString = "";
   return freeString;
 }
-#endif
-
-#if APIVERSNUM < 10712
-
-// --- cNestedItem -----------------------------------------------------------
-
-// copy of VDR's cNestedItem / cNestedItemList
-
-cNestedItem::cNestedItem(const char *Text, bool WithSubItems)
-{
-  text = strdup(Text ? Text : "");
-  subItems = WithSubItems ? new cList<cNestedItem> : NULL;
-}
-
-cNestedItem::~cNestedItem()
-{
-  delete subItems;
-  free(text);
-}
-
-int cNestedItem::Compare(const cListObject &ListObject) const
-{
-  return strcasecmp(text, ((cNestedItem *)&ListObject)->text);
-}
-
-void cNestedItem::AddSubItem(cNestedItem *Item)
-{
-  if (!subItems)
-     subItems = new cList<cNestedItem>;
-  if (Item)
-     subItems->Add(Item);
-}
-
-void cNestedItem::SetText(const char *Text)
-{
-  free(text);
-  text = strdup(Text ? Text : "");
-}
-
-void cNestedItem::SetSubItems(bool On)
-{
-  if (On && !subItems)
-     subItems = new cList<cNestedItem>;
-  else if (!On && subItems) {
-     delete subItems;
-     subItems = NULL;
-     }
-}
-
-// --- cNestedItemList -------------------------------------------------------
-
-cNestedItemList::cNestedItemList(void)
-{
-  fileName = NULL;
-}
-
-cNestedItemList::~cNestedItemList()
-{
-  free(fileName);
-}
-
-bool cNestedItemList::Parse(FILE *f, cList<cNestedItem> *List, int &Line)
-{
-  char *s;
-  cReadLine ReadLine;
-  while ((s = ReadLine.Read(f)) != NULL) {
-        Line++;
-        char *p = strchr(s, '#');
-        if (p)
-           *p = 0;
-        s = skipspace(stripspace(s));
-        if (!isempty(s)) {
-           p = s + strlen(s) - 1;
-           if (*p == '{') {
-              *p = 0;
-              stripspace(s);
-              cNestedItem *Item = new cNestedItem(s, true);
-              List->Add(Item);
-              if (!Parse(f, Item->SubItems(), Line))
-                 return false;
-              }
-           else if (*s == '}')
-              break;
-           else
-              List->Add(new cNestedItem(s));
-           }
-        }
-  return true;
-}
-
-bool cNestedItemList::Write(FILE *f, cList<cNestedItem> *List, int Indent)
-{
-  for (cNestedItem *Item = List->First(); Item; Item = List->Next(Item)) {
-      if (Item->SubItems()) {
-         fprintf(f, "%*s%s {\n", Indent, "", Item->Text());
-         Write(f, Item->SubItems(), Indent + 2);
-         fprintf(f, "%*s}\n", Indent + 2, "");
-         }
-      else
-         fprintf(f, "%*s%s\n", Indent, "", Item->Text());
-      }
-  return true;
-}
-
-void cNestedItemList::Clear(void)
-{
-  free(fileName);
-  fileName = NULL;
-  cList<cNestedItem>::Clear();
-}
-
-bool cNestedItemList::Load(const char *FileName)
-{
-  cList<cNestedItem>::Clear();
-  if (FileName) {
-     free(fileName);
-     fileName = strdup(FileName);
-     }
-  bool result = false;
-  if (fileName && access(fileName, F_OK) == 0) {
-     isyslog("loading %s", fileName);
-     FILE *f = fopen(fileName, "r");
-     if (f) {
-        int Line = 0;
-        result = Parse(f, this, Line);
-        fclose(f);
-        }
-     else {
-        LOG_ERROR_STR(fileName);
-        result = false;
-        }
-     }
-  return result;
-}
-
-bool cNestedItemList::Save(void)
-{
-  bool result = true;
-  cSafeFile f(fileName);
-  if (f.Open()) {
-     result = Write(f, this);
-     if (!f.Close())
-        result = false;
-     }
-  else
-     result = false;
-  return result;
-}
-
-cNestedItemList Folders;
-
-// --- cMenuFolderItem -------------------------------------------------------
-
-class cMenuFolderItem : public cOsdItem {
-private:
-  cNestedItem *folder;
-public:
-  cMenuFolderItem(cNestedItem *Folder);
-  cNestedItem *Folder(void) { return folder; }
-  };
-
-cMenuFolderItem::cMenuFolderItem(cNestedItem *Folder)
-:cOsdItem(Folder->Text())
-{
-  folder = Folder;
-  if (folder->SubItems())
-     SetText(cString::sprintf("%s...", folder->Text()));
-}
-
-// --- cMenuEditFolder -------------------------------------------------------
-
-class cMenuEditFolder : public cOsdMenu {
-private:
-  cList<cNestedItem> *list;
-  cNestedItem *folder;
-  char name[PATH_MAX];
-  int subFolder;
-  eOSState Confirm(void);
-public:
-  cMenuEditFolder(const char *Dir, cList<cNestedItem> *List, cNestedItem *Folder = NULL);
-  cString GetFolder(void);
-  virtual eOSState ProcessKey(eKeys Key);
-  };
-
-cMenuEditFolder::cMenuEditFolder(const char *Dir, cList<cNestedItem> *List, cNestedItem *Folder)
-:cOsdMenu(Folder ? trREMOTETIMERS("Edit folder") : trREMOTETIMERS("New folder"), 12)
-{
-  list = List;
-  folder = Folder;
-  if (folder) {
-     strn0cpy(name, folder->Text(), sizeof(name));
-     subFolder = folder->SubItems() != NULL;
-     }
-  else {
-     *name = 0;
-     subFolder = 0;
-     cRemote::Put(kRight, true); // go right into string editing mode
-     }
-  if (!isempty(Dir)) {
-     cOsdItem *DirItem = new cOsdItem(Dir);
-     DirItem->SetSelectable(false);
-     Add(DirItem);
-     }
-  Add(new cMenuEditStrItem( tr("Name"), name, sizeof(name), tr(FileNameChars)));
-  Add(new cMenuEditBoolItem(trREMOTETIMERS("Sub folder"), &subFolder));
-}
-
-cString cMenuEditFolder::GetFolder(void)
-{
-  return folder ? folder->Text() : "";
-}
-
-eOSState cMenuEditFolder::Confirm(void)
-{
-  if (!folder || strcmp(folder->Text(), name) != 0) {
-     // each name may occur only once in a folder list
-     for (cNestedItem *Folder = list->First(); Folder; Folder = list->Next(Folder)) {
-         if (strcmp(Folder->Text(), name) == 0) {
-            Skins.Message(mtError, trREMOTETIMERS("Folder name already exists!"));
-            return osContinue;
-            }
-         }
-     char *p = strpbrk(name, "\\{}#~"); // FOLDERDELIMCHAR
-     if (p) {
-        Skins.Message(mtError, cString::sprintf(trREMOTETIMERS("Folder name must not contain '%c'!"), *p));
-        return osContinue;
-        }
-     }
-  if (folder) {
-     folder->SetText(name);
-     folder->SetSubItems(subFolder);
-     }
-  else
-     list->Add(folder = new cNestedItem(name, subFolder));
-  return osEnd;
-}
-
-eOSState cMenuEditFolder::ProcessKey(eKeys Key)
-{
-  eOSState state = cOsdMenu::ProcessKey(Key);
-
-  if (state == osUnknown) {
-     switch (Key) {
-       case kOk:     return Confirm();
-       case kRed:
-       case kGreen:
-       case kYellow:
-       case kBlue:   return osContinue;
-       default: break;
-       }
-     }
-  return state;
-}
-
-// --- cMenuFolder -----------------------------------------------------------
-
-cMenuFolder::cMenuFolder(const char *Title, cNestedItemList *NestedItemList, const char *Path)
-:cOsdMenu(Title)
-{
-  // cOsdMenu::Title() and cOsdMenu::SubMenu() missing in < 10712
-  title = Title;
-  subMenuFolder = NULL;
-  subMenuEditFolder = NULL;
-
-  list = nestedItemList = NestedItemList;
-  firstFolder = NULL;
-  editing = false;
-  Set();
-  SetHelpKeys();
-  DescendPath(Path);
-}
-
-cMenuFolder::cMenuFolder(const char *Title, cList<cNestedItem> *List, cNestedItemList *NestedItemList, const char *Dir, const char *Path)
-:cOsdMenu(Title)
-{
-  // cOsdMenu::Title() and cOsdMenu::SubMenu() missing in < 10712
-  title = Title;
-  subMenuFolder = NULL;
-  subMenuEditFolder = NULL;
-
-  list = List;
-  nestedItemList = NestedItemList;
-  dir = Dir;
-  firstFolder = NULL;
-  editing = false;
-  Set();
-  SetHelpKeys();
-  DescendPath(Path);
-}
-
-void cMenuFolder::SetHelpKeys(void)
-{
-  SetHelp(firstFolder ? trREMOTETIMERS("Button$Select") : NULL, tr("Button$New"), firstFolder ? tr("Button$Delete") : NULL, firstFolder ? tr("Button$Edit") : NULL);
-}
-
-void cMenuFolder::Set(const char *CurrentFolder)
-{
-  firstFolder = NULL;
-  Clear();
-  if (!isempty(dir)) {
-     cOsdItem *DirItem = new cOsdItem(dir);
-     DirItem->SetSelectable(false);
-     Add(DirItem);
-     }
-  list->Sort();
-  for (cNestedItem *Folder = list->First(); Folder; Folder = list->Next(Folder)) {
-      cOsdItem *FolderItem = new cMenuFolderItem(Folder);
-      Add(FolderItem, CurrentFolder ? strcmp(Folder->Text(), CurrentFolder) == 0 : false);
-      if (!firstFolder)
-         firstFolder = FolderItem;
-      }
-}
-
-void cMenuFolder::DescendPath(const char *Path)
-{
-  if (Path) {
-     const char *p = strchr(Path, FOLDERDELIMCHAR);
-     if (p) {
-        for (cMenuFolderItem *Folder = (cMenuFolderItem *)firstFolder; Folder; Folder = (cMenuFolderItem *)Next(Folder)) {
-            if (strncmp(Folder->Folder()->Text(), Path, p - Path) == 0) {
-               SetCurrent(Folder);
-               if (Folder->Folder()->SubItems())
-                  AddSubMenu(subMenuFolder = new cMenuFolder(title, Folder->Folder()->SubItems(), nestedItemList, !isempty(dir) ? *cString::sprintf("%s%c%s", *dir, FOLDERDELIMCHAR, Folder->Folder()->Text()) : Folder->Folder()->Text(), p + 1));
-               break;
-               }
-            }
-        }
-    }
-}
-
-eOSState cMenuFolder::Select(void)
-{
-  if (firstFolder) {
-     cMenuFolderItem *Folder = (cMenuFolderItem *)Get(Current());
-     if (Folder) {
-        if (Folder->Folder()->SubItems())
-           return AddSubMenu(subMenuFolder = new cMenuFolder(title, Folder->Folder()->SubItems(), nestedItemList, !isempty(dir) ? *cString::sprintf("%s%c%s", *dir, FOLDERDELIMCHAR, Folder->Folder()->Text()) : Folder->Folder()->Text()));
-        else
-           return osEnd;
-        }
-     }
-  return osContinue;
-}
-
-eOSState cMenuFolder::New(void)
-{
-  editing = true;
-  return AddSubMenu(subMenuEditFolder = new cMenuEditFolder(dir, list));
-}
-
-eOSState cMenuFolder::Delete(void)
-{
-  if (!HasSubMenu() && firstFolder) {
-     cMenuFolderItem *Folder = (cMenuFolderItem *)Get(Current());
-     if (Folder && Interface->Confirm(Folder->Folder()->SubItems() ? trREMOTETIMERS("Delete folder and all sub folders?") : trREMOTETIMERS("Delete folder?"))) {
-        list->Del(Folder->Folder());
-        Del(Folder->Index());
-        firstFolder = Get(isempty(dir) ? 0 : 1);
-        Display();
-        SetHelpKeys();
-        nestedItemList->Save();
-        }
-     }
-  return osContinue;
-}
-
-eOSState cMenuFolder::Edit(void)
-{
-  if (!HasSubMenu() && firstFolder) {
-     cMenuFolderItem *Folder = (cMenuFolderItem *)Get(Current());
-     if (Folder) {
-        editing = true;
-        return AddSubMenu(subMenuEditFolder = new cMenuEditFolder(dir, list, Folder->Folder()));
-        }
-     }
-  return osContinue;
-}
-
-eOSState cMenuFolder::SetFolder(void)
-{
-  cMenuEditFolder *mef = subMenuEditFolder;
-  if (mef) {
-     Set(mef->GetFolder());
-     SetHelpKeys();
-     Display();
-     nestedItemList->Save();
-     subMenuEditFolder = NULL;
-     }
-  return CloseSubMenu();
-}
-
-cString cMenuFolder::GetFolder(void)
-{
-  if (firstFolder) {
-     cMenuFolderItem *Folder = (cMenuFolderItem *)Get(Current());
-     if (Folder) {
-        cMenuFolder *mf = subMenuFolder;
-        if (mf)
-           return cString::sprintf("%s%c%s", Folder->Folder()->Text(), FOLDERDELIMCHAR, *mf->GetFolder());
-        return Folder->Folder()->Text();
-        }
-     }
-  return "";
-}
-
-eOSState cMenuFolder::ProcessKey(eKeys Key)
-{
-  if (!HasSubMenu())
-     editing = false;
-  eOSState state = cOsdMenu::ProcessKey(Key);
-
-  if (state == osUnknown) {
-     switch (Key) {
-       case kOk:
-       case kRed:    return Select();
-       case kGreen:  return New();
-       case kYellow: return Delete();
-       case kBlue:   return Edit();
-       default:      state = osContinue;
-       }
-     }
-  else if (state == osEnd && HasSubMenu() && editing)
-     state = SetFolder();
-  return state;
-}
-
-#endif
 
 // --- cMenuEditRemoteTimer --------------------------------------------------------
 class cMenuEditRemoteTimer : public cMenuEditTimer {
@@ -758,13 +301,6 @@ private:
   int tmpRemote;
   int user;
   int tmpUser;
-#if APIVERSNUM < 10712
-  cMenuFolder *subMenuFolder;
-  char name[MaxFileName];
-  cMenuEditStrItem *file;
-  eOSState SetFolder(void);
-  void SetHelpKeys(void);
-#endif
   eOSState CheckState(eRemoteTimersState State);
 public:
 /*
@@ -778,22 +314,42 @@ public:
 cMenuEditRemoteTimer::cMenuEditRemoteTimer(cTimer *Timer, bool Remote, bool New, cMenuTimerItem **TimerItem)
 :cMenuEditTimer(Timer, New), timer(Timer), timerItem(TimerItem)
 {
+  SetCols(15, 4, 12);
   remote = tmpRemote = Remote;
   user = tmpUser = New ? MASK_FROM_SETUP(RemoteTimersSetup.defaultUser) : cMenuTimerItem::ParseUser(timer);
-#if APIVERSNUM < 10712
-  subMenuFolder = NULL;
-  file = NULL;
-  strn0cpy(name, Timer->File(), sizeof(name));
-  SetHelpKeys();
-  // replace "File" edit by our own implementation
-  Add(file = new cMenuEditStrItem( tr("File"), name, sizeof(name), tr(FileNameChars)), Get(8));
-  Del(8);
-#endif
   cOsdItem *item = new cMenuEditBoolItem(trREMOTETIMERS("Location"), &tmpRemote, trREMOTETIMERS("local"), trREMOTETIMERS("remote"));
   if (cSvdrp::GetInstance()->Offline())
       item->SetSelectable(false);
   Add(item, false, First());
   Add(new cMenuEditUserItem(trREMOTETIMERS("User ID"), &tmpUser), false, Get(8));
+
+  if (!New) {
+     cTimerConflicts *conflicts = Remote ? (cTimerConflicts*) &RemoteConflicts : (cTimerConflicts*) &LocalConflicts;
+     int timerId = Remote ? ((cRemoteTimer *) Timer)->Id() : Timer->Index() + 1;
+     for (cTimerConflict *c = conflicts->First(); c; c = conflicts->Next(c)) {
+         if (timerId == c->Id()) {
+            Add(new cOsdItem(cString::sprintf(trREMOTETIMERS("%.10s\tConflict (Recording %d%%)"),
+			*DayDateTime(c->Time()),
+			 c->Percent()), osUnknown, false));
+            for (const int* with = c->With(); with && *with; ++with) {
+                if (*with == timerId)
+                   continue;
+                const cTimer *t = Remote ? RemoteTimers.GetTimer(*with) : Timers.Get(*with - 1);
+                if (t) {
+                   Add(new cOsdItem(cString::sprintf("%02d:%02d %02d:%02d %2d\t%d\t%s\t%s",
+				t->Start() / 100,
+				t->Start() % 100,
+				t->Stop() / 100,
+				t->Stop() % 100,
+				t->Priority(),
+				t->Channel()->Number(),
+				t->Channel()->ShortName(true),
+				t->File())));
+                }
+            }
+         }
+     }
+  }
 }
 
 eOSState cMenuEditRemoteTimer::CheckState(eRemoteTimersState State)
@@ -805,53 +361,24 @@ eOSState cMenuEditRemoteTimer::CheckState(eRemoteTimersState State)
   return osBack;
 }
 
-#if APIVERSNUM < 10712
-
-void cMenuEditRemoteTimer::SetHelpKeys(void)
-{
-  SetHelp(trREMOTETIMERS("Button$Folder"));
-}
-
-eOSState cMenuEditRemoteTimer::SetFolder(void)
-{
-  cMenuFolder *mf = subMenuFolder;
-  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();
-     subMenuFolder = NULL;
-     }
-  return CloseSubMenu();
-}
-
-#endif
-
 eOSState cMenuEditRemoteTimer::ProcessKey(eKeys Key)
 {
   int TimerNumber = Timers.Count();
   eOSState state = cMenuEditTimer::ProcessKey(Key);
   if (state == osBack && Key == kOk) {
      // changes have been confirmed
-#if APIVERSNUM < 10712
-     timer->SetFile(name);
-#endif
      if (user != tmpUser)
         cMenuTimerItem::UpdateUser(*timer, tmpUser);
      if (TimerNumber == Timers.Count()) {
         // editing existing timer (remote timers are also added to Timers, first)
         if (remote == tmpRemote) {
            // timer was not moved
-           if (tmpRemote)
+           if (tmpRemote) {
               state = CheckState(RemoteTimers.Modify((cRemoteTimer*) timer));
+              RemoteConflicts.SetNeedsUpdate();
+              }
+           else
+              LocalConflicts.SetNeedsUpdate();
            }
         else if (tmpRemote) {
            // move local to remote
@@ -865,6 +392,8 @@ eOSState cMenuEditRemoteTimer::ProcessKey(eKeys Key)
               if ((state = CheckState(RemoteTimers.New(rt))) == osBack) {
                  Timers.Del(timer);
                  timer = rt;
+                 RemoteConflicts.SetNeedsUpdate();
+                 LocalConflicts.SetNeedsUpdate();
                  }
               else
                  delete rt;
@@ -873,22 +402,15 @@ eOSState cMenuEditRemoteTimer::ProcessKey(eKeys Key)
         else {
            // move remote to local
            cTimer *lt = new cTimer();
-#if VDRVERSNUM < 10403
-           if (lt->Parse(timer->ToText())) {
-#else
            *lt = *(cTimer*) timer;
-#endif
            if ((state = CheckState(RemoteTimers.Delete((cRemoteTimer*) timer))) == osBack) {
               Timers.Add(lt);
               timer = lt;
+              RemoteConflicts.SetNeedsUpdate();
+              LocalConflicts.SetNeedsUpdate();
               }
            else
               delete lt;
-#if VDRVERSNUM < 10403
-           }
-           else
-              delete lt;
-#endif
            }
         if (timerItem && state == osBack)
            (*timerItem)->Update(timer, tmpUser, tmpRemote);
@@ -902,20 +424,19 @@ eOSState cMenuEditRemoteTimer::ProcessKey(eKeys Key)
            if ((state = CheckState(RemoteTimers.New(rt))) == osBack) {
               Timers.Del(timer);
               timer = rt;
+              RemoteConflicts.SetNeedsUpdate();
               }
-           else
+           else {
               delete rt;
+              LocalConflicts.SetNeedsUpdate();
+              }
            }
+        else
+           LocalConflicts.SetNeedsUpdate();
         if (timerItem && state == osBack)
            *timerItem = new cMenuTimerItem(timer, tmpUser, tmpRemote);
         }
      }
-#if APIVERSNUM < 10712
-  else if (state == osContinue && Key == kRed && !HasSubMenu())
-    return AddSubMenu(subMenuFolder = new cMenuFolder(trREMOTETIMERS("Select folder"), &Folders, name));
-  else if (state == osEnd && HasSubMenu())
-     state = SetFolder();
-#endif
   return state;
 }
 
@@ -930,12 +451,14 @@ public:
   virtual int Compare(const cListObject &ListObject) const;
   virtual void Set(void);
   cTimer *Timer(void) { return timer; }
+  virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable);
   };
 */
 
 cMenuTimerItem::cMenuTimerItem(cTimer *Timer, int User, bool Remote)
 {
   Update(Timer, User, Remote);
+  UpdateConflict();
   Set();
 }
 
@@ -946,6 +469,13 @@ void cMenuTimerItem::Update(cTimer *Timer, int User, bool Remote)
   remote = Remote;
 }
 
+bool cMenuTimerItem::UpdateConflict()
+{
+  bool conflictOld = conflict;
+  conflict = remote ? RemoteConflicts.HasConflict(((cRemoteTimer*) timer)->Id()) : LocalConflicts.HasConflict(timer->Index() + 1);
+  return conflict != conflictOld;
+}
+
 int cMenuTimerItem::Compare(const cListObject &ListObject) const
 {
   return timer->Compare(*((cMenuTimerItem *)&ListObject)->timer);
@@ -955,11 +485,7 @@ void cMenuTimerItem::Set(void)
 {
   cString day, name("");
   if (timer->WeekDays())
-#if VDRVERSNUM < 10503
-     day = timer->PrintDay(0, timer->WeekDays());
-#else
      day = timer->PrintDay(0, timer->WeekDays(), false);
-#endif
   else if (timer->Day() - time(NULL) < 28 * SECSINDAY) {
      day = itoa(timer->GetMDay(timer->Day()));
      name = WeekDayName(timer->Day());
@@ -972,17 +498,16 @@ void cMenuTimerItem::Set(void)
      strftime(buffer, sizeof(buffer), "%Y%m%d", &tm_r);
      day = buffer;
      }
-#if VDRVERSNUM >= 10714
   const char *File = Setup.FoldersInTimerMenu ? NULL : strrchr(timer->File(), FOLDERDELIMCHAR);
   if (File && strcmp(File + 1, TIMERMACRO_TITLE) && strcmp(File + 1, TIMERMACRO_EPISODE))
      File++;
   else
      File = timer->File();
-#endif
   // TRANSLATORS: Indicator for (R)emote or (L)ocal timer in timers list
   const char *RL = trREMOTETIMERS("RL");
-  SetText(cString::sprintf("%c\t%c%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s",
+  SetText(cString::sprintf("%c%c\t%c%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s",
                     !(timer->HasFlags(tfActive)) ? ' ' : timer->FirstDay() ? '!' : timer->Recording() ? '#' : '>',
+                    conflict ? '%' : ' ',
                     RL[remote ? 0 : 1],
                     timer->Channel()->Number(),
                     *name,
@@ -992,11 +517,7 @@ void cMenuTimerItem::Set(void)
                     timer->Start() % 100,
                     timer->Stop() / 100,
                     timer->Stop() % 100,
-#if VDRVERSNUM >= 10714
                     File));
-#else
-                    timer->File()));
-#endif
 }
 
 int cMenuTimerItem::ParseUser(const cTimer *Timer) {
@@ -1009,6 +530,12 @@ void cMenuTimerItem::UpdateUser(cTimer& Timer, int User) {
   Timer.Parse(*modTimer);
 }
 
+void cMenuTimerItem::SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
+{
+  if (!RemoteTimersSetup.skinTimers || !DisplayMenu->SetItemTimer(timer, Index, Current, Selectable))
+     DisplayMenu->SetItem(Text(), Index, Current, Selectable);
+}
+
 // --- cMenuTimers -----------------------------------------------------------
 
 /*
@@ -1029,16 +556,14 @@ public:
   };
 */
 
-cMenuTimers::cMenuTimers(void)
-:cOsdMenu(tr("Timers"), 2, CHNUMWIDTH + 1, 10, 6, 6)
+cMenuTimers::cMenuTimers(const char* ServerIp, unsigned short ServerPort)
+:cOsdMenu(tr("Timers"), 3, CHNUMWIDTH + 1, 10, 6, 6)
 {
-#if VDRVERSNUM >= 10728
-  SetMenuCategory(mcTimer);
-#endif
+  SetMenuCategory(RemoteTimersSetup.skinTimers ? mcTimer : mcPlugin);
   helpKeys = -1;
   userFilter = USER_FROM_SETUP(RemoteTimersSetup.userFilterTimers);
   currentItem = NULL;
-  if (!cSvdrp::GetInstance()->Connect())
+  if (!cSvdrp::GetInstance()->Connect(ServerIp, ServerPort))
       Skins.Message(mtWarning, tr(MSG_UNAVAILABLE));
   Set();
   /*
@@ -1066,6 +591,8 @@ void cMenuTimers::Set(eRemoteTimersState Msg)
   if (currentIndex >= 0)
      currentTimerString = ((cMenuTimerItem *) Get(currentIndex))->Timer()->ToText();
   Clear();
+  LocalConflicts.Update();
+  RemoteConflicts.Update();
   eRemoteTimersState state = cSvdrp::GetInstance()->Offline() ? rtsOk : RemoteTimers.Refresh();
   if (state == rtsOk) {
       for (cRemoteTimer *timer = RemoteTimers.First(); timer; timer = RemoteTimers.Next(timer)) {
@@ -1132,6 +659,20 @@ cTimer *cMenuTimers::CurrentTimer(void)
   return item ? item->Timer() : NULL;
 }
 
+bool cMenuTimers::UpdateConflicts(bool Remote)
+{
+  bool updated = false;
+  Remote ? RemoteConflicts.Update() : LocalConflicts.Update();
+  for (cOsdItem *item = First(); item; item = Next(item)) {
+      cMenuTimerItem *i = (cMenuTimerItem *) item;
+      if (i->Remote() == Remote && i->UpdateConflict()) {
+         i->Set();
+         updated = true;
+         }
+      }
+  return updated;
+}
+
 void cMenuTimers::SetHelpKeys(void)
 {
   int NewHelpKeys = 0;
@@ -1169,8 +710,15 @@ eOSState cMenuTimers::OnOff(void)
         isyslog("timer %s first day set to %s", *timer->ToDescr(), *timer->PrintFirstDay());
      else
         isyslog("timer %s %sactivated", *timer->ToDescr(), timer->HasFlags(tfActive) ? "" : "de");
-     if (!item->Remote())
+     if (item->Remote()) {
+        if (UpdateConflicts(true))
+           Display();
+        }
+     else {
         Timers.SetModified();
+        if (UpdateConflicts(false))
+           Display();
+        }
      }
   return osContinue;
 }
@@ -1217,12 +765,15 @@ eOSState cMenuTimers::Delete(void)
               return osContinue;
            }
         isyslog("deleting timer %s", *ti->ToDescr());
-        if (item->Remote())
+        if (item->Remote()) {
            CheckState(RemoteTimers.Delete((cRemoteTimer*)ti), false);
+           UpdateConflicts(true);
+           }
         else {
            Timers.Del(ti);
            cOsdMenu::Del(Current());
            Timers.SetModified();
+           UpdateConflicts(false);
            }
         Display();
         }
@@ -1268,14 +819,26 @@ eOSState cMenuTimers::ProcessKey(eKeys Key)
        default: break;
        }
      }
+  bool display = false;
+  if (LocalConflicts.NeedsUpdate()) {
+     UpdateConflicts(false);
+     display = true;
+     }
+  if (RemoteConflicts.NeedsUpdate()) {
+     UpdateConflicts(true);
+     display = true;
+     }
   //if (TimerNumber >= 0 && !HasSubMenu() && Timers.Get(TimerNumber)) {
   if (TimerNumber >= 0 && !HasSubMenu() && currentItem) {
      // a newly created timer was confirmed with Ok
      Add(currentItem, true);
      //Add(new cMenuTimerItem(Timers.Get(TimerNumber)), true);
      Set();
-     Display();
+     //Display();
+     display = true;
      }
+  if (display)
+     Display();
   if (Key != kNone)
      SetHelpKeys();
   return state;
@@ -1286,15 +849,13 @@ eOSState cMenuTimers::ProcessKey(eKeys Key)
 cMenuEvent::cMenuEvent(const cEvent *Event, bool CanSwitch, bool Buttons)
 :cOsdMenu(tr("Event"))
 {
-#if VDRVERSNUM >= 10728
-  SetMenuCategory(mcEvent);
-#endif
+  SetMenuCategory(RemoteTimersSetup.skinSchedule ? mcEvent : mcPlugin);
   event = Event;
   if (event) {
      cChannel *channel = Channels.GetByChannelID(event->ChannelID(), true);
      if (channel) {
         SetTitle(channel->Name());
-        int TimerMatch = tmNone;
+        eTimerMatch TimerMatch = tmNone;
         //Timers.GetMatch(event, &TimerMatch);
 	GetBestMatch(event, MASK_FROM_SETUP(RemoteTimersSetup.userFilterSchedule), &TimerMatch, NULL, NULL);
         if (Buttons)
@@ -1354,7 +915,7 @@ public:
   const cChannel *channel;
   bool withDate;
   bool withBar;
-  int timerMatch;
+  eTimerMatch timerMatch;
   int timerType;
   cMenuScheduleItem(const cEvent *Event, cChannel *Channel = NULL, bool WithDate = false, bool WithBar = false);
   static void SetSortMode(eScheduleSortMode SortMode) { sortMode = SortMode; }
@@ -1362,6 +923,7 @@ public:
   static eScheduleSortMode SortMode(void) { return sortMode; }
   virtual int Compare(const cListObject &ListObject) const;
   bool Update(bool Force = false);
+  virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable);
   };
 
 cMenuScheduleItem::eScheduleSortMode cMenuScheduleItem::sortMode = ssmAllThis;
@@ -1407,7 +969,7 @@ static const char *TimerMatchChars = trREMOTETIMERS(" tTpP");
 bool cMenuScheduleItem::Update(bool Force)
 {
   bool result = false;
-  int oldTimerMatch = timerMatch;
+  eTimerMatch oldTimerMatch = timerMatch;
   //Timers.GetMatch(event, &timerMatch);
   int oldTimerType = timerType;
   GetBestMatch(event, MASK_FROM_SETUP(RemoteTimersSetup.userFilterSchedule), &timerMatch, &timerType, NULL);
@@ -1418,14 +980,7 @@ bool cMenuScheduleItem::Update(bool Force)
      char r = event->SeenWithin(30) && event->IsRunning() ? '*' : ' ';
      const char *csn = channel ? channel->ShortName(true) : NULL;
      cString eds = event->GetDateString();
-#if VDRVERSNUM < 10504
-#define Utf8SymChars(a,b) b
-#endif
-#if VDRVERSNUM < 10728
-#define CSN_SYMBOLS 6
-#else
 #define CSN_SYMBOLS 999
-#endif
      if (channel && withDate)
         buffer = cString::sprintf("%d\t%.*s\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, CSN_SYMBOLS), csn, Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title());
      else if (channel) {
@@ -1435,7 +990,7 @@ bool cMenuScheduleItem::Update(bool Force)
            buffer = cString::sprintf("%d\t%.*s\t%s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, CSN_SYMBOLS), csn, *event->GetTimeString(), ProgressBar[progress], t, v, r, event->Title());
 	   }
 	else
-           buffer = cString::sprintf("%d\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title());
+           buffer = cString::sprintf("%d\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, CSN_SYMBOLS), csn, *event->GetTimeString(), t, v, r, event->Title());
 	}
      else
         buffer = cString::sprintf("%.*s\t%s\t%c%c%c\t%s", Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title());
@@ -1445,11 +1000,18 @@ bool cMenuScheduleItem::Update(bool Force)
   return result;
 }
 
+void cMenuScheduleItem::SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
+{
+  if (!RemoteTimersSetup.skinSchedule || !DisplayMenu->SetItemEvent(event, Index, Current, Selectable, channel, withDate, timerMatch))
+     DisplayMenu->SetItem(Text(), Index, Current, Selectable);
+}
+
 // --- cMenuWhatsOn ----------------------------------------------------------
 
 class cMenuWhatsOn : public cOsdMenu {
 private:
-  bool now;
+  //bool now;
+  int whatsOnId;
   int helpKeys;
   int timerState;
   eOSState Record(void);
@@ -1458,8 +1020,9 @@ private:
   static const cEvent *scheduleEvent;
   bool Update(void);
   void SetHelpKeys(void);
+  time_t GetTime(int SecondsFromMidnight);
 public:
-  cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentChannelNr);
+  cMenuWhatsOn(const cSchedules *Schedules, int WhatsOnId, int CurrentChannelNr);
   static int CurrentChannel(void) { return currentChannel; }
   static void SetCurrentChannel(int ChannelNr) { currentChannel = ChannelNr; }
   static const cEvent *ScheduleEvent(void);
@@ -1469,13 +1032,16 @@ public:
 int cMenuWhatsOn::currentChannel = 0;
 const cEvent *cMenuWhatsOn::scheduleEvent = NULL;
 
-cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentChannelNr)
-:cOsdMenu(Now ? tr("What's on now?") : tr("What's on next?"), CHNUMWIDTH, CHNAMWIDTH, 6, 4, 4)
+#define NOW  (WhatsOnId == EPGTIME_LENGTH)
+#define NEXT (WhatsOnId == EPGTIME_LENGTH + 1)
+#define EPGTIMESTR(i) *cString::sprintf("%02d:%02d", RemoteTimersSetup.epgTime[i] / 100, RemoteTimersSetup.epgTime[i] % 100)
+#define EPGTIMESEC ((RemoteTimersSetup.epgTime[whatsOnId] / 100) * 3600 + (RemoteTimersSetup.epgTime[whatsOnId] % 100) * 60)
+
+cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, int WhatsOnId, int CurrentChannelNr)
+:cOsdMenu(NOW ? tr("What's on now?") : NEXT ? tr("What's on next?") : *cString::sprintf(trREMOTETIMERS("What's on at %s?"), EPGTIMESTR(WhatsOnId)), CHNUMWIDTH, CHNAMWIDTH, 6, 4, 4)
 {
-#if VDRVERSNUM >= 10728
-  SetMenuCategory(mcSchedule);
-#endif
-  now = Now;
+  SetMenuCategory(RemoteTimersSetup.skinSchedule ? (NOW ? mcScheduleNow : mcScheduleNext) : mcPlugin);
+  whatsOnId = WhatsOnId;
   helpKeys = -1;
   timerState = 0;
   Timers.Modified(timerState);
@@ -1483,9 +1049,9 @@ cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentCha
       if (!Channel->GroupSep()) {
          const cSchedule *Schedule = Schedules->GetSchedule(Channel);
          if (Schedule) {
-            const cEvent *Event = Now ? Schedule->GetPresentEvent() : Schedule->GetFollowingEvent();
+            const cEvent *Event = NOW ? Schedule->GetPresentEvent() : NEXT ? Schedule->GetFollowingEvent() : Schedule->GetEventAround(GetTime(EPGTIMESEC));
             if (Event)
-               Add(new cMenuScheduleItem(Event, Channel, false, Now), Channel->Number() == CurrentChannelNr);
+               Add(new cMenuScheduleItem(Event, Channel, false, NOW), Channel->Number() == CurrentChannelNr);
             }
          }
       }
@@ -1494,7 +1060,21 @@ cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentCha
   SetHelpKeys();
   int userFilter = USER_FROM_SETUP(RemoteTimersSetup.userFilterSchedule);
   if (userFilter != 0)
-     SetTitle(cString::sprintf("%s %s %d", Now ? tr("What's on now?") : tr("What's on next?"), trREMOTETIMERS("User"), userFilter));
+        SetTitle(cString::sprintf("%s %s %d", NOW ? tr("What's on now?") : NEXT ? tr("What's on next?") : *cString::sprintf(trREMOTETIMERS("What's on at %s?"), EPGTIMESTR(whatsOnId)), trREMOTETIMERS("User"), userFilter));
+}
+
+time_t cMenuWhatsOn::GetTime(int SecondsFromMidnight)
+{
+  time_t t = time(NULL);
+  struct tm tm;
+  localtime_r(&t, &tm);
+  if (tm.tm_hour * 3600 + tm.tm_min * 60 + tm.tm_sec > SecondsFromMidnight)
+     tm.tm_mday++;
+  tm.tm_hour = SecondsFromMidnight / 3600;
+  tm.tm_min = (SecondsFromMidnight % 3600) / 60;
+  tm.tm_sec = SecondsFromMidnight % 60;
+  tm.tm_isdst = -1;
+  return mktime(&tm);
 }
 
 bool cMenuWhatsOn::Update(void)
@@ -1520,8 +1100,14 @@ void cMenuWhatsOn::SetHelpKeys(void)
         NewHelpKeys = 1;
      }
   if (NewHelpKeys != helpKeys) {
+     static cString GreenTime;
+     int nextId = (whatsOnId + 1) % (EPGTIME_LENGTH + 2);
+     while (nextId < EPGTIME_LENGTH && !RemoteTimersSetup.epgTime[nextId])
+        ++nextId;
+     if (nextId < EPGTIME_LENGTH)
+        GreenTime = EPGTIMESTR(nextId);
      const char *Red[] = { NULL, tr("Button$Record"), tr("Button$Timer") };
-     SetHelp(Red[NewHelpKeys], now ? tr("Button$Next") : tr("Button$Now"), tr("Button$Schedule"), RemoteTimersSetup.swapOkBlue ? tr("Button$Info") : tr("Button$Switch"));
+     SetHelp(Red[NewHelpKeys], nextId == EPGTIME_LENGTH ? tr("Button$Now") : nextId > EPGTIME_LENGTH ? tr("Button$Next") : *GreenTime, tr("Button$Schedule"), RemoteTimersSetup.swapOkBlue ? tr("Button$Info") : tr("Button$Switch"));
      helpKeys = NewHelpKeys;
      }
 }
@@ -1549,13 +1135,15 @@ eOSState cMenuWhatsOn::Record(void)
 {
   cMenuScheduleItem *item = (cMenuScheduleItem *)Get(Current());
   if (item) {
-     int tm = tmNone;
+     eTimerMatch tm = tmNone;
      bool isRemote = false;
      if (item->timerMatch == tmFull) {
         //cTimer *timer = Timers.GetMatch(item->event, &tm);
         cTimer *timer = GetBestMatch(item->event, MASK_FROM_SETUP(RemoteTimersSetup.userFilterSchedule), &tm, NULL, &isRemote);
-        if (timer)
+        if (timer) {
+           isRemote ? RemoteConflicts.Update() : LocalConflicts.Update();
            return AddSubMenu(new cMenuEditRemoteTimer(timer, isRemote));
+           }
         }
 
      tm = tmNone;
@@ -1616,8 +1204,10 @@ eOSState cMenuWhatsOn::Record(void)
            }
         Timers.SetModified();
         isyslog("timer %s added (active)", *timer->ToDescr());
-        if (timer->Matches(0, false, NEWTIMERLIMIT))
+        if (timer->Matches(0, false, NEWTIMERLIMIT)) {
+           isRemote ? RemoteConflicts.Update() : LocalConflicts.Update();
            return AddSubMenu(new cMenuEditRemoteTimer(timer, isRemote));
+        }
         if (HasSubMenu())
            CloseSubMenu();
         if (Update())
@@ -1692,20 +1282,19 @@ public:
   };
 */
 
-cMenuSchedule::cMenuSchedule(void)
+cMenuSchedule::cMenuSchedule(const char* ServerIp, unsigned short ServerPort)
 :cOsdMenu("")
 {
-#if VDRVERSNUM >= 10728
-  SetMenuCategory(mcSchedule);
-#endif
-  now = next = false;
+  SetMenuCategory(RemoteTimersSetup.skinSchedule ? mcSchedule : mcPlugin);
+  //now = next = false;
+  whatsOnId = -1;
   otherChannel = 0;
   helpKeys = -1;
   timerState = 0;
   userFilter = USER_FROM_SETUP(RemoteTimersSetup.userFilterSchedule);
   Timers.Modified(timerState);
   cMenuScheduleItem::SetSortMode(cMenuScheduleItem::ssmAllThis);
-  if (!cSvdrp::GetInstance()->Connect() || RemoteTimers.Refresh() != rtsOk)
+  if (!cSvdrp::GetInstance()->Connect(ServerIp, ServerPort) || RemoteTimers.Refresh() != rtsOk)
      Skins.Message(mtWarning, tr(MSG_UNAVAILABLE));
   cChannel *channel = Channels.GetByNumber(cDevice::CurrentChannel());
   if (channel) {
@@ -1866,13 +1455,15 @@ eOSState cMenuSchedule::Record(void)
 {
   cMenuScheduleItem *item = (cMenuScheduleItem *)Get(Current());
   if (item) {
-     int tm = tmNone;
+     eTimerMatch tm = tmNone;
      bool isRemote = false;
      if (item->timerMatch == tmFull) {
         //cTimer *timer = Timers.GetMatch(item->event, &tm);
         cTimer *timer = GetBestMatch(item->event, MASK_FROM_SETUP(RemoteTimersSetup.userFilterSchedule), &tm, NULL, &isRemote);
-        if (timer)
+        if (timer) {
+           isRemote ? RemoteConflicts.Update() : LocalConflicts.Update();
            return AddSubMenu(new cMenuEditRemoteTimer(timer, isRemote));
+           }
         }
 
      tm = tmNone;
@@ -1933,8 +1524,10 @@ eOSState cMenuSchedule::Record(void)
            }
         Timers.SetModified();
         isyslog("timer %s added (active)", *timer->ToDescr());
-        if (timer->Matches(0, false, NEWTIMERLIMIT))
+        if (timer->Matches(0, false, NEWTIMERLIMIT)) {
+           isRemote ? RemoteConflicts.Update() : LocalConflicts.Update();
            return AddSubMenu(new cMenuEditRemoteTimer(timer, isRemote));
+        }
         if (HasSubMenu())
            CloseSubMenu();
         if (Update())
@@ -1966,22 +1559,25 @@ eOSState cMenuSchedule::ProcessKey(eKeys Key)
        case kRecord:
        case kRed:    return Record();
        case kGreen:  if (schedules) {
-                        if (!now && !next) {
+                        if (whatsOnId == -1) {
                            int ChannelNr = 0;
                            if (Count()) {
                               cChannel *channel = Channels.GetByChannelID(((cMenuScheduleItem *)Get(Current()))->event->ChannelID(), true);
                               if (channel)
                                  ChannelNr = channel->Number();
                               }
-                           now = true;
-                           return AddSubMenu(new cMenuWhatsOn(schedules, true, ChannelNr));
+                           whatsOnId = EPGTIME_LENGTH; // now
+                           return AddSubMenu(new cMenuWhatsOn(schedules, whatsOnId, ChannelNr));
                            }
-                        now = !now;
-                        next = !next;
-                        return AddSubMenu(new cMenuWhatsOn(schedules, now, cMenuWhatsOn::CurrentChannel()));
+                        //now = !now;
+                        //next = !next;
+                        whatsOnId = (whatsOnId + 1) % (EPGTIME_LENGTH + 2);
+                        while (whatsOnId < EPGTIME_LENGTH && !RemoteTimersSetup.epgTime[whatsOnId])
+                           ++whatsOnId;
+                        return AddSubMenu(new cMenuWhatsOn(schedules, whatsOnId, cMenuWhatsOn::CurrentChannel()));
                         }
        case kYellow: if (schedules)
-                        return AddSubMenu(new cMenuWhatsOn(schedules, false, cMenuWhatsOn::CurrentChannel()));
+                        return AddSubMenu(new cMenuWhatsOn(schedules, EPGTIME_LENGTH + 1, cMenuWhatsOn::CurrentChannel()));
                      break;
        case kBlue:   if (Count() && otherChannel)
                         return Switch();
@@ -1994,7 +1590,8 @@ eOSState cMenuSchedule::ProcessKey(eKeys Key)
        }
      }
   else if (!HasSubMenu()) {
-     now = next = false;
+     // now = next = false;
+     whatsOnId = -1;
      const cEvent *ei = cMenuWhatsOn::ScheduleEvent();
      if (ei) {
         cChannel *channel = Channels.GetByChannelID(ei->ChannelID(), true);
@@ -2016,180 +1613,6 @@ eOSState cMenuSchedule::ProcessKey(eKeys Key)
   return state;
 }
 
-#if VDRVERSNUM < 10713
-// --- cMenuCommands ---------------------------------------------------------
-
-class cMenuCommands : public cOsdMenu {
-private:
-#if APIVERSNUM < 10712
-  cCommands *commands;
-  char *parameters;
-#else
-  cList<cNestedItem> *commands;
-  cString parameters;
-  cString title;
-  cString command;
-  bool confirm;
-  char *result;
-  bool Parse(const char *s);
-#endif
-  eOSState Execute(void);
-public:
-#if APIVERSNUM < 10712
-  cMenuCommands(const char *Title, cCommands *Commands, const char *Parameters = NULL);
-#else
-  cMenuCommands(const char *Title, cList<cNestedItem> *Commands, const char *Parameters = NULL);
-#endif
-  virtual ~cMenuCommands();
-  virtual eOSState ProcessKey(eKeys Key);
-  };
-
-#if APIVERSNUM < 10712
-cMenuCommands::cMenuCommands(const char *Title, cCommands *Commands, const char *Parameters)
-:cOsdMenu(Title)
-{
-  SetHasHotkeys();
-  commands = Commands;
-  parameters = Parameters ? strdup(Parameters) : NULL;
-  for (cCommand *command = commands->First(); command; command = commands->Next(command))
-      Add(new cOsdItem(hk(command->Title())));
-}
-#else
-cMenuCommands::cMenuCommands(const char *Title, cList<cNestedItem> *Commands, const char *Parameters)
-:cOsdMenu(Title)
-{
-  result = NULL;
-  SetHasHotkeys();
-  commands = Commands;
-  parameters = Parameters;
-  for (cNestedItem *Command = commands->First(); Command; Command = commands->Next(Command)) {
-      const char *s = Command->Text();
-      if (Command->SubItems())
-         Add(new cOsdItem(hk(cString::sprintf("%s...", s))));
-      else if (Parse(s))
-         Add(new cOsdItem(hk(title)));
-      }
-}
-#endif
-
-cMenuCommands::~cMenuCommands()
-{
-#if APIVERSNUM < 10712
-  free(parameters);
-#else
-  free(result);
-#endif
-}
-
-#if APIVERSNUM < 10712
-eOSState cMenuCommands::Execute(void)
-{
-  cCommand *command = commands->Get(Current());
-  if (command) {
-     bool confirmed = true;
-     if (command->Confirm())
-        confirmed = Interface->Confirm(cString::sprintf("%s?", command->Title()));
-     if (confirmed) {
-        Skins.Message(mtStatus, cString::sprintf("%s...", command->Title()));
-        const char *Result = command->Execute(parameters);
-        Skins.Message(mtStatus, NULL);
-        if (Result)
-           return AddSubMenu(new cMenuText(command->Title(), Result, fontFix));
-        return osEnd;
-        }
-     }
-  return osContinue;
-}
-#else
-bool cMenuCommands::Parse(const char *s)
-{
-  const char *p = strchr(s, ':');
-  if (p) {
-     int l = p - s;
-     if (l > 0) {
-        char t[l + 1];
-        stripspace(strn0cpy(t, s, l + 1));
-        l = strlen(t);
-        if (l > 1 && t[l - 1] == '?') {
-           t[l - 1] = 0;
-           confirm = true;
-           }
-        else
-           confirm = false;
-        title = t;
-        command = skipspace(p + 1);
-        return true;
-        }
-     }
-  return false;
-}
-
-eOSState cMenuCommands::Execute(void)
-{
-  cNestedItem *Command = commands->Get(Current());
-  if (Command) {
-     if (Command->SubItems())
-        return AddSubMenu(new cMenuCommands(Title(), Command->SubItems(), parameters));
-     if (Parse(Command->Text())) {
-        if (!confirm || Interface->Confirm(cString::sprintf("%s?", *title))) {
-           Skins.Message(mtStatus, cString::sprintf("%s...", *title));
-           free(result);
-           result = NULL;
-           cString cmdbuf;
-           if (!isempty(parameters))
-              cmdbuf = cString::sprintf("%s %s", *command, *parameters);
-           const char *cmd = *cmdbuf ? *cmdbuf : *command;
-           dsyslog("executing command '%s'", cmd);
-           cPipe p;
-           if (p.Open(cmd, "r")) {
-              int l = 0;
-              int c;
-              while ((c = fgetc(p)) != EOF) {
-                    if (l % 20 == 0) {
-                       if (char *NewBuffer = (char *)realloc(result, l + 21))
-                          result = NewBuffer;
-                       else {
-                          esyslog("ERROR: out of memory");
-                          break;
-                          }
-                       }
-                    result[l++] = char(c);
-                    }
-              if (result)
-                 result[l] = 0;
-              p.Close();
-              }
-           else
-              esyslog("ERROR: can't open pipe for command '%s'", cmd);
-           Skins.Message(mtStatus, NULL);
-           if (result)
-              return AddSubMenu(new cMenuText(title, result, fontFix));
-           return osEnd;
-           }
-        }
-     }
-  return osContinue;
-}
-#endif
-
-eOSState cMenuCommands::ProcessKey(eKeys Key)
-{
-  eOSState state = cOsdMenu::ProcessKey(Key);
-
-  if (state == osUnknown) {
-     switch (Key) {
-       case kRed:
-       case kGreen:
-       case kYellow:
-       case kBlue:   return osContinue;
-       case kOk:     return Execute();
-       default:      break;
-       }
-     }
-  return state;
-}
-#endif
-
 // --- cMenuRecording --------------------------------------------------------
 
 class cMenuRecording : public cOsdMenu {
@@ -2205,21 +1628,12 @@ public:
 cMenuRecording::cMenuRecording(const cRecording *Recording, bool WithButtons)
 :cOsdMenu(tr("Recording info"))
 {
-#if VDRVERSNUM >= 10728
-  // with mcRecording some skins would add free diskspace to title
-  SetMenuCategory(mcPlugin);
-#endif
+  SetMenuCategory(RemoteTimersSetup.skinRecordings ? mcRecordingInfo : mcPlugin);
   recording = Recording;
   withButtons = WithButtons;
   if (withButtons)
      SetHelp(tr("Button$Play"), tr("Button$Rewind"));
-#if VDRVERSNUM < 10728
-  cIndexFile index(Recording->FileName(), false);
-  int last = index.Last();
-  SetTitle(cString::sprintf("%s - %d MB %s%s", tr("Recording info"), DirSizeMB(Recording->FileName()), last >= 0 ? "- " : "", last >= 0 ? *IndexToHMSF(last) : ""));
-#else
   SetTitle(cString::sprintf("%s - %s", tr("Recording info"), *cFreeDiskSpace::FreeDiskSpaceString(Recording)));
-#endif
 }
 
 void cMenuRecording::Display(void)
@@ -2297,31 +1711,18 @@ public:
 cMenuEditRecording::cMenuEditRecording(const cRecording *Recording)
 :cOsdMenu(trREMOTETIMERS("Edit recording"), 12)
 {
-#if VDRVERSNUM >= 10728
-  // with mcRecording some skins would add free diskspace to title
+  // there is no mcRecordingEdit
   SetMenuCategory(mcPlugin);
-#endif
   // Must be locked against Recordings
-#if VDRVERSNUM < 10721
-  priority = Recording->priority;
-  lifetime = Recording->lifetime;
-#else
   priority = Recording->Priority();
   lifetime = Recording->Lifetime();
-#endif
   strn0cpy(name, Recording->Name(), sizeof(name));
   tmpUser = user = ParseUser(Recording->Info()->Aux());
   fileName = Recording->FileName();
   subMenuFolder = NULL;
   file = NULL;
   SetHelpKeys();
-#if VDRVERSNUM < 10728
-  cIndexFile index(*fileName, false);
-  int last = index.Last();
-  SetTitle(cString::sprintf("%s - %d MB %s%s", trREMOTETIMERS("Edit recording"), DirSizeMB(*fileName), last >= 0 ? "- " : "", last >= 0 ? *IndexToHMSF(last) : ""));
-#else
   SetTitle(cString::sprintf("%s - %s", trREMOTETIMERS("Edit recording"), *cFreeDiskSpace::FreeDiskSpaceString(Recording)));
-#endif
   Add(new cMenuEditIntItem(tr("Priority"), &priority, 0, MAXPRIORITY));
   Add(new cMenuEditIntItem(tr("Lifetime"), &lifetime, 0, MAXLIFETIME));
   Add(new cMenuEditUserItem(trREMOTETIMERS("User ID"), &tmpUser));
@@ -2352,11 +1753,7 @@ eOSState cMenuEditRecording::Cut()
   cRecording *recording = Recordings.GetByName(*fileName);
   if (recording) {
      cMarks Marks;
-#if VDRVERSNUM >= 10703
      if (Marks.Load(recording->FileName(), recording->FramesPerSecond(), recording->IsPesRecording()) && Marks.Count()) {
-#else
-     if (Marks.Load(recording->FileName()) && Marks.Count()) {
-#endif
         const char *name = recording->Name();
         int len = strlen(RemoteTimersSetup.serverDir);
         bool remote = len == 0 || (strstr(name, RemoteTimersSetup.serverDir) == name && name[len] == FOLDERDELIMCHAR);
@@ -2414,7 +1811,6 @@ eOSState cMenuEditRecording::Info(void)
 #define INFOFILE_TS "info"
 bool cMenuEditRecording::ModifyInfo(cRecording *Recording, const char *Info)
 {
-#if VDRVERSNUM >= 10703
   cString InfoFileName = cString::sprintf(Recording->IsPesRecording() ? "%s/" INFOFILE_PES : "%s/" INFOFILE_TS, Recording->FileName());
   FILE *f = fopen(InfoFileName, "a");
   if (f) {
@@ -2432,24 +1828,6 @@ bool cMenuEditRecording::ModifyInfo(cRecording *Recording, const char *Info)
      }
   else
      esyslog("remotetimers: writing to '%s' failed: %m", *InfoFileName);
-#else
-  cString InfoFileName = cString::sprintf("%s/" INFOFILE_PES, Recording->FileName());
-  // check for write access as cRecording::WriteInfo() always returns true
-  if (access(InfoFileName, W_OK) == 0) {
-     FILE *f = fmemopen((void *) Info, strlen(Info) * sizeof(char), "r");
-     if (f) {
-        // Casting const away is nasty, but what the heck?
-        // The Recordings thread is locked and the object is going to be deleted anyway.
-        if (((cRecordingInfo *)Recording->Info())->Read(f) && Recording->WriteInfo())
-           return true;
-        esyslog("remotetimers: error in info string '%s'", Info);
-	}
-     else
-        esyslog("remotetimers: error in fmemopen: %m");
-     }
-  else
-     esyslog("remotetimers: '%s' not writeable: %m", *InfoFileName);
-#endif
   return false;
 }
 
@@ -2466,23 +1844,17 @@ bool cMenuEditRecording::UpdateUser(cRecording *Recording, int NewUser)
 #define PRIO_LIFE_FORMAT ".%02d.%02d.rec"
 bool cMenuEditRecording::UpdatePrioLife(cRecording *Recording)
 {
-#if VDRVERSNUM >= 10703
   if (!Recording->IsPesRecording()) {
      cString buffer = cString::sprintf("P %d\nL %d", priority, lifetime);
      if (ModifyInfo(Recording, *buffer))
         return true;
      }
   else
-#endif
   {
      char *newName = strdup(Recording->FileName());
      size_t len = strlen(newName);
      cString freeStr(newName, true);
-#if VDRVERSNUM < 10721
-     cString oldData = cString::sprintf(PRIO_LIFE_FORMAT, Recording->priority, Recording->lifetime);
-#else
      cString oldData = cString::sprintf(PRIO_LIFE_FORMAT, Recording->Priority(), Recording->Lifetime());
-#endif
      cString newData = cString::sprintf(PRIO_LIFE_FORMAT, priority, lifetime);
      size_t lenReplace = strlen(oldData);
      if (lenReplace < len) {
@@ -2605,11 +1977,7 @@ eOSState cMenuEditRecording::ProcessKey(eKeys Key)
                            bool replace = false;
                            if (user != tmpUser)
                               replace |= UpdateUser(recording, tmpUser);
-#if VDRVERSNUM < 10721
-                           if (priority != recording->priority || lifetime != recording->lifetime)
-#else
                            if (priority != recording->Priority() || lifetime != recording->Lifetime())
-#endif
                               replace |= UpdatePrioLife(recording);
                            if (replace) {
                               Recordings.Del(recording);
@@ -2673,7 +2041,8 @@ eOSState cRemoteTimersReplayControl::ProcessKey(eKeys Key)
 
 class cMenuRecordingItem : public cOsdItem {
 private:
-  char *fileName;
+  cRecording *recording;
+  int level;
   char *name;
   int user;
   int totalEntries, newEntries;
@@ -2682,14 +2051,16 @@ public:
   ~cMenuRecordingItem();
   void IncrementCounter(bool New);
   const char *Name(void) { return name; }
-  const char *FileName(void) { return fileName; }
+  cRecording *Recording(void) { return recording; }
   int User(void) { return user; } const
   bool IsDirectory(void) { return name != NULL; }
+  virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable);
   };
 
 cMenuRecordingItem::cMenuRecordingItem(cRecording *Recording, int Level, int User)
 {
-  fileName = strdup(Recording->FileName());
+  recording = Recording;
+  level = Level;
   name = NULL;
   user = User;
   totalEntries = newEntries = 0;
@@ -2700,7 +2071,6 @@ cMenuRecordingItem::cMenuRecordingItem(cRecording *Recording, int Level, int Use
 
 cMenuRecordingItem::~cMenuRecordingItem()
 {
-  free(fileName);
   free(name);
 }
 
@@ -2709,11 +2079,13 @@ void cMenuRecordingItem::IncrementCounter(bool New)
   totalEntries++;
   if (New)
      newEntries++;
-#if VDRVERSNUM < 10721
-  SetText(cString::sprintf("%d\t%d\t%s", totalEntries, newEntries, name));
-#else
   SetText(cString::sprintf("%d\t\t%d\t%s", totalEntries, newEntries, name));
-#endif
+}
+
+void cMenuRecordingItem::SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
+{
+  if (!RemoteTimersSetup.skinRecordings || !DisplayMenu->SetItemRecording(recording, Index, Current, Selectable, level, totalEntries, newEntries))
+     DisplayMenu->SetItem(Text(), Index, Current, Selectable);
 }
 
 // --- cMenuRecordings -------------------------------------------------------
@@ -2722,16 +2094,9 @@ int cMenuRecordings::userFilter = 0;
 bool cMenuRecordings::replayEnded = false;
 
 cMenuRecordings::cMenuRecordings(const char *Base, int Level, bool OpenSubMenus)
-#if VDRVERSNUM < 10721
-:cOsdMenu(Base ? Base : tr("Recordings"), 9, 7)
-#else
 :cOsdMenu(Base ? Base : tr("Recordings"), 9, 6, 6)
-#endif
 {
-#if VDRVERSNUM >= 10728
-  // with mcRecording some skins would add free diskspace to title
-  SetMenuCategory(mcPlugin);
-#endif
+  SetMenuCategory(RemoteTimersSetup.skinRecordings ? mcRecording : mcPlugin);
   base = Base ? strdup(Base) : NULL;
   level = ::Setup.RecordingDirs ? Level : -1;
   if (level <= 0 && !replayEnded)
@@ -2759,11 +2124,7 @@ cMenuRecordings::~cMenuRecordings()
 
 bool cMenuRecordings::SetFreeDiskDisplay(bool Force)
 {
-#if VDRVERSNUM >= 10515
   if (FreeDiskSpace.HasChanged(base, Force)) {
-#else
-  if (FreeDiskSpace.HasChanged(Force)) {
-#endif
      //XXX -> skin function!!!
      if (userFilter == 0)
         SetTitle(cString::sprintf("%s - %s", base ? base : tr("Recordings"), FreeDiskSpace.FreeDiskSpaceString()));
@@ -2784,8 +2145,7 @@ void cMenuRecordings::SetHelpKeys(void)
         NewHelpKeys = 1;
      else {
         NewHelpKeys = 2;
-        cRecording *recording = GetRecording(ri);
-        if (recording && recording->Info()->Title())
+        if (ri->Recording()->Info()->Title())
            NewHelpKeys = 3;
         if (userFilter != 0 && ri->User() != 0 && ri->User() != USER_MASK(userFilter))
 	   NewHelpKeys |= B_RELEASE;
@@ -2808,17 +2168,13 @@ void cMenuRecordings::Set(bool Refresh)
 {
   const char *CurrentRecording = cReplayControl::LastReplayed();
   cMenuRecordingItem *LastItem = NULL;
-  char *LastItemText = NULL;
   cThreadLock RecordingsLock(&Recordings);
   if (Refresh) {
-     cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
-     if (ri) {
-        cRecording *Recording = Recordings.GetByName(ri->FileName());
-        if (Recording)
-           CurrentRecording = Recording->FileName();
-        }
+     if (cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()))
+        CurrentRecording = ri->Recording()->FileName();
      }
   Clear();
+  GetRecordingsSortMode(DirectoryName());
   Recordings.Sort();
   for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) {
       int user = ParseUser(recording->Info()->Aux());
@@ -2826,34 +2182,46 @@ void cMenuRecordings::Set(bool Refresh)
          continue;
       if (!base || (strstr(recording->Name(), base) == recording->Name() && recording->Name()[strlen(base)] == FOLDERDELIMCHAR)) {
          cMenuRecordingItem *Item = new cMenuRecordingItem(recording, level, user);
-         if (*Item->Text() && (!Item->IsDirectory() || (!LastItem || !LastItem->IsDirectory() || strcmp(Item->Text(), LastItemText) != 0))) {
+         cMenuRecordingItem *LastDir = NULL;
+         if (Item->IsDirectory()) {
+            // Sorting may ignore non-alphanumeric characters, so we need to explicitly handle directories in case they only differ in such characters:
+            for (cMenuRecordingItem *p = LastItem; p; p = dynamic_cast<cMenuRecordingItem *>(p->Prev())) {
+                if (p->Name() && strcmp(p->Name(), Item->Name()) == 0) {
+                   LastDir = p;
+                   break;
+                   }
+                }
+            }
+         if (*Item->Text() && !LastDir) {
             Add(Item);
             LastItem = Item;
-            free(LastItemText);
-            LastItemText = strdup(LastItem->Text()); // must use a copy because of the counters!
+            if (Item->IsDirectory())
+               LastDir = Item;
             }
          else
             delete Item;
-         if (LastItem) {
+         if (LastItem || LastDir) {
             if (CurrentRecording && strcmp(CurrentRecording, recording->FileName()) == 0)
-               SetCurrent(LastItem);
-            if (LastItem->IsDirectory())
-               LastItem->IncrementCounter(recording->IsNew());
+               SetCurrent(LastDir ? LastDir : LastItem);
             }
+         if (LastDir)
+            LastDir->IncrementCounter(recording->IsNew());
          }
       }
-  free(LastItemText);
   Refresh |= SetFreeDiskDisplay(Refresh);
   if (Refresh)
      Display();
 }
 
-cRecording *cMenuRecordings::GetRecording(cMenuRecordingItem *Item)
+cString cMenuRecordings::DirectoryName(void)
 {
-  cRecording *recording = Recordings.GetByName(Item->FileName());
-  if (!recording)
-     Skins.Message(mtError, tr("Error while accessing recording!"));
-  return recording;
+  cString d(VideoDirectory);
+  if (base) {
+     char *s = ExchangeChars(strdup(base), true);
+     d = AddDirectory(d, s);
+     free(s);
+     }
+  return d;
 }
 
 bool cMenuRecordings::Open(bool OpenSubMenus)
@@ -2879,19 +2247,12 @@ eOSState cMenuRecordings::Play(void)
      if (ri->IsDirectory())
         Open();
      else {
-        cRecording *recording = GetRecording(ri);
-        if (recording) {
-#if VDRVERSNUM < 10728
-           cReplayControl::SetRecording(recording->FileName(), recording->Title());
-#else
-           cReplayControl::SetRecording(recording->FileName());
-#endif
-	   // use our own replay control which returns to this recordings menu
-	   cControl::Shutdown();
-	   cControl::Launch(new cRemoteTimersReplayControl(cMenuMain::IsOpen()));
-	   return osEnd;
-           // return osReplay;
-           }
+        cReplayControl::SetRecording(ri->Recording()->FileName());
+	// use our own replay control which returns to this recordings menu
+	cControl::Shutdown();
+	cControl::Launch(new cRemoteTimersReplayControl(cMenuMain::IsOpen()));
+	return osEnd;
+        // return osReplay;
         }
      }
   return osContinue;
@@ -2903,17 +2264,10 @@ eOSState cMenuRecordings::Rewind(void)
      return osContinue;
   cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
   if (ri && !ri->IsDirectory()) {
-     cRecording *recording = GetRecording(ri);
-     if (recording) {
-        cDevice::PrimaryDevice()->StopReplay(); // must do this first to be able to rewind the currently replayed recording
-#if VDRVERSNUM >= 10703
-        cResumeFile ResumeFile(ri->FileName(), recording->IsPesRecording());
-#else
-        cResumeFile ResumeFile(ri->FileName());
-#endif
-        ResumeFile.Delete();
-        return Play();
-        }
+     cDevice::PrimaryDevice()->StopReplay(); // must do this first to be able to rewind the currently replayed recording
+     cResumeFile ResumeFile(ri->Recording()->FileName(), ri->Recording()->IsPesRecording());
+     ResumeFile.Delete();
+     return Play();
      }
   return osContinue;
 }
@@ -2925,24 +2279,21 @@ eOSState cMenuRecordings::Delete(void)
   cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
   if (ri && !ri->IsDirectory()) {
      if (userFilter != 0 && ri->User() != 0 && ri->User() != USER_MASK(userFilter)) {
-        cRecording *recording = Recordings.GetByName(ri->FileName());
-        if (recording) {
-	   if (cMenuEditRecording::UpdateUser(recording, ri->User() ^ USER_MASK(userFilter))) {
-              cReplayControl::ClearLastReplayed(ri->FileName());
-              Recordings.Del(recording);
-              Recordings.AddByName(ri->FileName());
-              cOsdMenu::Del(Current());
-              SetHelpKeys();
-              Display();
-              if (!Count())
-                 return osBack;
-	      }
+        cRecording *recording = ri->Recording();
+        cString FileName = recording->FileName();
+	if (cMenuEditRecording::UpdateUser(recording, ri->User() ^ USER_MASK(userFilter))) {
+           cReplayControl::ClearLastReplayed(FileName);
+           Recordings.Del(recording);
+           Recordings.AddByName(FileName);
+           cOsdMenu::Del(Current());
+           SetHelpKeys();
+           Display();
+           if (!Count())
+              return osBack;
 	   }
-	else
-           Skins.Message(mtError, tr("Error while accessing recording!"));
 	}
      else if (Interface->Confirm(tr("Delete recording?"))) {
-        cRecordControl *rc = cRecordControls::GetRecordControl(ri->FileName());
+        cRecordControl *rc = cRecordControls::GetRecordControl(ri->Recording()->FileName());
         if (rc) {
            if (Interface->Confirm(tr("Timer still recording - really delete?"))) {
               cTimer *timer = rc->Timer();
@@ -2959,40 +2310,33 @@ eOSState cMenuRecordings::Delete(void)
            else
               return osContinue;
            }
-        cRecording *recording = GetRecording(ri);
-        if (recording) {
-#if VDRVERSNUM >= 10724
-           if (cCutter::Active(ri->FileName())) {
-              if (Interface->Confirm(tr("Recording is being edited - really delete?"))) {
-                 cCutter::Stop();
-                 recording = Recordings.GetByName(ri->FileName()); // cCutter::Stop() might have deleted it if it was the edited version
-                 // we continue with the code below even if recording is NULL,
-                 // in order to have the menu updated etc.
-                 }
-              else
-                 return osContinue;
-              }
-#endif
-#if VDRVERSNUM >= 10515
-           if (cReplayControl::NowReplaying() && strcmp(cReplayControl::NowReplaying(), ri->FileName()) == 0)
-              cControl::Shutdown();
-#endif
-           if (!recording || recording->Delete()) {
-              cReplayControl::ClearLastReplayed(ri->FileName());
-              Recordings.DelByName(ri->FileName());
-              cOsdMenu::Del(Current());
-              SetHelpKeys();
-              SetFreeDiskDisplay(true);
-#if VDRVERSNUM >= 10728
-              cVideoDiskUsage::ForceCheck();
-#endif
-              Display();
-              if (!Count())
-                 return osBack;
+        cRecording *recording = ri->Recording();
+        cString FileName = recording->FileName();
+        if (cCutter::Active(ri->Recording()->FileName())) {
+           if (Interface->Confirm(tr("Recording is being edited - really delete?"))) {
+              cCutter::Stop();
+              recording = Recordings.GetByName(FileName); // cCutter::Stop() might have deleted it if it was the edited version
+              // we continue with the code below even if recording is NULL,
+              // in order to have the menu updated etc.
               }
            else
-              Skins.Message(mtError, tr("Error while deleting recording!"));
+              return osContinue;
            }
+        if (cReplayControl::NowReplaying() && strcmp(cReplayControl::NowReplaying(), FileName) == 0)
+           cControl::Shutdown();
+        if (!recording || recording->Delete()) {
+           cReplayControl::ClearLastReplayed(FileName);
+           Recordings.DelByName(FileName);
+           cOsdMenu::Del(Current());
+           SetHelpKeys();
+           SetFreeDiskDisplay(true);
+           cVideoDiskUsage::ForceCheck();
+           Display();
+           if (!Count())
+              return osBack;
+           }
+        else
+           Skins.Message(mtError, tr("Error while deleting recording!"));
         }
      }
   return osContinue;
@@ -3003,11 +2347,8 @@ eOSState cMenuRecordings::Info(void)
   if (HasSubMenu() || Count() == 0)
      return osContinue;
   cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
-  if (ri && !ri->IsDirectory()) {
-     cRecording *recording = GetRecording(ri);
-     if (recording && recording->Info()->Title())
-        return AddSubMenu(new cMenuRecording(recording, true));
-     }
+  if (ri && !ri->IsDirectory() && ri->Recording()->Info()->Title())
+     return AddSubMenu(new cMenuRecording(ri->Recording(), true));
   return osContinue;
 }
 
@@ -3017,11 +2358,8 @@ eOSState cMenuRecordings::Edit(void)
      return osContinue;
   cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
   if (ri && !ri->IsDirectory()) {
-     cRecording *recording = GetRecording(ri);
-     if (recording) {
-        cThreadLock RecordingsLock(&Recordings);
-        return AddSubMenu(new cMenuEditRecording(recording));
-        }
+     cThreadLock RecordingsLock(&Recordings);
+     return AddSubMenu(new cMenuEditRecording(ri->Recording()));
      }
   return osContinue;
 }
@@ -3033,19 +2371,25 @@ eOSState cMenuRecordings::Commands(eKeys Key)
      return osContinue;
   cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
   if (ri && !ri->IsDirectory()) {
-     cRecording *recording = GetRecording(ri);
-     if (recording) {
-        cMenuCommands *menu;
-        eOSState state = AddSubMenu(menu = new cMenuCommands(tr("Recording commands"), &RecordingCommands, cString::sprintf("\"%s\"", *strescape(recording->FileName(), "\\\"$"))));
-        if (Key != kNone)
-           state = menu->ProcessKey(Key);
-        return state;
-        }
+     cMenuCommands *menu;
+     eOSState state = AddSubMenu(menu = new cMenuCommands(tr("Recording commands"), &RecordingCommands, cString::sprintf("\"%s\"", *strescape(ri->Recording()->FileName(), "\\\"$"))));
+     if (Key != kNone)
+        state = menu->ProcessKey(Key);
+     return state;
      }
   return osContinue;
 }
 */
 
+eOSState cMenuRecordings::Sort(void)
+{
+  if (HasSubMenu())
+     return osContinue;
+  IncRecordingsSortMode(DirectoryName());
+  Set(true);
+  return osContinue;
+}
+
 eOSState cMenuRecordings::ProcessKey(eKeys Key)
 {
   bool HadSubMenu = HasSubMenu();
@@ -3053,6 +2397,7 @@ eOSState cMenuRecordings::ProcessKey(eKeys Key)
 
   if (state == osUnknown) {
      switch (Key) {
+       case kPlayPause:
        case kPlay:
        case kOk:     return Play();
        //case kRed:    return (helpKeys > 1 && RecordingCommands.Count()) ? Commands() : Play();
@@ -3061,8 +2406,11 @@ eOSState cMenuRecordings::ProcessKey(eKeys Key)
        case kYellow: return Delete();
        case kInfo:
        case kBlue:   return Info();
+       //case k0:      return Sort();
        //case k1...k9: return Commands(Key);
        case k0 ... k9:
+                     if (userFilter == Key - k0)
+                        return Sort();
                      userFilter = Key - k0;
 		     if (RemoteTimersSetup.userFilterRecordings < 0 && ::Setup.ResumeID != Key - k0) {
 		        ::Setup.ResumeID = Key - k0;
@@ -3102,9 +2450,7 @@ int cMenuMain::count = 0;
 cMenuMain::cMenuMain(const char *Title, eOSState State)
 :cOsdMenu(Title)
 {
-#if VDRVERSNUM >= 10728
-  SetMenuCategory(mcPlugin);
-#endif
+  SetMenuCategory(mcMain);
   count++;
   SetHasHotkeys();
   Add(new cOsdItem(hk(tr("Schedule")),   osUser1));
@@ -3129,11 +2475,7 @@ eOSState cMenuMain::ProcessKey(eKeys Key)
     case osUser1:      return AddSubMenu(new cMenuSchedule);
     case osUser2:      return AddSubMenu(new cMenuTimers);
     case osUser3:      return AddSubMenu(new cMenuRecordings);
-#if VDRVERSNUM >= 10404
     case osUser4:      cMoveRec::Abort(-1); return osBack;
-#else
-    case osUser4:      cMoveRec::Abort(10); return osBack;
-#endif
     default:           return state;
     }
 }
diff --git a/menu.h b/menu.h
index d4fc670..8289e99 100644
--- a/menu.h
+++ b/menu.h
@@ -36,88 +36,24 @@ namespace PluginRemoteTimers {
 
 #define MSG_UNAVAILABLE trNOOP("Remote timers not available")
 
-cTimer* GetBestMatch(const cEvent *Event, int UserMask, int *Match, int *Type, bool *Remote);
-
-#if APIVERSNUM < 10712
-
-// copy of VDR's cNestedItem / cNestedItemList
-
-class cNestedItem : public cListObject {
-private:
-  char *text;
-  cList<cNestedItem> *subItems;
-public:
-  cNestedItem(const char *Text, bool WithSubItems = false);
-  virtual ~cNestedItem();
-  virtual int Compare(const cListObject &ListObject) const;
-  const char *Text(void) const { return text; }
-  cList<cNestedItem> *SubItems(void) { return subItems; }
-  void AddSubItem(cNestedItem *Item);
-  void SetText(const char *Text);
-  void SetSubItems(bool On);
-  };
-
-class cNestedItemList : public cList<cNestedItem> {
-private:
-  char *fileName;
-  bool Parse(FILE *f, cList<cNestedItem> *List, int &Line);
-  bool Write(FILE *f, cList<cNestedItem> *List, int Indent = 0);
-public:
-  cNestedItemList(void);
-  virtual ~cNestedItemList();
-  void Clear(void);
-  bool Load(const char *FileName);
-  bool Save(void);
-  };
-
-// copy of VDR's cMenuFolder
-
-class cMenuEditFolder;
-
-class cMenuFolder : public cOsdMenu {
-private:
-  // cOsdMenu::Title() and cOsdMenu::SubMenu() missing in < 10712
-  cString title;
-  cMenuFolder *subMenuFolder;
-  cMenuEditFolder *subMenuEditFolder;
-
-  cNestedItemList *nestedItemList;
-  cList<cNestedItem> *list;
-  cString dir;
-  cOsdItem *firstFolder;
-  bool editing;
-  void SetHelpKeys(void);
-  void Set(const char *CurrentFolder = NULL);
-  void DescendPath(const char *Path);
-  eOSState SetFolder(void);
-  eOSState Select(void);
-  eOSState New(void);
-  eOSState Delete(void);
-  eOSState Edit(void);
-  cMenuFolder(const char *Title, cList<cNestedItem> *List, cNestedItemList *NestedItemList, const char *Dir, const char *Path = NULL);
-public:
-  cMenuFolder(const char *Title, cNestedItemList *NestedItemList, const char *Path = NULL);
-  cString GetFolder(void);
-  virtual eOSState ProcessKey(eKeys Key);
-  };
-
-extern cNestedItemList Folders;
-
-#endif
+cTimer* GetBestMatch(const cEvent *Event, int UserMask, eTimerMatch *Match, int *Type, bool *Remote);
 
 class cMenuTimerItem : public cOsdItem {
 private:
   cTimer *timer;
   bool remote;
   int user;
+  bool conflict;
 public:
   cMenuTimerItem(cTimer *Timer, int User, bool Remote);
   void Update(cTimer *Timer, int User, bool Remote);
+  bool UpdateConflict();
   virtual int Compare(const cListObject &ListObject) const;
   virtual void Set(void);
   int User() { return user; }
   bool Remote() { return remote; }
   cTimer *Timer(void) { return timer; }
+  virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable);
 
   static int ParseUser(const cTimer *Timer);
   static void UpdateUser(cTimer &Timer, int User);
@@ -139,8 +75,9 @@ private:
   void SetHelpKeys(void);
   void Set(eRemoteTimersState State = rtsOk);
   void CheckState(eRemoteTimersState State, bool RefreshMsg = true);
+  bool UpdateConflicts(bool Remote);
 public:
-  cMenuTimers(void);
+  cMenuTimers(const char* ServerIp = NULL, unsigned short ServerPort = 0);
   virtual ~cMenuTimers();
   virtual eOSState ProcessKey(eKeys Key);
   };
@@ -149,7 +86,9 @@ class cMenuSchedule : public cOsdMenu {
 private:
   cSchedulesLock schedulesLock;
   const cSchedules *schedules;
-  bool now, next;
+  // bool now, next;
+  int whatsOnId; // -1: init, 0..EPGTIME_LENGTH-1: custom,
+                 // EPGTIME_LENGTH: now, EPGTIME_LENGTH+1: next
   int otherChannel;
   int helpKeys;
   int timerState;
@@ -164,7 +103,7 @@ private:
   bool Update(void);
   void SetHelpKeys(void);
 public:
-  cMenuSchedule(void);
+  cMenuSchedule(const char* ServerIp = NULL, unsigned short ServerPort = 0);
   virtual ~cMenuSchedule();
   virtual eOSState ProcessKey(eKeys Key);
   };
@@ -198,9 +137,10 @@ private:
   eOSState Delete(void);
   eOSState Info(void);
   eOSState Edit(void);
+  eOSState Sort(void);
   //eOSState Commands(eKeys Key = kNone);
 protected:
-  cRecording *GetRecording(cMenuRecordingItem *Item);
+  cString DirectoryName(void);
 public:
   static void SetReplayEnded() { replayEnded = true; }
   static bool ReplayEnded() { return replayEnded; }
diff --git a/menuitems.c b/menuitems.c
index 2c38272..b8805dc 100644
--- a/menuitems.c
+++ b/menuitems.c
@@ -21,9 +21,7 @@
 
 #include "menuitems.h"
 #include <ctype.h>
-#if VDRVERSNUM >10503
 #include <wctype.h>
-#endif
 #include <stdlib.h>
 #include <vdr/remote.h>
 
diff --git a/moverec.c b/moverec.c
index 2e244db..f9a8c3e 100644
--- a/moverec.c
+++ b/moverec.c
@@ -211,9 +211,7 @@ bool cMoveRec::Move(const cRecording* Recording, const char* DstDir)
 void cMoveRec::Action()
 {
 	SetPriority(19);
-#if VDRVERSNUM >= 10706
 	SetIOPriority(7);
-#endif
 	cReadDir dir(srcDir);
 	if (dir.Ok()) {
 		if (MakeDirs(dstDir, true)) {
diff --git a/patches/vdr-1.4.x-1.7.27-remote_instant_recordings.patch b/patches/vdr-1.4.x-1.7.27-remote_instant_recordings.patch
deleted file mode 100644
index 71db914..0000000
--- a/patches/vdr-1.4.x-1.7.27-remote_instant_recordings.patch
+++ /dev/null
@@ -1,124 +0,0 @@
-This is a "patch" for the Video Disk Recorder (VDR).
-
-* Description:
-Apply this patch to VDR if you want to redirect instant recordings to an
-other (server) VDR. This applies to recordings started with the "Record"
-button and paused live TV.
-
-* Requirements:
-The patch relies on either the timersync-plugin or the remotetimers-plugin.
-One of them must be installed on the client.
-
-If the timersync-plugin is installed, the timer for the instant recording
-is added to the local timers list. No recording is started. It is then
-the plugin's job to copy the timer to the server VDR. The local video
-directory must be a network mount of the server's video directory. Otherwise
-the immediate replay of a paused live view will fail.
-
-With the remotetimers-plugin, redirecting instant recordings must be enabled
-in remotetimers' setup. It is possible to handle instant recordings and
-paused live TV differently. Note that you need to (re-)compile the plugin
-after VDR has been patched. Otherwise the setup options won't be available.
-
-* Installation
-Change into the VDR source directory, then issue
-  patch -p0 < path/to/vdr-remote_instant_recordings.patch
-and recompile.
-
---- config.h.orig	2007-08-04 23:22:47.000000000 +0200
-+++ config.h	2008-06-27 20:25:47.000000000 +0200
-@@ -39,2 +39,4 @@
- 
-+#define REMOTEINSTANTVERSION 1.0
-+
- #define MAXPRIORITY 99
---- menu.c.orig	2008-06-27 20:30:14.000000000 +0200
-+++ menu.c	2008-06-27 20:31:01.000000000 +0200
-@@ -29,6 +29,8 @@
- #include "transfer.h"
- #include "videodir.h"
- 
-+#include "remotetimers.h"
-+
- #define MAXWAIT4EPGINFO   3 // seconds
- #define MODETIMEOUT       3 // seconds
- #define DISKSPACECHEK     5 // seconds between disk space checks in the main menu
-@@ -3694,6 +3723,50 @@
- 
- bool cRecordControls::Start(cTimer *Timer, bool Pause)
- {
-+  if (!Timer) {
-+     cTimer *t = new cTimer(true, Pause);
-+
-+     //get event
-+     cSchedulesLock SchedulesLock;
-+     const cEvent *event = NULL;;
-+     const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock);
-+     if (Schedules) {
-+        const cSchedule *Schedule = Schedules->GetSchedule(t->Channel());
-+        if (Schedule) {
-+           event = Schedule->GetEventAround(t->StartTime() + INSTANT_REC_EPG_LOOKAHEAD);
-+        }
-+     }
-+
-+     if (cPluginManager::GetPlugin("timersync")) {
-+        // sets the file name
-+        cRecording recording(t, event);
-+        Timers.Add(t);
-+        Timers.SetModified();
-+        if (!cReplayControl::LastReplayed())
-+           cReplayControl::SetRecording(recording.FileName(), recording.Name());
-+        return true;
-+     }
-+     else {
-+        RemoteTimers_InstantRecording_v1_0 ir;
-+        ir.timer = t;
-+        ir.pause = Pause;
-+        ir.event = event;
-+        ir.name = NULL;
-+        ir.fileName = NULL;
-+ 
-+        if (cPluginManager::CallFirstService("RemoteTimers::InstantRecording-v1.0", &ir)) {
-+           if (!cReplayControl::LastReplayed())
-+              cReplayControl::SetRecording(ir.fileName, ir.name);
-+ 	  delete t;
-+ 	  // empty names indicate an error
-+ 	  return *ir.fileName && *ir.name;
-+        }
-+        // service disabled or an error occured and the user confirmed local recording
-+        // fall through to local instant recording
-+     }
-+     delete t;
-+  }
-+
-   static time_t LastNoDiskSpaceMessage = 0;
-   int FreeMB = 0;
-   if (Timer) {
---- /dev/null	2008-06-27 20:13:35.796049750 +0200
-+++ remotetimers.h	2008-06-26 21:20:49.000000000 +0200
-@@ -0,0 +1,25 @@
-+/*
-+ * remotetimers.h: Public interface of the plugin's services
-+ *
-+ * See the README file for copyright information and how to reach the author.
-+ */
-+
-+#ifndef _SERVICE__H
-+#define _SERVICE__H
-+
-+#ifndef __TIMERS_H
-+#include <vdr/timer.h>
-+#include <vdr/epg.h>
-+#endif
-+
-+struct RemoteTimers_InstantRecording_v1_0 {
-+//in
-+	const cTimer	*timer;
-+	bool		pause;
-+	const cEvent	*event;
-+//out
-+	cString		name;
-+	cString		fileName;
-+};
-+
-+#endif //_SERVICE__H
diff --git a/patches/vdr-1.5.15-1.7.9-video_on_networkshare.diff b/patches/vdr-1.5.15-1.7.9-video_on_networkshare.diff
deleted file mode 100644
index ba67fbb..0000000
--- a/patches/vdr-1.5.15-1.7.9-video_on_networkshare.diff
+++ /dev/null
@@ -1,33 +0,0 @@
-This is a "patch" for the Video Disk Recorder (VDR).
-
-* Description:
-Apply this patch to VDR if its video directory is a mounted network share.
-It changes the way VDR checks for different filesystems. The current method
-fails if the video directory and at least one of its subdirectories are
-network mounts of different shares. In this case the calculated amount of
-free diskspace will not always be accurate.
-
-* Installation
-Change into the VDR source directory, then issue
-  patch -p0 < path/to/vdr-1.5.15-1.7.9-video_on_networkshare.diff
-and recompile.
-
---- tools.c.orig	2009-11-02 12:44:36.000000000 +0100
-+++ tools.c	2009-11-02 13:44:27.000000000 +0100
-@@ -279,11 +279,11 @@
- 
- bool EntriesOnSameFileSystem(const char *File1, const char *File2)
- {
--  struct statfs statFs;
--  if (statfs(File1, &statFs) == 0) {
--     fsid_t fsid1 = statFs.f_fsid;
--     if (statfs(File2, &statFs) == 0)
--        return memcmp(&statFs.f_fsid, &fsid1, sizeof(fsid1)) == 0;
-+  struct stat st;
-+  if (stat(File1, &st) == 0) {
-+     dev_t dev1 = st.st_dev;
-+     if (stat(File2, &st) == 0)
-+        return st.st_dev == dev1;
-      else
-         LOG_ERROR_STR(File2);
-      }
diff --git a/patches/vdr-1.7.28-skinlcars.patch b/patches/vdr-1.7.29-skinlcars.patch
similarity index 86%
rename from patches/vdr-1.7.28-skinlcars.patch
rename to patches/vdr-1.7.29-skinlcars.patch
index 77cc8ea..84b42e6 100644
--- a/patches/vdr-1.7.28-skinlcars.patch
+++ b/patches/vdr-1.7.29-skinlcars.patch
@@ -31,7 +31,7 @@ and recompile.
  #include "symbols/arrowdown.xpm"
  #include "symbols/arrowup.xpm"
  #include "symbols/audio.xpm"
-@@ -1142,12 +1155,25 @@
+@@ -1158,12 +1171,25 @@
  
  void cSkinLCARSDisplayMenu::DrawTimers(void)
  {
@@ -56,9 +56,9 @@ and recompile.
 +        SortedTimers.Sort(PluginRemoteTimers::CompareTimers);
 +        }
       cVector<int> FreeDeviceSlots;
+      int NumDevices = 0;
       int y = ys04;
-      // Timers and recording devices:
-@@ -1158,7 +1184,7 @@
+@@ -1175,7 +1201,7 @@
                 if (y + lineHeight > ys05)
                    break;
                 if (const cTimer *Timer = SortedTimers[i]) {
@@ -67,10 +67,10 @@ and recompile.
                       if (cRecordControl *RecordControl = cRecordControls::GetRecordControl(Timer)) {
                          if (!Device || Device == RecordControl->Device()) {
                             DrawTimer(Timer, y, NumTimers > 0);
-@@ -1206,6 +1232,8 @@
+@@ -1233,6 +1259,8 @@
           }
-      osd->DrawText(xs02, ys00, itoa(Timers.Count()), Theme.Color(clrMenuFrameFg), frameColor, font, xs03 - xs02, ys01 - ys00, taBottom | taLeft | taBorder);
-      osd->DrawText(xs08, ys00, itoa(cDevice::NumDevices()), Theme.Color(clrMenuFrameFg), frameColor, font, xs09 - xs08, ys01 - ys00, taBottom | taRight | taBorder);
+      osd->DrawText(xs02, ys00, itoa(NumTimers), Theme.Color(clrMenuFrameFg), frameColor, font, xs03 - xs02, ys01 - ys00, taBottom | taLeft | taBorder);
+      osd->DrawText(xs08, ys00, itoa(NumDevices), Theme.Color(clrMenuFrameFg), frameColor, font, xs09 - xs08, ys01 - ys00, taBottom | taRight | taBorder);
 +     if (*errorMsg)
 +        SetMessage(mtError, *errorMsg);
       lastSignalDisplay = 0;
diff --git a/po/de_DE.po b/po/de_DE.po
index 8e84d1b..23ac168 100644
--- a/po/de_DE.po
+++ b/po/de_DE.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: VDR 1.5.7\n"
 "Report-Msgid-Bugs-To: <vdrdev at schmirler.de>\n"
-"POT-Creation-Date: 2012-06-07 01:07+0200\n"
+"POT-Creation-Date: 2013-08-04 11:41+0200\n"
 "PO-Revision-Date: 2008-02-20 11:48+0100\n"
 "Last-Translator: Frank Schmirler <vdrdev at schmirler.de>\n"
 "Language-Team: <vdr at linuxtv.org>\n"
@@ -16,31 +16,6 @@ msgstr ""
 "Content-Type: text/plain; charset=ISO-8859-15\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-msgid "Edit folder"
-msgstr "Verzeichnis editieren"
-
-msgid "New folder"
-msgstr "Neues Verzeichnis"
-
-msgid "Sub folder"
-msgstr "Unterverzeichnis"
-
-msgid "Folder name already exists!"
-msgstr "Verzeichnisname existiert bereits!"
-
-#, c-format
-msgid "Folder name must not contain '%c'!"
-msgstr "Verzeichnisname darf kein '%c' enthalten!"
-
-msgid "Button$Select"
-msgstr "Ausw�hlen"
-
-msgid "Delete folder and all sub folders?"
-msgstr "Verzeichnis und alle Unterverzeichnisse l�schen?"
-
-msgid "Delete folder?"
-msgstr "Verzeichnis l�schen?"
-
 msgid "Location"
 msgstr "Aufnahmeort"
 
@@ -53,15 +28,13 @@ msgstr "Server"
 msgid "User ID"
 msgstr "Benutzer-ID"
 
-msgid "Button$Folder"
-msgstr "Verzeichnis"
+#, c-format
+msgid "%.10s\tConflict (Recording %d%%)"
+msgstr "%.10s\tKonflikt (%d%% werden aufgenommen)"
 
 msgid "Timer is recording - can't move it to server"
 msgstr "Timer nimmt gerade auf - auf Server verschieben nicht m�glich"
 
-msgid "Select folder"
-msgstr "Verzeichnis w�hlen"
-
 #. TRANSLATORS: Indicator for (R)emote or (L)ocal timer in timers list
 msgid "RL"
 msgstr "SL"
@@ -77,6 +50,10 @@ msgstr "Abmelden"
 msgid " tTpP"
 msgstr " tTpP"
 
+#, c-format
+msgid "What's on at %s?"
+msgstr "Was l�uft um %s?"
+
 msgid "Edit recording"
 msgstr "Aufzeichnung editieren"
 
@@ -95,9 +72,15 @@ msgstr "Fehler beim Umbenennen der Aufzeichnung"
 msgid "Move to other filesystem in background?"
 msgstr "Im Hintergrund auf anderes Dateisystem verschieben?"
 
+msgid "Button$Folder"
+msgstr "Verzeichnis"
+
 msgid "Cut"
 msgstr "Schneiden"
 
+msgid "Select folder"
+msgstr "Verzeichnis w�hlen"
+
 #. TRANSLATORS: Button displayed instead of "Delete" when there are other users who didn't watch the recording yet
 msgid "Release"
 msgstr "Freigeben"
@@ -105,6 +88,9 @@ msgstr "Freigeben"
 msgid "Abort moving recording"
 msgstr "Aufzeichnung verschieben abbrechen"
 
+msgid "Remote timers not available"
+msgstr "Timer des Servers nicht verf�gbar"
+
 msgid "Finished moving recording"
 msgstr "Aufzeichnung verschoben"
 
@@ -144,10 +130,6 @@ msgstr "Kanal-ID"
 msgid "Hide mainmenu entry"
 msgstr "Hauptmen�eintrag verstecken"
 
-#, c-format
-msgid "Replace mainmenu \"%s\""
-msgstr "Hauptmen� \"%s\" ersetzen"
-
 msgid "Defaults for new timers"
 msgstr "Voreinstellungen f�r neue Timer"
 
@@ -157,23 +139,28 @@ msgstr "Direktaufzeichnungen"
 msgid "Pause recordings"
 msgstr "Live-Signal anhalten"
 
-msgid "Settings for menu"
-msgstr "Einstellungen f�r das Men�"
-
 #, c-format
-msgid "Binding of %s/%s in \"What's on\" menus"
-msgstr "Funktion von %s/%s in \"Was l�uft\"-Men�s"
+msgid "Settings for menu \"%s\""
+msgstr "Einstellungen f�r das Men� \"%s\""
 
-#, c-format
-msgid "Show progress bar in menu \"%s\""
-msgstr "Fortschrittsanzeige im Men� \"%s\""
+msgid "Replace mainmenu"
+msgstr "Hauptmen� ersetzen"
+
+msgid "List style"
+msgstr "Darstellung der Liste"
+
+msgid "Show progress bar"
+msgstr "Fortschrittsanzeige"
 
 #, c-format
-msgid "User ID filter in menu \"%s\""
-msgstr "Benutzer-Filter im Men� \"%s\""
+msgid "Key binding of %s/%s"
+msgstr "Funktion der Tasten %s/%s"
+
+msgid "User ID filter"
+msgstr "Benutzer-Filter"
 
 msgid "Move recording bandwidth limit (Mbit/s)"
-msgstr "Bandbreite Aufzeichnung verschieben (Mbit/s)"
+msgstr "Max. Bandbreite beim Verschieben (Mbit/s)"
 
 msgid "unlimited"
 msgstr "unbegrenzt"
@@ -220,5 +207,26 @@ msgstr "Unerwarteter Fehler - kann Schnitt auf Server nicht starten"
 msgid "Lost SVDRP connection - unable to start remote cutter"
 msgstr "SVDRP-Verbindung verloren - kann Schnitt auf Server nicht starten"
 
-msgid "Remote timers not available"
-msgstr "Timer des Servers nicht verf�gbar"
+#~ msgid "Edit folder"
+#~ msgstr "Verzeichnis editieren"
+
+#~ msgid "New folder"
+#~ msgstr "Neues Verzeichnis"
+
+#~ msgid "Sub folder"
+#~ msgstr "Unterverzeichnis"
+
+#~ msgid "Folder name already exists!"
+#~ msgstr "Verzeichnisname existiert bereits!"
+
+#~ msgid "Folder name must not contain '%c'!"
+#~ msgstr "Verzeichnisname darf kein '%c' enthalten!"
+
+#~ msgid "Button$Select"
+#~ msgstr "Ausw�hlen"
+
+#~ msgid "Delete folder and all sub folders?"
+#~ msgstr "Verzeichnis und alle Unterverzeichnisse l�schen?"
+
+#~ msgid "Delete folder?"
+#~ msgstr "Verzeichnis l�schen?"
diff --git a/po/it_IT.po b/po/it_IT.po
index 150375b..16ab36a 100644
--- a/po/it_IT.po
+++ b/po/it_IT.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: VDR 1.5.7\n"
 "Report-Msgid-Bugs-To: <vdrdev at schmirler.de>\n"
-"POT-Creation-Date: 2012-06-07 01:07+0200\n"
+"POT-Creation-Date: 2013-08-04 11:41+0200\n"
 "PO-Revision-Date: 2012-06-07 20:30+0100\n"
 "Last-Translator: Diego Pierotto <vdr-italian at tiscali.it>\n"
 "Language-Team:  <vdr at linuxtv.org>\n"
@@ -16,31 +16,6 @@ msgstr ""
 "Content-Type: text/plain; charset=ISO-8859-15\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-msgid "Edit folder"
-msgstr "Modifica cartella"
-
-msgid "New folder"
-msgstr "Nuova cartella"
-
-msgid "Sub folder"
-msgstr "Sottocartella"
-
-msgid "Folder name already exists!"
-msgstr "Nome cartella gi� esistente!"
-
-#, c-format
-msgid "Folder name must not contain '%c'!"
-msgstr "Il nome cartella non pu� contenere '%c'!"
-
-msgid "Button$Select"
-msgstr "Seleziona"
-
-msgid "Delete folder and all sub folders?"
-msgstr "Eliminare la cartella e tutte le sottocartelle?"
-
-msgid "Delete folder?"
-msgstr "Eliminare la cartella?"
-
 msgid "Location"
 msgstr "Posizione"
 
@@ -53,15 +28,13 @@ msgstr "remoto"
 msgid "User ID"
 msgstr "ID utente"
 
-msgid "Button$Folder"
-msgstr "Cartella"
+#, c-format
+msgid "%.10s\tConflict (Recording %d%%)"
+msgstr ""
 
 msgid "Timer is recording - can't move it to server"
 msgstr "Timer in registrazione - impossibile spostarlo sul server"
 
-msgid "Select folder"
-msgstr "Seleziona cartella"
-
 #. TRANSLATORS: Indicator for (R)emote or (L)ocal timer in timers list
 msgid "RL"
 msgstr "RL"
@@ -77,6 +50,10 @@ msgstr "Annulla"
 msgid " tTpP"
 msgstr " tTpP"
 
+#, c-format
+msgid "What's on at %s?"
+msgstr ""
+
 msgid "Edit recording"
 msgstr "Modifica registrazione"
 
@@ -95,9 +72,15 @@ msgstr "Impossibile rinominare registrazione"
 msgid "Move to other filesystem in background?"
 msgstr "Spostare verso un altro filesystem in sottofondo?"
 
+msgid "Button$Folder"
+msgstr "Cartella"
+
 msgid "Cut"
 msgstr "Taglia"
 
+msgid "Select folder"
+msgstr "Seleziona cartella"
+
 #. TRANSLATORS: Button displayed instead of "Delete" when there are other users who didn't watch the recording yet
 msgid "Release"
 msgstr "Rilascia"
@@ -105,6 +88,9 @@ msgstr "Rilascia"
 msgid "Abort moving recording"
 msgstr "Spostamento registrazione annullato"
 
+msgid "Remote timers not available"
+msgstr "Timer remoti non disponibili"
+
 msgid "Finished moving recording"
 msgstr "Spostamento registrazione completato"
 
@@ -144,10 +130,6 @@ msgstr "ID canale"
 msgid "Hide mainmenu entry"
 msgstr "Nascondi voce menu principale"
 
-#, c-format
-msgid "Replace mainmenu \"%s\""
-msgstr "Sostituisci \"%s\" menu principale"
-
 msgid "Defaults for new timers"
 msgstr "Valori predefiniti per i nuovi timer"
 
@@ -157,20 +139,25 @@ msgstr "Registrazioni immediate"
 msgid "Pause recordings"
 msgstr "Pausa registrazioni"
 
-msgid "Settings for menu"
-msgstr "Impostazioni menu"
-
 #, c-format
-msgid "Binding of %s/%s in \"What's on\" menus"
-msgstr "Associazione %s/%s nel menu \"Adesso\""
+msgid "Settings for menu \"%s\""
+msgstr "Impostazioni \"%s\" menu"
 
-#, c-format
-msgid "Show progress bar in menu \"%s\""
-msgstr "Mostra barra avanzamento nel menu \"%s\""
+msgid "Replace mainmenu"
+msgstr "Sostituisci menu principale"
+
+msgid "List style"
+msgstr ""
+
+msgid "Show progress bar"
+msgstr "Mostra barra avanzamento"
 
 #, c-format
-msgid "User ID filter in menu \"%s\""
-msgstr "Filtra per ID utente nel menu \"%s\""
+msgid "Key binding of %s/%s"
+msgstr "Associazione %s/%s"
+
+msgid "User ID filter"
+msgstr "Filtra per ID utente"
 
 msgid "Move recording bandwidth limit (Mbit/s)"
 msgstr "Limite banda spostamento registrazione (Mbit/s)"
@@ -220,6 +207,26 @@ msgstr "Errore inatteso - impossibile avviare taglio remoto"
 msgid "Lost SVDRP connection - unable to start remote cutter"
 msgstr "Persa connessione SVDRP - impossibile avviare taglio remoto"
 
-msgid "Remote timers not available"
-msgstr "Timer remoti non disponibili"
+#~ msgid "Edit folder"
+#~ msgstr "Modifica cartella"
+
+#~ msgid "New folder"
+#~ msgstr "Nuova cartella"
+
+#~ msgid "Sub folder"
+#~ msgstr "Sottocartella"
+
+#~ msgid "Folder name already exists!"
+#~ msgstr "Nome cartella gi� esistente!"
+
+#~ msgid "Folder name must not contain '%c'!"
+#~ msgstr "Il nome cartella non pu� contenere '%c'!"
+
+#~ msgid "Button$Select"
+#~ msgstr "Seleziona"
+
+#~ msgid "Delete folder and all sub folders?"
+#~ msgstr "Eliminare la cartella e tutte le sottocartelle?"
 
+#~ msgid "Delete folder?"
+#~ msgstr "Eliminare la cartella?"
diff --git a/po/sk_SK.po b/po/sk_SK.po
old mode 100644
new mode 100755
index 54b0a58..996c9ac
--- a/po/sk_SK.po
+++ b/po/sk_SK.po
@@ -7,8 +7,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: remotetimers0.1.4\n"
 "Report-Msgid-Bugs-To: <vdrdev at schmirler.de>\n"
-"POT-Creation-Date: 2012-06-07 01:07+0200\n"
-"PO-Revision-Date: 2012-06-18 20:24+0100\n"
+"POT-Creation-Date: 2013-08-04 11:41+0200\n"
+"PO-Revision-Date: 2013-03-13 00:10+0100\n"
 "Last-Translator: Milan Hrala <hrala.milan at gmail.com>\n"
 "Language-Team: Slovak <hrala.milan at gmail.com>\n"
 "Language: sk\n"
@@ -16,31 +16,6 @@ msgstr ""
 "Content-Type: text/plain; charset=iso-8859-2\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-msgid "Edit folder"
-msgstr "Upravi� prie�inok"
-
-msgid "New folder"
-msgstr "Nov� prie�inok"
-
-msgid "Sub folder"
-msgstr "Podprie�inok"
-
-msgid "Folder name already exists!"
-msgstr "Prie�inok u� existuje!"
-
-#, c-format
-msgid "Folder name must not contain '%c'!"
-msgstr "Meno prie�inka nesmie obsahova� '%c'!"
-
-msgid "Button$Select"
-msgstr "Vybra�"
-
-msgid "Delete folder and all sub folders?"
-msgstr "Vymaza� prie�inok a v�etky podprie�inky?"
-
-msgid "Delete folder?"
-msgstr "Vymaza� prie�inok?"
-
 msgid "Location"
 msgstr "Umiestnenie"
 
@@ -51,17 +26,15 @@ msgid "remote"
 msgstr "vzdialen�"
 
 msgid "User ID"
-msgstr "U��vate�sk� ID"
+msgstr "U��vate�sk� identifika�n� ��slo"
 
-msgid "Button$Folder"
-msgstr "Prie�inok"
+#, c-format
+msgid "%.10s\tConflict (Recording %d%%)"
+msgstr ""
 
 msgid "Timer is recording - can't move it to server"
 msgstr "Pl�n sa nahr�va - ned� sa presun�� na server"
 
-msgid "Select folder"
-msgstr "Vybra� prie�inok"
-
 #. TRANSLATORS: Indicator for (R)emote or (L)ocal timer in timers list
 msgid "RL"
 msgstr "RL"
@@ -77,6 +50,10 @@ msgstr "Zru
 msgid " tTpP"
 msgstr " tTpP"
 
+#, c-format
+msgid "What's on at %s?"
+msgstr ""
+
 msgid "Edit recording"
 msgstr "Upravi� nahr�vku"
 
@@ -84,7 +61,7 @@ msgid "Remote editing process started"
 msgstr "Spusten� vzdialen� upravovanie procesu"
 
 msgid "Unable to update user ID"
-msgstr "Nemo�n� obnovi� u��vate�sk� ID"
+msgstr "Nemo�n� obnovi� u��vate�sk� ident. ��slo"
 
 msgid "Unable to change priority/lifetime"
 msgstr "Nemo�no zmeni� prioritu/�ivotnos�"
@@ -95,9 +72,15 @@ msgstr "Nemo
 msgid "Move to other filesystem in background?"
 msgstr "Presun na �al�� s�borov� syst�m na pozad�?"
 
+msgid "Button$Folder"
+msgstr "Prie�inok"
+
 msgid "Cut"
 msgstr "Vystrihn��"
 
+msgid "Select folder"
+msgstr "Vybra� prie�inok"
+
 #. TRANSLATORS: Button displayed instead of "Delete" when there are other users who didn't watch the recording yet
 msgid "Release"
 msgstr "Uvolni�"
@@ -105,6 +88,9 @@ msgstr "Uvolni
 msgid "Abort moving recording"
 msgstr "Presun nahr�vky zru�en�"
 
+msgid "Remote timers not available"
+msgstr "Vzdialen� pl�nova� nedostupn�"
+
 msgid "Finished moving recording"
 msgstr "Presun nahr�vky ukon�en�"
 
@@ -133,21 +119,17 @@ msgid "from svdrpservice"
 msgstr "zo svdrpservice"
 
 msgid "Map channels using"
-msgstr "Mapa pou��van�ch kan�lov"
+msgstr "Mapova� pou�it� kan�ly"
 
 msgid "channel number"
 msgstr "��slo kan�lu"
 
 msgid "channel ID"
-msgstr "ID kan�lu"
+msgstr "I.�. kan�lu"
 
 msgid "Hide mainmenu entry"
 msgstr "Schova� v hlavnom menu"
 
-#, c-format
-msgid "Replace mainmenu \"%s\""
-msgstr "Zameni� hlavn� menu \"%s\""
-
 msgid "Defaults for new timers"
 msgstr "Predvolen� pre nov� pl�ny"
 
@@ -157,20 +139,25 @@ msgstr "Okam
 msgid "Pause recordings"
 msgstr "Pauza nahr�vania"
 
-msgid "Settings for menu"
-msgstr "Nastavenie pre menu"
-
 #, c-format
-msgid "Binding of %s/%s in \"What's on\" menus"
-msgstr "V�zba %s/%s in \"What's on\" menus"
+msgid "Settings for menu \"%s\""
+msgstr "Nastavenia pre menu \"%s\""
 
-#, c-format
-msgid "Show progress bar in menu \"%s\""
-msgstr "Zobrazi� stav priebehu v menu \"%s\""
+msgid "Replace mainmenu"
+msgstr "Zameni� hlavn� menu"
+
+msgid "List style"
+msgstr "Zoznam �t�lov"
+
+msgid "Show progress bar"
+msgstr "Zobrazi� stav priebehu"
 
 #, c-format
-msgid "User ID filter in menu \"%s\""
-msgstr "Filter u��vate�sk�ho ID v menu \"%s\""
+msgid "Key binding of %s/%s"
+msgstr "K���ov� prepojenie na  %s/%s"
+
+msgid "User ID filter"
+msgstr "Filter ident. ��sla u��vate�a"
 
 msgid "Move recording bandwidth limit (Mbit/s)"
 msgstr "Obmedzenie ��rky p�sma pri presune nahr�vky  (Mbit / s)"
@@ -182,7 +169,7 @@ msgid "Remote recordings"
 msgstr "Vzdialen� nahr�vania"
 
 msgid "Mounted on subdirectory"
-msgstr "Pripojen� na pod adres�r"
+msgstr "Pripojen� na pod adres�r"
 
 msgid "Monitor update file"
 msgstr "Sledova� aktualiza�n� s�bor"
@@ -197,7 +184,7 @@ msgid "Timer is recording - please deactivate it first"
 msgstr "Pl�n sa nahr�va - pros�m, vypnite ho najprv"
 
 msgid "Timer already defined"
-msgstr "Pl�n je ur�en�"
+msgstr "Pl�n nahr�vania je ur�en�"
 
 msgid "Timers modified remotely - please check remote timers"
 msgstr "Pl�n zmenen� vzdialene - pros�m skontrolujte vzdialen� pl�nova�"
@@ -220,6 +207,26 @@ msgstr "Neo
 msgid "Lost SVDRP connection - unable to start remote cutter"
 msgstr "Straten� SVDRP spojenie - nem�e spusti� vzdialen� zostrihanie"
 
-msgid "Remote timers not available"
-msgstr "Vzdialen� pl�nova� nedostupn�"
+#~ msgid "Edit folder"
+#~ msgstr "Upravi� prie�inok"
+
+#~ msgid "New folder"
+#~ msgstr "Nov� prie�inok"
+
+#~ msgid "Sub folder"
+#~ msgstr "Podprie�inok"
+
+#~ msgid "Folder name already exists!"
+#~ msgstr "Prie�inok u� existuje!"
+
+#~ msgid "Folder name must not contain '%c'!"
+#~ msgstr "Meno prie�inka nesmie obsahova� '%c'!"
+
+#~ msgid "Button$Select"
+#~ msgstr "Vybra�"
+
+#~ msgid "Delete folder and all sub folders?"
+#~ msgstr "Vymaza� prie�inok a v�etky podprie�inky?"
 
+#~ msgid "Delete folder?"
+#~ msgstr "Vymaza� prie�inok?"
diff --git a/remotetimers.c b/remotetimers.c
index ce956ee..ffc0154 100644
--- a/remotetimers.c
+++ b/remotetimers.c
@@ -25,11 +25,12 @@
 #include "remotetimers.h"
 #include "setup.h"
 #include "menu.h"
+#include "conflict.h"
 #include "moverec.h"
 #include "watcher.h"
 #include "i18n.h"
 
-static const char *VERSION        = "0.1.7";
+static const char *VERSION        = "1.0.1";
 static const char *DESCRIPTION    = trNOOP("Edit timers on remote VDR");
 static const char *MAINMENUENTRY  = trNOOP("Remote Timers");
 
@@ -82,18 +83,12 @@ bool cPluginRemotetimers::ProcessArgs(int argc, char *argv[])
 
 bool cPluginRemotetimers::Initialize(void)
 {
-#if APIVERSNUM < 10712
-  PluginRemoteTimers::Folders.Load(AddDirectory(AddDirectory(ConfigDirectory(), ".."), "folders.conf"));
-#endif
   return true;
 }
 
 bool cPluginRemotetimers::Start(void)
 {
   // Start any background activities the plugin shall perform.
-#if VDRVERSNUM < 10507
-  RegisterI18n(Phrases);
-#endif
   if (RemoteTimersSetup.watchUpdate)
      cUpdateWatcher::GetInstance()->Start();
   return true;
@@ -212,6 +207,8 @@ bool cPluginRemotetimers::Service(const char *Id, void *Data)
      if (Data) {
         cString *errorMsg = (cString *) Data;
         if (svdrp->Connect() && RemoteTimers.Refresh() == rtsOk) {
+           RemoteConflicts.Update();
+           LocalConflicts.Update();
            cSchedulesLock SchedulesLock;
            const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock);
            if (Schedules) {
@@ -229,6 +226,26 @@ bool cPluginRemotetimers::Service(const char *Id, void *Data)
      return true;
   }
 
+  if (strcmp(Id, "RemoteTimers::ForEachConflict-v1.0") == 0) {
+     if (Data) {
+        const char *conflict = *(const char **) Data;
+        cTimerConflict *c = RemoteConflicts.First();
+        if (conflict) {
+           // find current conflict
+           while (c && (c->Text() == NULL || strcmp(c->Text(), conflict) != 0))
+                 c = RemoteConflicts.Next(c);
+           // step to next conflict
+           if (c)
+              c = RemoteConflicts.Next(c);
+           // skip conflicts at same time
+           while (c && c->Text() == NULL)
+                 c = RemoteConflicts.Next(c);
+        }
+        *(const char **)Data = c ? c->Text() : NULL;
+     }
+     return true;
+  }
+
   if (strcmp(Id, "RemoteTimers::ForEach-v1.0") == 0) {
      if (Data) {
         cRemoteTimer *t = *(cRemoteTimer **) Data;
@@ -241,7 +258,9 @@ bool cPluginRemotetimers::Service(const char *Id, void *Data)
   if (strcmp(Id, "RemoteTimers::GetMatch-v1.0") == 0) {
      if (Data) {
         RemoteTimers_GetMatch_v1_0 *match = (RemoteTimers_GetMatch_v1_0 *) Data;
-        match->timer = PluginRemoteTimers::GetBestMatch(match->event, MASK_FROM_SETUP(RemoteTimersSetup.userFilterSchedule), &match->timerMatch, &match->timerType, &match->isRemote);
+        eTimerMatch timerMatch = tmNone;
+        match->timer = PluginRemoteTimers::GetBestMatch(match->event, MASK_FROM_SETUP(RemoteTimersSetup.userFilterSchedule), &timerMatch, &match->timerType, &match->isRemote);
+        match->timerMatch = timerMatch;
      }
      return true;
   }
@@ -282,7 +301,7 @@ bool cPluginRemotetimers::Service(const char *Id, void *Data)
      if (Data) {
         RemoteTimers_Event_v1_0 *data = (RemoteTimers_Event_v1_0 *) Data;
         cTimer *t = NULL;
-        int tm = tmNone;
+        eTimerMatch tm = tmNone;
         bool isRemote = false;
 
         // check for timer with user filter
@@ -439,6 +458,27 @@ bool cPluginRemotetimers::Service(const char *Id, void *Data)
      return true;
   }
 
+  if (strcmp(Id, "RemoteTimers::GetTimerById-v1.0") == 0) {
+     if (Data) {
+        RemoteTimers_Timer_v1_1 *rtt = (RemoteTimers_Timer_v1_1 *) Data;
+        rtt->timer = RemoteTimers.GetTimer(rtt->id);
+     }
+     return true;
+  }
+
+  if (strcmp(Id, "RemoteTimers::Menu-v1.0") == 0) {
+     if (Data) {
+        RemoteTimers_Menu_v1_0 *data = (RemoteTimers_Menu_v1_0 *) Data;
+        if (data->state == osTimers)
+           data->menu = new ::PluginRemoteTimers::cMenuTimers(data->serverIp, data->serverPort);
+        else if (data->state == osSchedule)
+           data->menu = new ::PluginRemoteTimers::cMenuSchedule(data->serverIp, data->serverPort);
+        else
+           data->menu = NULL;
+     }
+     return true;
+  }
+
   /*
    * MainMenuHooks
    */
diff --git a/remotetimers.h b/remotetimers.h
index a69a7a0..950474f 100644
--- a/remotetimers.h
+++ b/remotetimers.h
@@ -1,7 +1,7 @@
 /*
  * remotetimers.h: Public interface of the plugin's services
  *
- * Copyright (C) 2008-2011 Frank Schmirler <vdr at schmirler.de>
+ * Copyright (C) 2008-2013 Frank Schmirler <vdr at schmirler.de>
  *
  * This file is part of VDR Plugin remotetimers.
  *
@@ -24,10 +24,9 @@
 #ifndef _SERVICE__H
 #define _SERVICE__H
 
-#ifndef __TIMERS_H
-#include <vdr/timer.h>
+#include <vdr/timers.h>
 #include <vdr/epg.h>
-#endif
+#include <vdr/osdbase.h>
 
 /*
  * If the Data argument is NULL, all service calls return true.
@@ -63,6 +62,16 @@ struct RemoteTimers_InstantRecording_v1_0 {
 //	cString errorMsg;
 
 /*
+ * RemoteTimers::ForEachConflict-v1.0
+ * Iterates the list of remote timer conflicts.
+ * The service call always returns true.
+ * Data points to a const char* which must be NULL to return the first conflict. Pass the previously returned conflict to get the next one until const char* is NULL.
+ *
+ */
+//in+out
+//	const char* conflict;
+
+/*
  * RemoteTimers::ForEach-v1.0
  * Iterates the list of remote timers.
  * The service call always returns true.
@@ -138,4 +147,36 @@ struct RemoteTimers_Timer_v1_0 {
 	cString		errorMsg;
 };
 
+/*
+ * RemoteTimers::GetTimerById-v1.0
+ * Get a remote timer by its id (i.e. timer->Index()+1 on remote machine).
+ * The service call always returns true.
+ * Data must point to a RemoteTimers_Timer_v1_1 structure. errorMsg is unused.
+ * NULL is returned as timer if no remote timer exists for the given id locally.
+ * Note that a timer with this id may exist remotely. This can happen if the
+ * remote timer's channel doesn't exist on the local machine.
+ */
+
+struct RemoteTimers_Timer_v1_1 {
+//in+out
+	cTimer		*timer;
+	int		id;
+//out
+	cString		errorMsg;
+};
+
+/*
+ * RemoteTimers::Menu-v1.0
+ * Depending on the state parameter, open the Timers or Schedule menu.
+ * In case of an error, menu is NULL.
+ * Data points to a RemoteTimers_Menu_v1_0 struct.
+ */
+struct RemoteTimers_Menu_v1_0 {
+//in
+	const char	*serverIp;
+	unsigned short	serverPort;
+	eOSState	state;
+//out
+	cOsdMenu	*menu;
+};
 #endif //_SERVICE__H
diff --git a/setup.c b/setup.c
index d44f49c..05eec78 100644
--- a/setup.c
+++ b/setup.c
@@ -46,9 +46,14 @@ cRemoteTimersSetup::cRemoteTimersSetup() {
 	useChannelId = 1;
 	swapOkBlue = 0;
 	showProgressBar = 0;
+	for (int i = 0; i < EPGTIME_LENGTH; ++i)
+		epgTime[i] = 0;
 	userFilterSchedule = 0;
 	userFilterTimers = 0;
 	userFilterRecordings = 0;
+	skinSchedule = 0;
+	skinTimers = 0;
+	skinRecordings = 0;
 	defaultUser = 0;
 	addToRemote = 1;
 	remotePause = 0;
@@ -68,9 +73,14 @@ cRemoteTimersSetup& cRemoteTimersSetup::operator=(const cRemoteTimersSetup &Setu
 	useChannelId = Setup.useChannelId;
 	swapOkBlue = Setup.swapOkBlue;
 	showProgressBar = Setup.showProgressBar;
+	for (int i = 0; i < EPGTIME_LENGTH; ++i)
+		epgTime[i] = Setup.epgTime[i];
 	userFilterSchedule = Setup.userFilterSchedule;
 	userFilterTimers = Setup.userFilterTimers;
 	userFilterRecordings = Setup.userFilterRecordings;
+	skinSchedule = Setup.skinSchedule;
+	skinTimers = Setup.skinTimers;
+	skinRecordings = Setup.skinRecordings;
 	defaultUser = Setup.defaultUser;
 	addToRemote = Setup.addToRemote;
 	remotePause = Setup.remotePause;
@@ -100,12 +110,23 @@ bool cRemoteTimersSetup::Parse(const char *Name, const char *Value) {
 		swapOkBlue = atoi(Value);
 	else if (!strcasecmp(Name, "ShowProgressBar"))
 		showProgressBar = atoi(Value);
+	else if (!strncasecmp(Name, "EpgTime", 7)) {
+		int i = atoi(Name + 7);
+		if (0 <= i && i < EPGTIME_LENGTH)
+			epgTime[i] = atoi(Value);
+	}
 	else if (!strcasecmp(Name, "UserFilterSchedule"))
 		userFilterSchedule = atoi(Value);
 	else if (!strcasecmp(Name, "UserFilterTimers"))
 		userFilterTimers = atoi(Value);
 	else if (!strcasecmp(Name, "UserFilterRecordings"))
 		userFilterRecordings = atoi(Value);
+	else if (!strcasecmp(Name, "SkinSchedule"))
+		skinSchedule = atoi(Value);
+	else if (!strcasecmp(Name, "SkinTimers"))
+		skinTimers = atoi(Value);
+	else if (!strcasecmp(Name, "SkinRecordings"))
+		skinRecordings = atoi(Value);
 	else if (!strcasecmp(Name, "DefaultUser"))
 		defaultUser = PluginRemoteTimers::cMenuEditUserItem::Parse(Value);
 	else if (!strcasecmp(Name, "AddToRemote"))
@@ -135,9 +156,14 @@ void cRemoteTimersMenuSetup::Store() {
 	SetupStore("UseChannelId", setupTmp.useChannelId);
 	SetupStore("SwapOkBlue", setupTmp.swapOkBlue);
 	SetupStore("ShowProgressBar", setupTmp.showProgressBar);
+	for (int i = 0; i < EPGTIME_LENGTH; ++i)
+		SetupStore(cString::sprintf("EpgTime%d", i), setupTmp.epgTime[i]);
 	SetupStore("UserFilterSchedule", setupTmp.userFilterSchedule);
 	SetupStore("UserFilterTimers", setupTmp.userFilterTimers);
 	SetupStore("UserFilterRecordings", setupTmp.userFilterRecordings);
+	SetupStore("SkinSchedule", setupTmp.skinSchedule);
+	SetupStore("SkinTimers", setupTmp.skinTimers);
+	SetupStore("SkinRecordings", setupTmp.skinRecordings);
 	SetupStore("DefaultUser", PluginRemoteTimers::cMenuEditUserItem::ToString(setupTmp.defaultUser));
 	SetupStore("AddToRemote", setupTmp.addToRemote);
 	SetupStore("RemotePause", setupTmp.remotePause);
@@ -174,11 +200,6 @@ void cRemoteTimersMenuSetup::Set() {
 	Add(new cMenuEditIntItem(trREMOTETIMERS("Server port"), &setupTmp.serverPort, 0, 65535, trREMOTETIMERS("from svdrpservice")));
 	Add(new cMenuEditBoolItem(trREMOTETIMERS("Map channels using"), &setupTmp.useChannelId, trREMOTETIMERS("channel number"), trREMOTETIMERS("channel ID")));
 	Add(new cMenuEditBoolItem(trREMOTETIMERS("Hide mainmenu entry"), &setupTmp.hideMainMenuEntry));
-#ifdef MAINMENUHOOKSVERSNUM
-	Add(new cMenuEditBoolItem(cString::sprintf(trREMOTETIMERS("Replace mainmenu \"%s\""), tr("Schedule")), &setupTmp.replaceSchedule));
-	Add(new cMenuEditBoolItem(cString::sprintf(trREMOTETIMERS("Replace mainmenu \"%s\""), tr("Timers")), &setupTmp.replaceTimers));
-	Add(new cMenuEditBoolItem(cString::sprintf(trREMOTETIMERS("Replace mainmenu \"%s\""), tr("Recordings")), &setupTmp.replaceRecordings));
-#endif
 	
 	Add(new cOsdItem(trREMOTETIMERS("Defaults for new timers"), osUnknown, false));
 	Add(new cMenuEditBoolItem(trREMOTETIMERS("Location"), &setupTmp.addToRemote, trREMOTETIMERS("local"), trREMOTETIMERS("remote")));
@@ -188,12 +209,30 @@ void cRemoteTimersMenuSetup::Set() {
 #endif
 	Add(new PluginRemoteTimers::cMenuEditUserItem(trREMOTETIMERS("User ID"), &setupTmp.defaultUser, tr("Setup.Replay$Resume ID")));
 	
-	Add(new cOsdItem(trREMOTETIMERS("Settings for menu"), osUnknown, false));
-	Add(new cMenuEditBoolItem(cString::sprintf(trREMOTETIMERS("Binding of %s/%s in \"What's on\" menus"), tr("Key$Ok"), tr("Key$Blue")), &setupTmp.swapOkBlue, swapOkBlueFalse, swapOkBlueTrue));
-	Add(new cMenuEditBoolItem(cString::sprintf(trREMOTETIMERS("Show progress bar in menu \"%s\""), tr("Schedule")), &setupTmp.showProgressBar));
-	Add(new cMenuEditIntItem(cString::sprintf(trREMOTETIMERS("User ID filter in menu \"%s\""), tr("Schedule")), &setupTmp.userFilterSchedule, -1, MAX_USER, tr("Setup.Replay$Resume ID")));
-	Add(new cMenuEditIntItem(cString::sprintf(trREMOTETIMERS("User ID filter in menu \"%s\""), tr("Timers")), &setupTmp.userFilterTimers, -1, MAX_USER, tr("Setup.Replay$Resume ID")));
-	Add(new cMenuEditIntItem(cString::sprintf(trREMOTETIMERS("User ID filter in menu \"%s\""), tr("Recordings")), &setupTmp.userFilterRecordings, -1, MAX_USER, tr("Setup.Replay$Resume ID")));
+	Add(new cOsdItem(cString::sprintf(trREMOTETIMERS("Settings for menu \"%s\""), tr("Schedule")), osUnknown, false));
+#ifdef MAINMENUHOOKSVERSNUM
+	Add(new cMenuEditBoolItem(trREMOTETIMERS("Replace mainmenu"), &setupTmp.replaceSchedule));
+#endif
+	Add(new cMenuEditBoolItem(trREMOTETIMERS("List style"), &setupTmp.skinSchedule, tr("Plugin"), tr("Setup.OSD$Skin")));
+	Add(new cMenuEditBoolItem(trREMOTETIMERS("Show progress bar"), &setupTmp.showProgressBar));
+	for (int i = 0; i < EPGTIME_LENGTH; ++i)
+		Add(new cMenuEditTimeItem(cString::sprintf("%s %d", *cString::sprintf(trREMOTETIMERS("What's on at %s?"), "..."), i + 1), &setupTmp.epgTime[i]));
+	Add(new cMenuEditBoolItem(cString::sprintf(trREMOTETIMERS("Key binding of %s/%s"), tr("Key$Ok"), tr("Key$Blue")), &setupTmp.swapOkBlue, swapOkBlueFalse, swapOkBlueTrue));
+	Add(new cMenuEditIntItem(trREMOTETIMERS("User ID filter"), &setupTmp.userFilterSchedule, -1, MAX_USER, tr("Setup.Replay$Resume ID")));
+
+	Add(new cOsdItem(cString::sprintf(trREMOTETIMERS("Settings for menu \"%s\""), tr("Timers")), osUnknown, false));
+#ifdef MAINMENUHOOKSVERSNUM
+	Add(new cMenuEditBoolItem(trREMOTETIMERS("Replace mainmenu"), &setupTmp.replaceTimers));
+#endif
+	Add(new cMenuEditBoolItem(trREMOTETIMERS("List style"), &setupTmp.skinTimers, tr("Plugin"), tr("Setup.OSD$Skin")));
+	Add(new cMenuEditIntItem(trREMOTETIMERS("User ID filter"), &setupTmp.userFilterTimers, -1, MAX_USER, tr("Setup.Replay$Resume ID")));
+
+	Add(new cOsdItem(cString::sprintf(trREMOTETIMERS("Settings for menu \"%s\""), tr("Recordings")), osUnknown, false));
+#ifdef MAINMENUHOOKSVERSNUM
+	Add(new cMenuEditBoolItem(trREMOTETIMERS("Replace mainmenu"), &setupTmp.replaceRecordings));
+#endif
+	Add(new cMenuEditBoolItem(trREMOTETIMERS("List style"), &setupTmp.skinRecordings, tr("Plugin"), tr("Setup.OSD$Skin")));
+	Add(new cMenuEditIntItem(trREMOTETIMERS("User ID filter"), &setupTmp.userFilterRecordings, -1, MAX_USER, tr("Setup.Replay$Resume ID")));
 	Add(new cMenuEditIntItem(trREMOTETIMERS("Move recording bandwidth limit (Mbit/s)"), &setupTmp.moveBandwidth, 0, INT_MAX, trREMOTETIMERS("unlimited")));
 
 	Add(new cOsdItem(trREMOTETIMERS("Remote recordings"), osUnknown, false));
diff --git a/setup.h b/setup.h
index 2ad975f..b22dc96 100644
--- a/setup.h
+++ b/setup.h
@@ -26,6 +26,7 @@
 #include "menuitems.h"
 
 #define MAX_IP_LENGTH 16
+#define EPGTIME_LENGTH 4
 
 struct cRemoteTimersSetup {
 	int hideMainMenuEntry;
@@ -37,9 +38,13 @@ struct cRemoteTimersSetup {
 	int useChannelId;
 	int swapOkBlue;
 	int showProgressBar;
+	int epgTime[EPGTIME_LENGTH];
 	int userFilterSchedule;
 	int userFilterTimers;
 	int userFilterRecordings;
+	int skinSchedule;
+	int skinTimers;
+	int skinRecordings;
 	int defaultUser;
 	int addToRemote;
 	int remotePause;
diff --git a/svdrp.c b/svdrp.c
index 9687b91..43ef3a4 100644
--- a/svdrp.c
+++ b/svdrp.c
@@ -50,15 +50,17 @@ cSvdrp::~cSvdrp() {
 		service->Service("SvdrpConnection-v1.0", &conn);
 }
 
-bool cSvdrp::Connect() {
+bool cSvdrp::Connect(const char* ServerIp, unsigned short ServerPort) {
 	refcount++;
 	if (!service)
 		esyslog("remotetimers: Plugin svdrpservice not available.");
 	else if (conn.handle < 0) {
-		conn.serverIp = RemoteTimersSetup.serverIp;
-		conn.serverPort = RemoteTimersSetup.serverPort;
+		conn.serverIp = (ServerIp && *ServerIp) ? ServerIp : RemoteTimersSetup.serverIp;
+		conn.serverPort = ServerPort != 0 ? ServerPort : RemoteTimersSetup.serverPort;
 		conn.shared = true;
 		service->Service("SvdrpConnection-v1.0", &conn);
+		if (conn.handle < 0)
+			RemoteTimers.Clear();
 	}
 	return conn.handle >= 0;
 }
@@ -315,6 +317,15 @@ cRemoteTimer *cRemoteTimers::GetTimer(cTimer *Timer)
 	return NULL;
 }
 
+cRemoteTimer *cRemoteTimers::GetTimer(int Id)
+{
+	for (cRemoteTimer *ti = First(); ti; ti = Next(ti)) {
+		if (Id == ti->Id())
+			return ti;
+	}
+	return NULL;
+}
+
 cRemoteTimer *cRemoteTimers::GetMatch(const cEvent *Event, int *Match)
 {
 	cRemoteTimer *t = NULL;
diff --git a/svdrp.h b/svdrp.h
index 357078b..03e0410 100644
--- a/svdrp.h
+++ b/svdrp.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008-2011 Frank Schmirler <vdr at schmirler.de>
+ * Copyright (C) 2008-2013 Frank Schmirler <vdr at schmirler.de>
  *
  * This file is part of VDR Plugin remotetimers.
  *
@@ -23,7 +23,7 @@
 #define _REMOTETIMERS_SVDRP__H
 
 #include <stdlib.h>
-#include "../svdrpservice/svdrpservice.h"
+#include "svdrpservice.h"
 #include <vdr/tools.h>
 #include <vdr/plugin.h>
 
@@ -40,7 +40,7 @@ class cSvdrp {
 
 		cSvdrp(cPlugin *Service);
 		~cSvdrp();
-		bool Connect();
+		bool Connect(const char* ServerIp = NULL, unsigned short ServerPort = 0);
 		void Disconnect();
 		bool Offline() { return conn.handle == -1; }
 		unsigned short Send(SvdrpCommand_v1_0 *Cmd);
@@ -80,6 +80,7 @@ class cRemoteTimers: public cList<cRemoteTimer> {
 		eRemoteTimersState New(cRemoteTimer *Timer);
 		cRemoteTimer* GetMatch(const cEvent *Event, int *Match);
 		cRemoteTimer* GetTimer(cTimer *Timer);
+		cRemoteTimer* GetTimer(int Id);
 };
 
 enum eRemoteRecordingsState { rrsOk, rrsLocked, rrsNotFound, rrsUnexpected, rrsConnError };
diff --git a/svdrpservice.h b/svdrpservice.h
new file mode 100644
index 0000000..239128c
--- /dev/null
+++ b/svdrpservice.h
@@ -0,0 +1,40 @@
+/*
+ * svdrpservice.h: Public interface of the plugin's services
+ *
+ * See the README file for copyright information and how to reach the author.
+ */
+
+#ifndef _SVDRPSERVICE__H
+#define _SVDRPSERVICE__H
+
+#include <vdr/tools.h>
+
+class cLine: public cListObject {
+	private:
+		char *Line;
+	public:
+		const char *Text() { return Line; }
+		cLine(const char *s) { Line = s ? strdup(s) : NULL; };
+		virtual ~cLine() { if (Line) free(Line); };
+};
+
+struct SvdrpConnection_v1_0 {
+//in+out
+	cString		serverIp;
+	unsigned short	serverPort;
+//in
+	bool		shared;
+//in+out
+	int		handle;
+};
+
+struct SvdrpCommand_v1_0 {
+//in
+	cString		command;
+	int		handle;
+//out
+	cList<cLine>	reply;
+	unsigned short	responseCode;
+};
+
+#endif //_SVDRPSERVICE__H

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-vdr-dvb/vdr-plugin-remotetimers.git



More information about the pkg-vdr-dvb-changes mailing list