Version 0.99

- Fixed a bug in moving timers or channels to the last position in the list
  (thanks to Matthias Schniedermeyer for helping to debug this one).
- Changed the estimated data rate for calculating the remaining disk capacity
  to 25.75 MB/min.
- Only reporting the 'EPG bugfix statistics' if there really were any fixes.
- Added Finnish language texts (thanks to Hannu Savolainen).
- Reverted to the previous way of searching for the EPG record of the current
  recording in case of a periodic timer (i.e. taking the one that is in the
  middle between start and end time).
- Added a typedef for 'in_addr_t' to make it work with glibc < 2.2 (thanks to
  Jrgen Schmidt).
- When the last entry in a "Recordings" menu page is deleted, that page is now
  automatically closed (suggested by Uwe Freese).
- Changed the default name for instant recordings to "TITLE EPISODE" (avoiding
  the '-').
- If Setup.ShowInfoOnChSwitch is set to "no", the box for the EPG display is no
  longer shown (thanks to Andy Grobb).
- If compiled with VFAT=1, characters that can't be handled by a VFAT system are
  now encoded to '#XX'.
- When the user presses the "Power" button and there is a timer about to start
  recording within Setup.MinEventTimeout minutes, there is now a confirmation
  prompt telling the user that there is an upcoming timer event.
- If a recording has no episode title, the trailing '~' is no longer shown in
  the progress display.
This commit is contained in:
Klaus Schmidinger 2002-02-10 18:00:00 +01:00
parent ef0a53af72
commit a1da0e5c5d
12 changed files with 359 additions and 51 deletions

View File

@ -47,6 +47,7 @@ Matthias Schniedermeyer <ms@citd.de>
for implementing the 'MarkInstantRecord' setup option for implementing the 'MarkInstantRecord' setup option
for his "schnitt" tools for his "schnitt" tools
for his "master-timer" tool for his "master-timer" tool
for helping to debug the "move to last position in list" bug
Miha Setina <mihasetina@softhome.net> Miha Setina <mihasetina@softhome.net>
for translating the OSD texts to the Slovenian language for translating the OSD texts to the Slovenian language
@ -161,6 +162,7 @@ Simon Bauschulte <SemiSchwabe@Brutzel.de>
Andy Grobb <Charly98@01019freenet.de> Andy Grobb <Charly98@01019freenet.de>
for completing storing the current audio volume in the setup.conf file for completing storing the current audio volume in the setup.conf file
for fixing the EPG display in case Setup.ShowInfoOnChSwitch is set to "no"
Thomas Heiligenmann <thomas@heiligenmann.de> Thomas Heiligenmann <thomas@heiligenmann.de>
for implementing the SVDRP commands LSTR and DELR for implementing the SVDRP commands LSTR and DELR
@ -189,3 +191,17 @@ Davide Achilli <davide@objsystem.it>
Michael Paar <mpaar@uumail.de> Michael Paar <mpaar@uumail.de>
for enabling recording of radio channels for enabling recording of radio channels
Hannu Savolainen <hannu@opensound.com>
for translating the OSD texts to the Finnish language
Jürgen Schmidt <ju@ct.heise.de>
for fixing a problem with 'in_addr_t' on systems with glibc < 2.2.
Uwe Freese <mail@uwe-freese.de>
for suggesting to automatically close an empty recordings page after deleting
an entry
Rainer Zocholl <Usenet-372114@zocki.toppoint.de>
for suggesting a confirmation prompt when the user presses the "Power" button
and there is an upcoming timer event

27
HISTORY
View File

