summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--HISTORY7
-rw-r--r--MANUAL4
-rw-r--r--config.c5
-rw-r--r--config.h3
-rw-r--r--i18n.c7
-rw-r--r--interface.c16
-rw-r--r--menu.c3
-rw-r--r--svdrp.c54
-rw-r--r--svdrp.h8
-rwxr-xr-xsvdrpsend.pl57
10 files changed, 147 insertions, 17 deletions
diff --git a/HISTORY b/HISTORY
index 0ec90804..d0149ebb 100644
--- a/HISTORY
+++ b/HISTORY
@@ -350,7 +350,7 @@ Video Disk Recorder Revision History
- Encrypted channels can now be selected even without knowing the PNR (however, it
is still necessary for the EPG info).
-2001-02-11: Version 0.71
+2001-02-18: Version 0.71
- Fixed 'Transfer Mode' in cases where a non-primary interface was switched to
a channel that only the primary interface can receive (which could happen in
@@ -392,3 +392,8 @@ Video Disk Recorder Revision History
- When removing recordings empty directories are now removed from the video
directory.
- Added the "schnitt" tools from Matthias Schniedermeyer.
+- New SVDRP command MESG to display a short message on the OSD.
+- The Perl script 'svdrpsend.pl' can be used to send SVDRP commands to VDR.
+- SVDRP can now immediately reuse the same port if VDR is restarted.
+- SVDRP now has a timeout after which the connection is automatically closed
+ (default is 300 seconds, can be changed in "Setup").
diff --git a/MANUAL b/MANUAL
index 986da1dd..3593be9a 100644
--- a/MANUAL
+++ b/MANUAL
@@ -328,6 +328,10 @@ Video Disk Recorder User's Manual
to keep the EPG up-to-date.
A value of '0' turns off scanning on a single card system.
+ SVDRPTimeout = 300 The time (in seconds) of inactivity on an open SVDRP
+ connection after which the connection is automatically
+ closed. Default is 300, a value of 0 means no timeout.
+
* Executing system commands
The "Main" menu option "Commands" allows you to execute any system commands
diff --git a/config.c b/config.c
index 3d3017c8..21d8c581 100644
--- a/config.c
+++ b/config.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: config.c 1.41 2001/02/11 11:22:48 kls Exp $
+ * $Id: config.c 1.42 2001/02/18 13:11:59 kls Exp $
*/
#include "config.h"
@@ -738,6 +738,7 @@ cSetup::cSetup(void)
MarginStart = 2;
MarginStop = 10;
EPGScanTimeout = 5;
+ SVDRPTimeout = 300;
CurrentChannel = -1;
}
@@ -758,6 +759,7 @@ bool cSetup::Parse(char *s)
else if (!strcasecmp(Name, "MarginStart")) MarginStart = atoi(Value);
else if (!strcasecmp(Name, "MarginStop")) MarginStop = atoi(Value);
else if (!strcasecmp(Name, "EPGScanTimeout")) EPGScanTimeout = atoi(Value);
+ else if (!strcasecmp(Name, "SVDRPTimeout")) SVDRPTimeout = atoi(Value);
else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value);
else
return false;
@@ -811,6 +813,7 @@ bool cSetup::Save(const char *FileName)
fprintf(f, "MarginStart = %d\n", MarginStart);
fprintf(f, "MarginStop = %d\n", MarginStop);
fprintf(f, "EPGScanTimeout = %d\n", EPGScanTimeout);
+ fprintf(f, "SVDRPTimeout = %d\n", SVDRPTimeout);
fprintf(f, "CurrentChannel = %d\n", CurrentChannel);
f.Close();
isyslog(LOG_INFO, "saved setup to %s", FileName);
diff --git a/config.h b/config.h
index 8f44e56e..963bcae3 100644
--- a/config.h
+++ b/config.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: config.h 1.40 2001/02/03 15:55:45 kls Exp $
+ * $Id: config.h 1.41 2001/02/18 13:12:06 kls Exp $
*/
#ifndef __CONFIG_H
@@ -269,6 +269,7 @@ public:
int SetSystemTime;
int MarginStart, MarginStop;
int EPGScanTimeout;
+ int SVDRPTimeout;
int CurrentChannel;
cSetup(void);
bool Load(const char *FileName);
diff --git a/i18n.c b/i18n.c
index 749f7804..89915264 100644
--- a/i18n.c
+++ b/i18n.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: i18n.c 1.12 2001/02/13 22:17:27 kls Exp $
+ * $Id: i18n.c 1.13 2001/02/18 13:14:00 kls Exp $
*
* Slovenian translations provided by Miha Setina <mihasetina@softhome.net>
* Italian translations provided by Alberto Carraro <bertocar@tin.it>
@@ -416,6 +416,11 @@ const tPhrase Phrases[] = {
"Cas do EPG pregleda",
"Timeout EPG",
},
+ { "SVDRPTimeout",
+ "SVDRP Timeout",
+ "", // TODO
+ "Timeout SVDRP",
+ },
// The days of the week:
{ "MTWTFSS",
"MDMDFSS",
diff --git a/interface.c b/interface.c
index 2346f6ca..55cdb0b9 100644
--- a/interface.c
+++ b/interface.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: interface.c 1.34 2001/02/02 14:49:39 kls Exp $
+ * $Id: interface.c 1.35 2001/02/18 10:46:13 kls Exp $
*/
#include "interface.h"
@@ -70,8 +70,16 @@ unsigned int cInterface::GetCh(bool Wait, bool *Repeat, bool *Release)
eKeys cInterface::GetKey(bool Wait)
{
Flush();
- if (SVDRP)
+ if (SVDRP) {
SVDRP->Process();
+ if (!open) {
+ char *message = SVDRP->GetMessage();
+ if (message) {
+ Info(message);
+ delete message;
+ }
+ }
+ }
eKeys Key = keyFromWait;
if (Key == kNone) {
bool Repeat = false, Release = false;
@@ -281,7 +289,7 @@ void cInterface::Status(const char *s, eDvbColor FgColor, eDvbColor BgColor)
void cInterface::Info(const char *s)
{
Open();
- isyslog(LOG_INFO, s);
+ isyslog(LOG_INFO, "info: %s", s);
Status(s, clrWhite, clrGreen);
Wait();
Status(NULL);
@@ -291,7 +299,7 @@ void cInterface::Info(const char *s)
void cInterface::Error(const char *s)
{
Open();
- esyslog(LOG_ERR, s);
+ esyslog(LOG_ERR, "ERROR: %s", s);
Status(s, clrWhite, clrRed);
Wait();
Status(NULL);
diff --git a/menu.c b/menu.c
index 92c8091d..37c1a16c 100644
--- a/menu.c
+++ b/menu.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: menu.c 1.65 2001/02/11 11:01:47 kls Exp $
+ * $Id: menu.c 1.66 2001/02/18 13:12:32 kls Exp $
*/
#include "menu.h"
@@ -1608,6 +1608,7 @@ void cMenuSetup::Set(void)
Add(new cMenuEditIntItem( tr("MarginStart"), &data.MarginStart));
Add(new cMenuEditIntItem( tr("MarginStop"), &data.MarginStop));
Add(new cMenuEditIntItem( tr("EPGScanTimeout"), &data.EPGScanTimeout));
+ Add(new cMenuEditIntItem( tr("SVDRPTimeout"), &data.SVDRPTimeout));
}
eOSState cMenuSetup::ProcessKey(eKeys Key)
diff --git a/svdrp.c b/svdrp.c
index 0ce30dba..ffdac28b 100644
--- a/svdrp.c
+++ b/svdrp.c
@@ -10,7 +10,7 @@
* and interact with the Video Disk Recorder - or write a full featured
* graphical interface that sits on top of an SVDRP connection.
*
- * $Id: svdrp.c 1.13 2000/12/03 15:34:35 kls Exp $
+ * $Id: svdrp.c 1.14 2001/02/18 14:18:13 kls Exp $
*/
#define _GNU_SOURCE
@@ -63,6 +63,10 @@ bool cSocket::Open(void)
port = 0;
return false;
}
+ // allow it to always reuse the same port:
+ int ReUseAddr = 1;
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &ReUseAddr, sizeof(ReUseAddr));
+ //
struct sockaddr_in name;
name.sin_family = AF_INET;
name.sin_port = htons(port);
@@ -137,6 +141,12 @@ const char *HelpPages[] = {
"LSTT [ <number> ]\n"
" List timers. Without option, all timers are listed. Otherwise\n"
" only the given timer is listed.",
+ "MESG [ <message> ]\n"
+ " Displays the given message on the OSD. If message is omitted, the\n"
+ " currently pending message (if any) will be returned. The message\n"
+ " will be displayed for a few seconds as soon as the OSD has become\n"
+ " idle. If a new MESG command is entered while the previous message\n"
+ " has not yet been displayed, the old message will be overwritten.",
"MODC <number> <settings>\n"
" Modify a channel. Settings must be in the same format as returned\n"
" by the LSTC command.",
@@ -224,22 +234,25 @@ const char *GetHelpPage(const char *Cmd)
cSVDRP::cSVDRP(int Port)
:socket(Port)
{
+ message = NULL;
+ lastActivity = 0;
isyslog(LOG_INFO, "SVDRP listening on port %d", Port);
}
cSVDRP::~cSVDRP()
{
Close();
+ delete message;
}
-void cSVDRP::Close(void)
+void cSVDRP::Close(bool Timeout)
{
if (file.IsOpen()) {
//TODO how can we get the *full* hostname?
char buffer[MAXCMDBUFFER];
gethostname(buffer, sizeof(buffer));
- Reply(221, "%s closing connection", buffer);
- isyslog(LOG_INFO, "closing connection"); //TODO store IP#???
+ Reply(221, "%s closing connection%s", buffer, Timeout ? " (timeout)" : "");
+ isyslog(LOG_INFO, "closing SVDRP connection"); //TODO store IP#???
file.Close();
}
}
@@ -557,6 +570,20 @@ void cSVDRP::CmdLSTT(const char *Option)
}
}
+void cSVDRP::CmdMESG(const char *Option)
+{
+ if (*Option) {
+ delete message;
+ message = strdup(Option);
+ isyslog(LOG_INFO, "SVDRP message: '%s'", message);
+ Reply(250, "Message stored");
+ }
+ else if (message)
+ Reply(250, "%s", message);
+ else
+ Reply(550, "No pending message");
+}
+
void cSVDRP::CmdMODC(const char *Option)
{
if (*Option) {
@@ -820,6 +847,7 @@ void cSVDRP::Execute(char *Cmd)
else if (CMD("HITK")) CmdHITK(s);
else if (CMD("LSTC")) CmdLSTC(s);
else if (CMD("LSTT")) CmdLSTT(s);
+ else if (CMD("MESG")) CmdMESG(s);
else if (CMD("MODC")) CmdMODC(s);
else if (CMD("MODT")) CmdMODT(s);
else if (CMD("MOVC")) CmdMOVC(s);
@@ -839,7 +867,8 @@ void cSVDRP::Execute(char *Cmd)
void cSVDRP::Process(void)
{
- bool SendGreeting = !file.IsOpen();
+ bool NewConnection = !file.IsOpen();
+ bool SendGreeting = NewConnection;
if (file.IsOpen() || file.Open(socket.Accept())) {
char buffer[MAXCMDBUFFER];
@@ -849,6 +878,8 @@ void cSVDRP::Process(void)
time_t now = time(NULL);
Reply(220, "%s SVDRP VideoDiskRecorder %s; %s", buffer, VDRVERSION, ctime(&now));
}
+ if (NewConnection)
+ lastActivity = time(NULL);
int rbytes = file.ReadString(buffer, sizeof(buffer) - 1);
if (rbytes > 0) {
//XXX overflow check???
@@ -859,11 +890,22 @@ void cSVDRP::Process(void)
buffer[rbytes] = 0;
// showtime!
Execute(buffer);
+ lastActivity = time(NULL);
}
else if (rbytes < 0)
Close();
+ else if (Setup.SVDRPTimeout && time(NULL) - lastActivity > Setup.SVDRPTimeout) {
+ isyslog(LOG_INFO, "timeout on SVDRP connection");
+ Close(true);
+ }
}
}
-//TODO timeout???
+char *cSVDRP::GetMessage(void)
+{
+ char *s = message;
+ message = NULL;
+ return s;
+}
+
//TODO more than one connection???
diff --git a/svdrp.h b/svdrp.h
index 12eb11e3..62c1e753 100644
--- a/svdrp.h
+++ b/svdrp.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: svdrp.h 1.6 2000/09/17 13:22:04 kls Exp $
+ * $Id: svdrp.h 1.7 2001/02/18 13:36:47 kls Exp $
*/
#ifndef __SVDRP_H
@@ -31,7 +31,9 @@ private:
cSocket socket;
cFile file;
CRect ovlClipRects[MAXCLIPRECTS];
- void Close(void);
+ char *message;
+ time_t lastActivity;
+ void Close(bool Timeout = false);
bool Send(const char *s, int length = -1);
void Reply(int Code, const char *fmt, ...);
void CmdCHAN(const char *Option);
@@ -42,6 +44,7 @@ private:
void CmdHITK(const char *Option);
void CmdLSTC(const char *Option);
void CmdLSTT(const char *Option);
+ void CmdMESG(const char *Option);
void CmdMODC(const char *Option);
void CmdMODT(const char *Option);
void CmdMOVC(const char *Option);
@@ -59,6 +62,7 @@ public:
cSVDRP(int Port);
~cSVDRP();
void Process(void);
+ char *GetMessage(void);
};
#endif //__SVDRP_H
diff --git a/svdrpsend.pl b/svdrpsend.pl
new file mode 100755
index 00000000..5efd504b
--- /dev/null
+++ b/svdrpsend.pl
@@ -0,0 +1,57 @@
+#!/usr/bin/perl
+
+use Socket;
+use Getopt::Std;
+
+$Usage = qq{
+Usage: $0 options command...
+
+Options: -d hostname destination hostname (default: localhost)
+ -p port SVDRP port number (default: 2001)
+};
+
+die $Usage if (!$ARGV[0] || !getopts("d:p:"));
+
+$Dest = $opt_d || "localhost";
+$Port = $opt_p || 2001;
+$Cmd = "@ARGV" || Error("missing command");
+
+$Timeout = 10; # max. seconds to wait for response
+
+$SIG{ALRM} = sub { Error("timeout"); };
+alarm($Timeout);
+
+$iaddr = inet_aton($Dest) || Error("no host: $Dest");
+$paddr = sockaddr_in($Port, $iaddr);
+
+$proto = getprotobyname('tcp');
+socket(SOCK, PF_INET, SOCK_STREAM, $proto) || Error("socket: $!");
+connect(SOCK, $paddr) || Error("connect: $!");
+select(SOCK); $| = 1;
+Receive();
+Send($Cmd);
+Send("quit");
+close(SOCK) || Error("close: $!");
+
+sub Send
+{
+ my $cmd = shift || Error("no command to send");
+ print SOCK "$cmd\r\n";
+ Receive();
+}
+
+sub Receive
+{
+ while (<SOCK>) {
+ print STDOUT $_;
+ last if substr($_, 3, 1) ne "-";
+ }
+}
+
+sub Error
+{
+ print STDERR "@_\n";
+ close(SOCK);
+ exit 0;
+}
+