mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
Implemented 'Commands' menu
This commit is contained in:
parent
9c499caf87
commit
54a2e99c7b
24
FORMATS
24
FORMATS
@ -66,3 +66,27 @@ Video Disk Recorder File Formats
|
||||
|
||||
See the MANUAL file for a description of the available options.
|
||||
|
||||
* commands.conf
|
||||
|
||||
This file contains the definitions of commands that can be executed from
|
||||
the "Main" menus "Commands" option.
|
||||
|
||||
Each line contains one command definition in the following format:
|
||||
|
||||
title : command
|
||||
|
||||
where 'title' is the string the will be displayed in the "Commands" menu,
|
||||
and 'command' is the actual command string that will be executed when this
|
||||
option is selected. The delimiting ':' may be surrounded by any number of
|
||||
white space characters.
|
||||
|
||||
In order to avoid error messages to stderr, every command should have
|
||||
stderr redirected to stdout. Everything the command prints to stdout will
|
||||
be displayed in a result window, with 'title' as its title.
|
||||
|
||||
Examples:
|
||||
|
||||
Check for new mail: /usr/local/bin/checkmail 2>&1
|
||||
CPU status : /usr/loval/bin/cpustatus 2>&1
|
||||
Disk space : df -h | grep '/video' | awk '{ print 100 - $5 "% free"; }'
|
||||
|
||||
|
3
HISTORY
3
HISTORY
@ -278,3 +278,6 @@ Video Disk Recorder Revision History
|
||||
- Fixed a timing problem with OSD refresh and SVDRP.
|
||||
- Avoiding multiple definitions of the same timer in the "Schedule" menu (this
|
||||
could happen when pressing the "Red" button while editing the timer).
|
||||
- There can now be a configuration file named 'commands.conf' that defines
|
||||
commands that can be executed through the "Main" menu's "Commands" option
|
||||
(see FORMATS for details on how to define these commands).
|
||||
|
24
MANUAL
24
MANUAL
@ -273,3 +273,27 @@ Video Disk Recorder User's Manual
|
||||
MarginStart = 2 Defines how many minutes before the official start time
|
||||
MarginStop = 10 of a broadcast VDR shall start recording, and how long
|
||||
after the official end time it shall stop recording.
|
||||
|
||||
* Executing system commands
|
||||
|
||||
The "Main" menu option "Commands" allows you to execute any system commands
|
||||
defined in the configuration file 'commands.conf' (see FORMATS for details).
|
||||
The "Commands" option will only be present in the "Main" menu if a valid
|
||||
'commands.conf' file containing at least one command definition has been
|
||||
found at program start.
|
||||
|
||||
This feature can be used to do virtually anything, like checking for new
|
||||
mail, displaying the CPU temperature - you name it! All you need to do is
|
||||
enter the necessary command definition into 'commands.conf' and implement
|
||||
the actual command that will be called. Such a command can typically be a
|
||||
shell script or a Perl program. Anything that command writes to stdout will
|
||||
be displayed on a result screen after executing the command. In order to
|
||||
avoid error messages going to stderr, command definitions should redirect
|
||||
stderr to stdout (see FORMATS).
|
||||
|
||||
WARNING: THE COMMANDS DEFINED IN 'commands.conf' WILL BE EXECUTED UNDER THE
|
||||
======= SAME USER ID THAT VDR IS RUNNING WITH. BE VERY CAREFUL WHEN
|
||||
DEFINING THESE COMMANDS AND MAKE SURE THEY DON'T HARM YOUR SYSTEM,
|
||||
ESPECIALLY IF YOU ARE RUNNING VDR UNDER A HIGH PRIVILEGED USER ID
|
||||
(LIKE 'root').
|
||||
|
||||
|
63
config.c
63
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.31 2000/11/11 09:56:01 kls Exp $
|
||||
* $Id: config.c 1.32 2000/11/11 15:41:07 kls Exp $
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
@ -426,7 +426,7 @@ bool cTimer::Parse(const char *s)
|
||||
delete summary;
|
||||
summary = NULL;
|
||||
//XXX Apparently sscanf() doesn't work correctly if the last %a argument
|
||||
//XXX results in an empty string (this firt occured when the EIT gathering
|
||||
//XXX results in an empty string (this first occured when the EIT gathering
|
||||
//XXX was put into a separate thread - don't know why this happens...
|
||||
//XXX As a cure we copy the original string and add a blank.
|
||||
//XXX If anybody can shed some light on why sscanf() failes here, I'd love
|
||||
@ -539,10 +539,69 @@ cTimer *cTimer::GetMatch(void)
|
||||
return t0;
|
||||
}
|
||||
|
||||
// --- cCommand -------------------------------------------------------------
|
||||
|
||||
char *cCommand::result = NULL;
|
||||
|
||||
cCommand::cCommand(void)
|
||||
{
|
||||
title = command = NULL;
|
||||
}
|
||||
|
||||
cCommand::~cCommand()
|
||||
{
|
||||
delete title;
|
||||
delete command;
|
||||
}
|
||||
|
||||
bool cCommand::Parse(const char *s)
|
||||
{
|
||||
const char *p = strchr(s, ':');
|
||||
if (p) {
|
||||
int l = p - s;
|
||||
if (l > 0) {
|
||||
title = new char[l + 1];
|
||||
strn0cpy(title, s, l + 1);
|
||||
if (!isempty(title)) {
|
||||
command = stripspace(strdup(skipspace(p + 1)));
|
||||
return !isempty(command);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *cCommand::Execute(void)
|
||||
{
|
||||
dsyslog(LOG_INFO, "executing command '%s'", command);
|
||||
delete result;
|
||||
result = NULL;
|
||||
FILE *p = popen(command, "r");
|
||||
if (p) {
|
||||
int l = 0;
|
||||
int c;
|
||||
while ((c = fgetc(p)) != EOF) {
|
||||
if (l % 20 == 0)
|
||||
result = (char *)realloc(result, l + 21);
|
||||
result[l++] = c;
|
||||
}
|
||||
if (result)
|
||||
result[l] = 0;
|
||||
pclose(p);
|
||||
}
|
||||
else
|
||||
esyslog(LOG_ERR, "ERROR: can't open pipe for command '%s'", command);
|
||||
return result;
|
||||
}
|
||||
|
||||
// -- cKeys ------------------------------------------------------------------
|
||||
|
||||
cKeys Keys;
|
||||
|
||||
// -- cCommands --------------------------------------------------------------
|
||||
|
||||
cCommands Commands;
|
||||
|
||||
// -- cChannels --------------------------------------------------------------
|
||||
|
||||
int CurrentGroup = -1;
|
||||
|
20
config.h
20
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.31 2000/11/11 10:39:00 kls Exp $
|
||||
* $Id: config.h 1.32 2000/11/11 14:39:40 kls Exp $
|
||||
*/
|
||||
|
||||
#ifndef __CONFIG_H
|
||||
@ -115,7 +115,7 @@ public:
|
||||
char *summary;
|
||||
cTimer(bool Instant = false);
|
||||
cTimer(const cEventInfo *EventInfo);
|
||||
~cTimer();
|
||||
virtual ~cTimer();
|
||||
cTimer& operator= (const cTimer &Timer);
|
||||
const char *ToText(void);
|
||||
bool Parse(const char *s);
|
||||
@ -132,6 +132,19 @@ public:
|
||||
static const char *PrintDay(int d);
|
||||
};
|
||||
|
||||
class cCommand : public cListObject {
|
||||
private:
|
||||
char *title;
|
||||
char *command;
|
||||
static char *result;
|
||||
public:
|
||||
cCommand(void);
|
||||
virtual ~cCommand();
|
||||
bool Parse(const char *s);
|
||||
const char *Title(void) { return title; }
|
||||
const char *Execute(void);
|
||||
};
|
||||
|
||||
template<class T> class cConfig : public cList<T> {
|
||||
private:
|
||||
char *fileName;
|
||||
@ -217,11 +230,14 @@ public:
|
||||
cTimer *GetTimer(cTimer *Timer);
|
||||
};
|
||||
|
||||
class cCommands : public cConfig<cCommand> {};
|
||||
|
||||
extern int CurrentGroup;
|
||||
|
||||
extern cChannels Channels;
|
||||
extern cTimers Timers;
|
||||
extern cKeys Keys;
|
||||
extern cCommands Commands;
|
||||
|
||||
class cSetup {
|
||||
private:
|
||||
|
5
i18n.c
5
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.1 2000/11/11 10:39:27 kls Exp $
|
||||
* $Id: i18n.c 1.2 2000/11/11 16:20:47 kls Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -70,6 +70,9 @@ const tPhrase Phrases[] = {
|
||||
{ "Setup",
|
||||
"Einstellungen",
|
||||
},
|
||||
{ "Commands",
|
||||
"Befehle",
|
||||
},
|
||||
{ "Edit Channel",
|
||||
"Kanal Editieren",
|
||||
},
|
||||
|
75
menu.c
75
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.45 2000/11/11 12:55:10 kls Exp $
|
||||
* $Id: menu.c 1.46 2000/11/11 15:22:56 kls Exp $
|
||||
*/
|
||||
|
||||
#include "menu.h"
|
||||
@ -850,26 +850,30 @@ eOSState cMenuTextItem::ProcessKey(eKeys Key)
|
||||
return osContinue;
|
||||
}
|
||||
|
||||
// --- cMenuSummary ----------------------------------------------------------
|
||||
// --- cMenuText -------------------------------------------------------------
|
||||
|
||||
class cMenuSummary : public cOsdMenu {
|
||||
class cMenuText : public cOsdMenu {
|
||||
public:
|
||||
cMenuSummary(const char *Text);
|
||||
cMenuText(const char *Title, const char *Text);
|
||||
virtual eOSState ProcessKey(eKeys Key);
|
||||
};
|
||||
|
||||
cMenuSummary::cMenuSummary(const char *Text)
|
||||
:cOsdMenu(tr("Summary"))
|
||||
cMenuText::cMenuText(const char *Title, const char *Text)
|
||||
:cOsdMenu(Title)
|
||||
{
|
||||
Add(new cMenuTextItem(Text, 1, 2, MenuColumns - 2, MAXOSDITEMS));
|
||||
}
|
||||
|
||||
eOSState cMenuSummary::ProcessKey(eKeys Key)
|
||||
eOSState cMenuText::ProcessKey(eKeys Key)
|
||||
{
|
||||
eOSState state = cOsdMenu::ProcessKey(Key);
|
||||
|
||||
if (state == osUnknown)
|
||||
state = osContinue;
|
||||
if (state == osUnknown) {
|
||||
switch (Key) {
|
||||
case kOk: return osBack;
|
||||
default: state = osContinue;
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
@ -1058,7 +1062,7 @@ eOSState cMenuTimers::Summary(void)
|
||||
return osContinue;
|
||||
cTimer *ti = Timers.Get(Current());
|
||||
if (ti && ti->summary && *ti->summary)
|
||||
return AddSubMenu(new cMenuSummary(ti->summary));
|
||||
return AddSubMenu(new cMenuText(tr("Summary"), ti->summary));
|
||||
return Edit(); // convenience for people not using the Summary feature ;-)
|
||||
}
|
||||
|
||||
@ -1442,7 +1446,7 @@ eOSState cMenuRecordings::Summary(void)
|
||||
return osContinue;
|
||||
cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
|
||||
if (ri && ri->recording->Summary() && *ri->recording->Summary())
|
||||
return AddSubMenu(new cMenuSummary(ri->recording->Summary()));
|
||||
return AddSubMenu(new cMenuText(tr("Summary"), ri->recording->Summary()));
|
||||
return osContinue;
|
||||
}
|
||||
|
||||
@ -1524,6 +1528,52 @@ eOSState cMenuSetup::ProcessKey(eKeys Key)
|
||||
return state;
|
||||
}
|
||||
|
||||
// --- cMenuCommands ---------------------------------------------------------
|
||||
|
||||
class cMenuCommands : public cOsdMenu {
|
||||
private:
|
||||
eOSState Execute(void);
|
||||
public:
|
||||
cMenuCommands(void);
|
||||
virtual eOSState ProcessKey(eKeys Key);
|
||||
};
|
||||
|
||||
cMenuCommands::cMenuCommands(void)
|
||||
:cOsdMenu(tr("Commands"))
|
||||
{
|
||||
int i = 0;
|
||||
cCommand *command;
|
||||
|
||||
while ((command = Commands.Get(i)) != NULL) {
|
||||
Add(new cOsdItem(command->Title()));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
eOSState cMenuCommands::Execute(void)
|
||||
{
|
||||
cCommand *command = Commands.Get(Current());
|
||||
if (command) {
|
||||
const char *Result = command->Execute();
|
||||
if (Result)
|
||||
return AddSubMenu(new cMenuText(command->Title(), Result));
|
||||
}
|
||||
return osContinue;
|
||||
}
|
||||
|
||||
eOSState cMenuCommands::ProcessKey(eKeys Key)
|
||||
{
|
||||
eOSState state = cOsdMenu::ProcessKey(Key);
|
||||
|
||||
if (state == osUnknown) {
|
||||
switch (Key) {
|
||||
case kOk: return Execute();
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
// --- cMenuMain -------------------------------------------------------------
|
||||
|
||||
#define STOP_RECORDING tr("Stop recording ")
|
||||
@ -1536,6 +1586,8 @@ cMenuMain::cMenuMain(bool Replaying)
|
||||
Add(new cOsdItem(tr("Timers"), osTimers));
|
||||
Add(new cOsdItem(tr("Recordings"), osRecordings));
|
||||
Add(new cOsdItem(tr("Setup"), osSetup));
|
||||
if (Commands.Count())
|
||||
Add(new cOsdItem(tr("Commands"), osCommands));
|
||||
if (Replaying)
|
||||
Add(new cOsdItem(tr("Stop replaying"), osStopReplay));
|
||||
const char *s = NULL;
|
||||
@ -1560,6 +1612,7 @@ eOSState cMenuMain::ProcessKey(eKeys Key)
|
||||
case osTimers: return AddSubMenu(new cMenuTimers);
|
||||
case osRecordings: return AddSubMenu(new cMenuRecordings);
|
||||
case osSetup: return AddSubMenu(new cMenuSetup);
|
||||
case osCommands: return AddSubMenu(new cMenuCommands);
|
||||
case osStopRecord: if (Interface->Confirm(tr("Stop Recording?"))) {
|
||||
cOsdItem *item = Get(Current());
|
||||
if (item) {
|
||||
|
3
osd.h
3
osd.h
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: osd.h 1.15 2000/11/10 15:28:28 kls Exp $
|
||||
* $Id: osd.h 1.16 2000/11/11 14:49:29 kls Exp $
|
||||
*/
|
||||
|
||||
#ifndef __OSD_H
|
||||
@ -24,6 +24,7 @@ enum eOSState { osUnknown,
|
||||
osTimers,
|
||||
osRecordings,
|
||||
osSetup,
|
||||
osCommands,
|
||||
osRecord,
|
||||
osReplay,
|
||||
osStopRecord,
|
||||
|
14
tools.c
14
tools.c
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: tools.c 1.22 2000/10/29 11:21:55 kls Exp $
|
||||
* $Id: tools.c 1.23 2000/11/11 15:17:12 kls Exp $
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
@ -92,6 +92,18 @@ char *skipspace(const char *s)
|
||||
return (char *)s;
|
||||
}
|
||||
|
||||
char *stripspace(char *s)
|
||||
{
|
||||
if (s && *s) {
|
||||
for (char *p = s + strlen(s) - 1; p >= s; p--) {
|
||||
if (!isspace(*p))
|
||||
break;
|
||||
*p = 0;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
bool isempty(const char *s)
|
||||
{
|
||||
return !(s && *skipspace(s));
|
||||
|
3
tools.h
3
tools.h
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: tools.h 1.18 2000/10/29 11:19:20 kls Exp $
|
||||
* $Id: tools.h 1.19 2000/11/11 15:14:40 kls Exp $
|
||||
*/
|
||||
|
||||
#ifndef __TOOLS_H
|
||||
@ -41,6 +41,7 @@ char *readline(FILE *f);
|
||||
char *strn0cpy(char *dest, const char *src, size_t n);
|
||||
char *strreplace(char *s, char c1, char c2);
|
||||
char *skipspace(const char *s);
|
||||
char *stripspace(char *s);
|
||||
bool isempty(const char *s);
|
||||
int time_ms(void);
|
||||
void delay_ms(int ms);
|
||||
|
3
vdr.c
3
vdr.c
@ -22,7 +22,7 @@
|
||||
*
|
||||
* The project's page is at http://www.cadsoft.de/people/kls/vdr
|
||||
*
|
||||
* $Id: vdr.c 1.44 2000/11/10 16:13:27 kls Exp $
|
||||
* $Id: vdr.c 1.45 2000/11/11 14:40:11 kls Exp $
|
||||
*/
|
||||
|
||||
#include <getopt.h>
|
||||
@ -165,6 +165,7 @@ int main(int argc, char *argv[])
|
||||
Setup.Load(AddDirectory(ConfigDirectory, "setup.conf"));
|
||||
Channels.Load(AddDirectory(ConfigDirectory, "channels.conf"));
|
||||
Timers.Load(AddDirectory(ConfigDirectory, "timers.conf"));
|
||||
Commands.Load(AddDirectory(ConfigDirectory, "commands.conf"));
|
||||
#ifdef REMOTE_LIRC
|
||||
Keys.SetDummyValues();
|
||||
#else
|
||||
|
Loading…
Reference in New Issue
Block a user