@ -969,3 +969,30 @@ Video Disk Recorder Revision History
radio recordings. Thanks to Michael Paar. radio recordings. Thanks to Michael Paar.
- Fixed a problem with the ERR macro defined by ncurses.h (thanks to Artur - Fixed a problem with the ERR macro defined by ncurses.h (thanks to Artur
Skawina). Skawina).
2002-02-10: Version 0.99
- Fixed a bug in moving timers or channels to the last position in the list
(thanks to Matthias Schniedermeyer for helping to debug this one).
- Changed the estimated data rate for calculating the remaining disk capacity
to 25.75 MB/min.
- Only reporting the 'EPG bugfix statistics' if there really were any fixes.
- Added Finnish language texts (thanks to Hannu Savolainen).
- Reverted to the previous way of searching for the EPG record of the current
recording in case of a periodic timer (i.e. taking the one that is in the
middle between start and end time).
- Added a typedef for 'in_addr_t' to make it work with glibc < 2.2 (thanks to
Jürgen Schmidt).
- When the last entry in a "Recordings" menu page is deleted, that page is now
automatically closed (suggested by Uwe Freese).
- Changed the default name for instant recordings to "TITLE EPISODE" (avoiding
the '-').
- If Setup.ShowInfoOnChSwitch is set to "no", the box for the EPG display is no
longer shown (thanks to Andy Grobb).
- If compiled with VFAT=1, characters that can't be handled by a VFAT system are
now encoded to '#XX'.
- When the user presses the "Power" button and there is a timer about to start
recording within Setup.MinEventTimeout minutes, there is now a confirmation
prompt telling the user that there is an upcoming timer event.
- If a recording has no episode title, the trailing '~' is no longer shown in
the progress display.

View File

@ -200,3 +200,4 @@ VIVA2:12552:v:0:22000:171:172:0:0:12120
MTV German:12699:v:0:22000:3031:3032:0:0:28643 MTV German:12699:v:0:22000:3031:3032:0:0:28643
IFA-TV:10832:h:0:22000:132:133:32:0:7251 IFA-TV:10832:h:0:22000:132:133:32:0:7251
QVC Germany:12552:v:0:22000:165:166:0:0:12100 QVC Germany:12552:v:0:22000:165:166:0:0:12100
TANGOTV:10832:h:1:22000:61:62:0:0:61920

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: config.c 1.82 2002/02/03 15:25:44 kls Exp $ * $Id: config.c 1.83 2002/02/10 11:39:00 kls Exp $
*/ */
#include "config.h" #include "config.h"
@ -847,7 +847,7 @@ cSetup::cSetup(void)
ShowInfoOnChSwitch = 1; ShowInfoOnChSwitch = 1;
MenuScrollPage = 1; MenuScrollPage = 1;
MarkInstantRecord = 1; MarkInstantRecord = 1;
strcpy(NameInstantRecord, "TITLE-EPISODE"); strcpy(NameInstantRecord, "TITLE EPISODE");
LnbSLOF = 11700; LnbSLOF = 11700;
LnbFrequLo = 9750; LnbFrequLo = 9750;
LnbFrequHi = 10600; LnbFrequHi = 10600;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: config.h 1.93 2002/02/03 15:16:21 kls Exp $ * $Id: config.h 1.95 2002/02/10 15:44:40 kls Exp $
*/ */
#ifndef __CONFIG_H #ifndef __CONFIG_H
@ -19,7 +19,7 @@
#include "eit.h" #include "eit.h"
#include "tools.h" #include "tools.h"
#define VDRVERSION "0.99pre5" #define VDRVERSION "0.99"
#define MAXPRIORITY 99 #define MAXPRIORITY 99
#define MAXLIFETIME 99 #define MAXLIFETIME 99
@ -174,6 +174,8 @@ public:
const char *Execute(void); const char *Execute(void);
}; };
typedef uint32_t in_addr_t; //XXX from /usr/include/netinet/in.h (apparently this is not defined on systems with glibc < 2.2)
class cSVDRPhost : public cListObject { class cSVDRPhost : public cListObject {
private: private:
struct in_addr addr; struct in_addr addr;

47
eit.c
View File

@ -16,7 +16,7 @@
* the Free Software Foundation; either version 2 of the License, or * * the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. * * (at your option) any later version. *
* * * *
* $Id: eit.c 1.33 2002/02/02 12:12:26 kls Exp $ * $Id: eit.c 1.34 2002/02/09 14:48:43 kls Exp $
***************************************************************************/ ***************************************************************************/
#include "eit.h" #include "eit.h"
@ -352,7 +352,7 @@ void cEventInfo::Dump(FILE *f, const char *Prefix) const
} }
} }
#define MAXEPGBUGFIXSTATS 6 #define MAXEPGBUGFIXSTATS 5
#define MAXEPGBUGFIXCHANS 50 #define MAXEPGBUGFIXCHANS 50
struct tEpgBugFixStats { struct tEpgBugFixStats {
int hits; int hits;
@ -381,32 +381,39 @@ static void EpgBugFixStat(int Number, unsigned int ServiceID)
static void ReportEpgBugFixStats(bool Reset = false) static void ReportEpgBugFixStats(bool Reset = false)
{ {
if (Setup.EPGBugfixLevel > 0) { if (Setup.EPGBugfixLevel > 0) {
dsyslog(LOG_INFO, "====================="); bool GotHits = false;
dsyslog(LOG_INFO, "EPG bugfix statistics");
dsyslog(LOG_INFO, "=====================");
dsyslog(LOG_INFO, "IF SOMEBODY WHO IS IN CHARGE OF THE EPG DATA FOR ONE OF THE LISTED");
dsyslog(LOG_INFO, "CHANNELS READS THIS: PLEASE TAKE A LOOK AT THE FUNCTION cEventInfo::FixEpgBugs()");
dsyslog(LOG_INFO, "IN VDR/eit.c TO LEARN WHAT'S WRONG WITH YOUR DATA, AND FIX IT!");
dsyslog(LOG_INFO, "=====================");
dsyslog(LOG_INFO, "Fix\tHits\tChannels");
char buffer[1024]; char buffer[1024];
for (int i = 0; i < MAXEPGBUGFIXSTATS; i++) { for (int i = 0; i < MAXEPGBUGFIXSTATS; i++) {
const char *delim = "\t"; const char *delim = "\t";
tEpgBugFixStats *p = &EpgBugFixStats[i]; tEpgBugFixStats *p = &EpgBugFixStats[i];
char *q = buffer; if (p->hits) {
q += snprintf(q, sizeof(buffer) - (q - buffer), "%d\t%d", i, p->hits); if (!GotHits) {
for (int c = 0; c < p->n; c++) { dsyslog(LOG_INFO, "=====================");
cChannel *channel = Channels.GetByServiceID(p->serviceIDs[c]); dsyslog(LOG_INFO, "EPG bugfix statistics");
if (channel) { dsyslog(LOG_INFO, "=====================");
q += snprintf(q, sizeof(buffer) - (q - buffer), "%s%s", delim, channel->name); dsyslog(LOG_INFO, "IF SOMEBODY WHO IS IN CHARGE OF THE EPG DATA FOR ONE OF THE LISTED");
delim = ", "; dsyslog(LOG_INFO, "CHANNELS READS THIS: PLEASE TAKE A LOOK AT THE FUNCTION cEventInfo::FixEpgBugs()");
dsyslog(LOG_INFO, "IN VDR/eit.c TO LEARN WHAT'S WRONG WITH YOUR DATA, AND FIX IT!");
dsyslog(LOG_INFO, "=====================");
dsyslog(LOG_INFO, "Fix\tHits\tChannels");
GotHits = true;
}
char *q = buffer;
q += snprintf(q, sizeof(buffer) - (q - buffer), "%d\t%d", i, p->hits);
for (int c = 0; c < p->n; c++) {
cChannel *channel = Channels.GetByServiceID(p->serviceIDs[c]);
if (channel) {
q += snprintf(q, sizeof(buffer) - (q - buffer), "%s%s", delim, channel->name);
delim = ", ";
}
} }
} dsyslog(LOG_INFO, "%s", buffer);
dsyslog(LOG_INFO, "%s", buffer); }
if (Reset) if (Reset)
p->hits = p->n = 0; p->hits = p->n = 0;
} }
dsyslog(LOG_INFO, "====================="); if (GotHits)
dsyslog(LOG_INFO, "=====================");
} }
} }

BIN
gmon.out

Binary file not shown.

182
i18n.c

File diff suppressed because it is too large Load Diff

27
menu.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: menu.c 1.148 2002/02/03 15:42:38 kls Exp $ * $Id: menu.c 1.152 2002/02/10 11:52:34 kls Exp $
*/ */
#include "menu.h" #include "menu.h"
@ -1680,6 +1680,8 @@ eOSState cMenuRecordings::Del(void)
cOsdMenu::Del(Current()); cOsdMenu::Del(Current());
Recordings.Del(recording); Recordings.Del(recording);
Display(); Display();
if (!Count())
return osBack;
} }
else else
Interface->Error(tr("Error while deleting recording!")); Interface->Error(tr("Error while deleting recording!"));
@ -1707,6 +1709,7 @@ eOSState cMenuRecordings::Summary(void)
eOSState cMenuRecordings::ProcessKey(eKeys Key) eOSState cMenuRecordings::ProcessKey(eKeys Key)
{ {
bool HadSubMenu = HasSubMenu();
eOSState state = cOsdMenu::ProcessKey(Key); eOSState state = cOsdMenu::ProcessKey(Key);
if (state == osUnknown) { if (state == osUnknown) {
@ -1720,6 +1723,13 @@ eOSState cMenuRecordings::ProcessKey(eKeys Key)
default: break; default: break;
} }
} }
if (Key == kYellow && HadSubMenu && !HasSubMenu()) {
// the last recording in a subdirectory was deleted, so let's go back up
cOsdMenu::Del(Current());
if (!Count())
return osBack;
Display();
}
if (!HasSubMenu() && Key != kNone) if (!HasSubMenu() && Key != kNone)
SetHelpKeys(); SetHelpKeys();
return state; return state;
@ -1944,13 +1954,14 @@ cMenuMain::cMenuMain(bool Replaying, eOSState State)
// Title with disk usage: // Title with disk usage:
#define MB_PER_MINUTE 30 // this is just an estimate! #define MB_PER_MINUTE 25.75 // this is just an estimate!
char buffer[40]; char buffer[40];
int FreeMB; int FreeMB;
int Percent = VideoDiskSpace(&FreeMB); int Percent = VideoDiskSpace(&FreeMB);
int Hours = int(double(FreeMB) / MB_PER_MINUTE / 60); int Minutes = int(double(FreeMB) / MB_PER_MINUTE);
int Minutes = (FreeMB / MB_PER_MINUTE) % 60; int Hours = Minutes / 60;
Minutes %= 60;
snprintf(buffer, sizeof(buffer), "%s - Disk %d%% - %2d:%02d %s", tr("Main"), Percent, Hours, Minutes, tr("free")); snprintf(buffer, sizeof(buffer), "%s - Disk %d%% - %2d:%02d %s", tr("Main"), Percent, Hours, Minutes, tr("free"));
SetTitle(buffer); SetTitle(buffer);
@ -2113,10 +2124,11 @@ cDisplayChannel::cDisplayChannel(int Number, bool Switched)
{ {
group = -1; group = -1;
withInfo = !Switched || Setup.ShowInfoOnChSwitch; withInfo = !Switched || Setup.ShowInfoOnChSwitch;
int EpgLines = withInfo ? 5 : 1;
lines = 0; lines = 0;
oldNumber = number = 0; oldNumber = number = 0;
cChannel *channel = Channels.GetByNumber(Number); cChannel *channel = Channels.GetByNumber(Number);
Interface->Open(Setup.OSDwidth, Setup.ChannelInfoPos ? 5 : -5); Interface->Open(Setup.OSDwidth, Setup.ChannelInfoPos ? EpgLines : -EpgLines);
if (channel) { if (channel) {
DisplayChannel(channel); DisplayChannel(channel);
DisplayInfo(); DisplayInfo();
@ -2131,7 +2143,8 @@ cDisplayChannel::cDisplayChannel(eKeys FirstKey)
oldNumber = cDvbApi::CurrentChannel(); oldNumber = cDvbApi::CurrentChannel();
number = 0; number = 0;
lastTime = time_ms(); lastTime = time_ms();
Interface->Open(Setup.OSDwidth, Setup.ChannelInfoPos ? 5 : -5); int EpgLines = Setup.ShowInfoOnChSwitch ? 5 : 1;
Interface->Open(Setup.OSDwidth, Setup.ChannelInfoPos ? EpgLines : -EpgLines);
ProcessKey(FirstKey); ProcessKey(FirstKey);
} }
@ -2340,7 +2353,7 @@ cRecordControl::~cRecordControl()
bool cRecordControl::GetEventInfo(void) bool cRecordControl::GetEventInfo(void)
{ {
cChannel *channel = Channels.GetByNumber(timer->channel); cChannel *channel = Channels.GetByNumber(timer->channel);
time_t Time = timer->StartTime() + ((Setup.MarginStart * 2) + 1) * 60; time_t Time = timer->IsSingleEvent() ? timer->StartTime() + ((Setup.MarginStart * 2) + 1) * 60 : timer->StartTime() + (timer->StopTime() - timer->StartTime()) / 2;
for (int seconds = 0; seconds <= MAXWAIT4EPGINFO; seconds++) { for (int seconds = 0; seconds <= MAXWAIT4EPGINFO; seconds++) {
{ {
cThreadLock ThreadLock; cThreadLock ThreadLock;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: recording.c 1.49 2002/02/03 15:46:42 kls Exp $ * $Id: recording.c 1.51 2002/02/10 15:41:23 kls Exp $
*/ */
#include "recording.h" #include "recording.h"
@ -196,22 +196,82 @@ tCharExchange CharExchange[] = {
{ ' ', '_' }, { ' ', '_' },
{ '\'', '\x01' }, { '\'', '\x01' },
{ '/', '\x02' }, { '/', '\x02' },
#ifdef VFAT
{ ':', '\x03' },
#endif
{ 0, 0 } { 0, 0 }
}; };
char *ExchangeChars(char *s, bool ToFileSystem) static char *ExchangeChars(char *s, bool ToFileSystem)
{ {
char *p = s; char *p = s;
while (*p) { while (*p) {
#define VFAT 1
#ifdef VFAT
// The VFAT file system can't handle all characters, so we
// have to take extra efforts to encode/decode them:
if (ToFileSystem) {
switch (*p) {
// characters that can be used "as is":
case '!':
case '@':
case '$':
case '%':
case '&':
case '(':
case ')':
case '+':
case ',':
case '-':
case '.':
case ';':
case '=':
case '0' ... '9':
case 'a' ... 'z':
case 'A' ... 'Z': break;
// characters that can be mapped to other characters:
case ' ': *p = '_'; break;
case '~': *p = '/'; break;
// characters that have to be encoded:
default: {
int l = p - s;
s = (char *)realloc(s, strlen(s) + 10);
p = s + l;
char buf[4];
sprintf(buf, "#%02X", (unsigned char)*p);
memmove(p + 2, p, strlen(p) + 1);
strncpy(p, buf, 3);
p += 2;
}
}
}
else {
switch (*p) {
// mapped characters:
case '_': *p = ' '; break;
case '/': *p = '~'; break;
// encodes characters:
case '#': {
if (strlen(p) > 2) {
char buf[3];
sprintf(buf, "%c%c", *(p + 1), *(p + 2));
unsigned char c = strtol(buf, NULL, 16);
*p = c;
memmove(p + 1, p + 3, strlen(p) - 2);
}
}
break;
// backwards compatibility:
case '\x01': *p = '\''; break;
case '\x02': *p = '/'; break;
case '\x03': *p = ':'; break;
}
}
#else
for (struct tCharExchange *ce = CharExchange; ce->a && ce->b; ce++) { for (struct tCharExchange *ce = CharExchange; ce->a && ce->b; ce++) {
if (*p == (ToFileSystem ? ce->a : ce->b)) { if (*p == (ToFileSystem ? ce->a : ce->b)) {
*p = ToFileSystem ? ce->b : ce->a; *p = ToFileSystem ? ce->b : ce->a;
break; break;
} }
} }
#endif
p++; p++;
} }
return s; return s;
@ -285,7 +345,7 @@ cRecording::cRecording(const char *FileName)
name = new char[p - FileName + 1]; name = new char[p - FileName + 1];
strncpy(name, FileName, p - FileName); strncpy(name, FileName, p - FileName);
name[p - FileName] = 0; name[p - FileName] = 0;
ExchangeChars(name, false); name = ExchangeChars(name, false);
} }
// read an optional summary file: // read an optional summary file:
char *SummaryFileName = NULL; char *SummaryFileName = NULL;
@ -384,9 +444,9 @@ const char *cRecording::FileName(void)
if (!fileName) { if (!fileName) {
struct tm tm_r; struct tm tm_r;
struct tm *t = localtime_r(&start, &tm_r); struct tm *t = localtime_r(&start, &tm_r);
ExchangeChars(name, true); name = ExchangeChars(name, true);
asprintf(&fileName, NAMEFORMAT, VideoDirectory, name, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, priority, lifetime); asprintf(&fileName, NAMEFORMAT, VideoDirectory, name, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, priority, lifetime);
ExchangeChars(name, false); name = ExchangeChars(name, false);
} }
return fileName; return fileName;
} }
@ -399,7 +459,7 @@ const char *cRecording::Title(char Delimiter, bool NewIndicator, int Level)
if (Level < 0 || Level == HierarchyLevels()) { if (Level < 0 || Level == HierarchyLevels()) {
struct tm tm_r; struct tm tm_r;
struct tm *t = localtime_r(&start, &tm_r); struct tm *t = localtime_r(&start, &tm_r);
const char *s; char *s;
if (Level > 0 && (s = strrchr(name, '~')) != NULL) if (Level > 0 && (s = strrchr(name, '~')) != NULL)
s++; s++;
else else
@ -413,6 +473,11 @@ const char *cRecording::Title(char Delimiter, bool NewIndicator, int Level)
New, New,
Delimiter, Delimiter,
s); s);
// let's not display a trailing '~':
stripspace(titleBuffer);
s = &titleBuffer[strlen(titleBuffer) - 1];
if (*s == '~')
*s = 0;
} }
else if (Level < HierarchyLevels()) { else if (Level < HierarchyLevels()) {
const char *s = name; const char *s = name;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: tools.c 1.56 2002/02/03 16:44:08 kls Exp $ * $Id: tools.c 1.57 2002/02/05 18:16:52 kls Exp $
*/ */
#include "tools.h" #include "tools.h"
@ -804,8 +804,10 @@ void cListBase::Move(cListObject *From, cListObject *To)
To->Prev()->Append(From); To->Prev()->Append(From);
From->Append(To); From->Append(To);
} }
else else {
lastObject->Append(From); lastObject->Append(From);
lastObject = From;
}
if (!From->Prev()) if (!From->Prev())
objects = From; objects = From;
} }

11
vdr.c
View File

@ -22,7 +22,7 @@
* *
* The project's page is at http://www.cadsoft.de/people/kls/vdr * The project's page is at http://www.cadsoft.de/people/kls/vdr
* *
* $Id: vdr.c 1.94 2002/02/02 15:50:43 kls Exp $ * $Id: vdr.c 1.95 2002/02/10 15:12:43 kls Exp $
*/ */
#include <getopt.h> #include <getopt.h>
@ -494,13 +494,20 @@ int main(int argc, char *argv[])
else else
LastActivity = 1; LastActivity = 1;
} }
bool UserShutdown = key == kPower;
if (UserShutdown && Next && Delta <= Setup.MinEventTimeout * 60 && !ForceShutdown) {
char *buf;
asprintf(&buf, tr("Recording in %d minutes, shut down anyway?"), Delta / 60);
if (Interface->Confirm(buf))
ForceShutdown = true;
delete buf;
}
if (!Next || Delta > Setup.MinEventTimeout * 60 || ForceShutdown) { if (!Next || Delta > Setup.MinEventTimeout * 60 || ForceShutdown) {
ForceShutdown = false; ForceShutdown = false;
if (timer) if (timer)
dsyslog(LOG_INFO, "next timer event at %s", ctime(&Next)); dsyslog(LOG_INFO, "next timer event at %s", ctime(&Next));
if (WatchdogTimeout > 0) if (WatchdogTimeout > 0)
signal(SIGALRM, SIG_IGN); signal(SIGALRM, SIG_IGN);
bool UserShutdown = key == kPower;
if (Interface->Confirm(tr("Press any key to cancel shutdown"), UserShutdown ? 5 : SHUTDOWNWAIT, true)) { if (Interface->Confirm(tr("Press any key to cancel shutdown"), UserShutdown ? 5 : SHUTDOWNWAIT, true)) {
int Channel = timer ? timer->channel : 0; int Channel = timer ? timer->channel : 0;
const char *File = timer ? timer->file : ""; const char *File = timer ? timer->file : "";