vdr  2.4.1
vdr.c
Go to the documentation of this file.
1 /*
2  * vdr.c: Video Disk Recorder main program
3  *
4  * Copyright (C) 2000-2018 Klaus Schmidinger
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  *
21  * The author can be reached at vdr@tvdr.de
22  *
23  * The project's page is at http://www.tvdr.de
24  *
25  * $Id: vdr.c 4.25.1.5 2019/05/23 10:02:45 kls Exp $
26  */
27 
28 #include <getopt.h>
29 #include <grp.h>
30 #include <langinfo.h>
31 #include <locale.h>
32 #include <pwd.h>
33 #include <signal.h>
34 #include <stdlib.h>
35 #include <sys/capability.h>
36 #include <sys/prctl.h>
37 #ifdef SDNOTIFY
38 #include <systemd/sd-daemon.h>
39 #endif
40 #include <termios.h>
41 #include <unistd.h>
42 #include "args.h"
43 #include "audio.h"
44 #include "channels.h"
45 #include "config.h"
46 #include "cutter.h"
47 #include "device.h"
48 #include "diseqc.h"
49 #include "dvbdevice.h"
50 #include "eitscan.h"
51 #include "epg.h"
52 #include "i18n.h"
53 #include "interface.h"
54 #include "keys.h"
55 #include "libsi/si.h"
56 #include "lirc.h"
57 #include "menu.h"
58 #include "osdbase.h"
59 #include "plugin.h"
60 #include "recording.h"
61 #include "shutdown.h"
62 #include "skinclassic.h"
63 #include "skinlcars.h"
64 #include "skinsttng.h"
65 #include "sourceparams.h"
66 #include "sources.h"
67 #include "status.h"
68 #include "svdrp.h"
69 #include "themes.h"
70 #include "timers.h"
71 #include "tools.h"
72 #include "transfer.h"
73 #include "videodir.h"
74 
75 #define MINCHANNELWAIT 10 // seconds to wait between failed channel switchings
76 #define ACTIVITYTIMEOUT 60 // seconds before starting housekeeping
77 #define SHUTDOWNWAIT 300 // seconds to wait in user prompt before automatic shutdown
78 #define SHUTDOWNRETRY 360 // seconds before trying again to shut down
79 #define SHUTDOWNFORCEPROMPT 5 // seconds to wait in user prompt to allow forcing shutdown
80 #define SHUTDOWNCANCELPROMPT 5 // seconds to wait in user prompt to allow canceling shutdown
81 #define RESTARTCANCELPROMPT 5 // seconds to wait in user prompt before restarting on SIGHUP
82 #define MANUALSTART 600 // seconds the next timer must be in the future to assume manual start
83 #define CHANNELSAVEDELTA 600 // seconds before saving channels.conf after automatic modifications
84 #define DEVICEREADYTIMEOUT 30 // seconds to wait until all devices are ready
85 #define MENUTIMEOUT 120 // seconds of user inactivity after which an OSD display is closed
86 #define TIMERCHECKDELTA 10 // seconds between checks for timers that need to see their channel
87 #define TIMERDEVICETIMEOUT 8 // seconds before a device used for timer check may be reused
88 #define TIMERLOOKAHEADTIME 60 // seconds before a non-VPS timer starts and the channel is switched if possible
89 #define VPSLOOKAHEADTIME 24 // hours within which VPS timers will make sure their events are up to date
90 #define VPSUPTODATETIME 3600 // seconds before the event or schedule of a VPS timer needs to be refreshed
91 
92 #define EXIT(v) { ShutdownHandler.Exit(v); goto Exit; }
93 
94 static int LastSignal = 0;
95 
96 static bool SetUser(const char *User, bool UserDump)
97 {
98  if (User) {
99  struct passwd *user = isnumber(User) ? getpwuid(atoi(User)) : getpwnam(User);
100  if (!user) {
101  fprintf(stderr, "vdr: unknown user: '%s'\n", User);
102  return false;
103  }
104  if (setgid(user->pw_gid) < 0) {
105  fprintf(stderr, "vdr: cannot set group id %u: %s\n", (unsigned int)user->pw_gid, strerror(errno));
106  return false;
107  }
108  if (initgroups(user->pw_name, user->pw_gid) < 0) {
109  fprintf(stderr, "vdr: cannot set supplemental group ids for user %s: %s\n", user->pw_name, strerror(errno));
110  return false;
111  }
112  if (setuid(user->pw_uid) < 0) {
113  fprintf(stderr, "vdr: cannot set user id %u: %s\n", (unsigned int)user->pw_uid, strerror(errno));
114  return false;
115  }
116  if (UserDump && prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0)
117  fprintf(stderr, "vdr: warning - cannot set dumpable: %s\n", strerror(errno));
118  setenv("HOME", user->pw_dir, 1);
119  setenv("USER", user->pw_name, 1);
120  setenv("LOGNAME", user->pw_name, 1);
121  setenv("SHELL", user->pw_shell, 1);
122  }
123  return true;
124 }
125 
126 static bool DropCaps(void)
127 {
128  // drop all capabilities except selected ones
129  cap_t caps_all = cap_get_proc();
130  if (!caps_all) {
131  fprintf(stderr, "vdr: cap_get_proc failed: %s\n", strerror(errno));
132  return false;
133  }
134  char *caps_text = cap_to_text(caps_all, NULL);
135  if (!caps_text) {
136  fprintf(stderr, "vdr: cap_to_text failed: %s\n", strerror(errno));
137  return false;
138  }
139  if (cap_free(caps_all)) {
140  fprintf(stderr, "vdr: cap_free failed: %s\n", strerror(errno));
141  return false;
142  }
143  cap_t caps;
144  if (strstr(caps_text,"cap_sys_time"))
145  caps = cap_from_text("= cap_sys_nice,cap_sys_time,cap_net_raw=ep");
146  else
147  caps = cap_from_text("= cap_sys_nice,cap_net_raw=ep");
148  if (!caps) {
149  fprintf(stderr, "vdr: cap_from_text failed: %s\n", strerror(errno));
150  return false;
151  }
152  if (cap_set_proc(caps) == -1) {
153  fprintf(stderr, "vdr: cap_set_proc failed: %s\n", strerror(errno));
154  cap_free(caps);
155  return false;
156  }
157  cap_free(caps);
158  return true;
159 }
160 
161 static bool SetKeepCaps(bool On)
162 {
163  // set keeping capabilities during setuid() on/off
164  if (prctl(PR_SET_KEEPCAPS, On ? 1 : 0, 0, 0, 0) != 0) {
165  fprintf(stderr, "vdr: prctl failed\n");
166  return false;
167  }
168  return true;
169 }
170 
171 static void SignalHandler(int signum)
172 {
173  switch (signum) {
174  case SIGPIPE:
175  break;
176  case SIGHUP:
177  LastSignal = signum;
178  break;
179  default:
180  LastSignal = signum;
181  Interface->Interrupt();
182  ShutdownHandler.Exit(0);
183  }
184  signal(signum, SignalHandler);
185 }
186 
187 static void Watchdog(int signum)
188 {
189  // Something terrible must have happened that prevented the 'alarm()' from
190  // being called in time, so let's get out of here:
191  esyslog("PANIC: watchdog timer expired - exiting!");
192 #ifdef SDNOTIFY
193  sd_notify(0, "STOPPING=1\nSTATUS=PANIC");
194 #endif
195  exit(1);
196 }
197 
198 int main(int argc, char *argv[])
199 {
200  // Save terminal settings:
201 
202  struct termios savedTm;
203  bool HasStdin = (tcgetpgrp(STDIN_FILENO) == getpid() || getppid() != (pid_t)1) && tcgetattr(STDIN_FILENO, &savedTm) == 0;
204 
205  // Initiate locale:
206 
207  setlocale(LC_ALL, "");
208 
209  // Command line options:
210 
211 #define dd(a, b) (*a ? a : b)
212 #define DEFAULTSVDRPPORT 6419
213 #define DEFAULTWATCHDOG 0 // seconds
214 #define DEFAULTVIDEODIR VIDEODIR
215 #define DEFAULTCONFDIR dd(CONFDIR, VideoDirectory)
216 #define DEFAULTARGSDIR dd(ARGSDIR, "/etc/vdr/conf.d")
217 #define DEFAULTCACHEDIR dd(CACHEDIR, VideoDirectory)
218 #define DEFAULTRESDIR dd(RESDIR, ConfigDirectory)
219 #define DEFAULTPLUGINDIR PLUGINDIR
220 #define DEFAULTLOCDIR LOCDIR
221 #define DEFAULTEPGDATAFILENAME "epg.data"
222 
223  bool StartedAsRoot = false;
224  const char *VdrUser = NULL;
225  bool UserDump = false;
226  int SVDRPport = DEFAULTSVDRPPORT;
227  const char *AudioCommand = NULL;
228  const char *VideoDirectory = DEFAULTVIDEODIR;
229  const char *ConfigDirectory = NULL;
230  const char *CacheDirectory = NULL;
231  const char *ResourceDirectory = NULL;
232  const char *LocaleDirectory = DEFAULTLOCDIR;
233  const char *EpgDataFileName = DEFAULTEPGDATAFILENAME;
234  bool DisplayHelp = false;
235  bool DisplayVersion = false;
236  bool DaemonMode = false;
237  int SysLogTarget = LOG_USER;
238  bool MuteAudio = false;
239  int WatchdogTimeout = DEFAULTWATCHDOG;
240  const char *Terminal = NULL;
241  const char *OverrideCharacterTable = NULL;
242 #ifndef DEPRECATED_VDR_CHARSET_OVERRIDE
243 #define DEPRECATED_VDR_CHARSET_OVERRIDE 0
244 #endif
245 #if DEPRECATED_VDR_CHARSET_OVERRIDE
246  OverrideCharacterTable = getenv("VDR_CHARSET_OVERRIDE");
247  const char *DeprecatedVdrCharsetOverride = OverrideCharacterTable;
248 #endif
249 
250  bool UseKbd = true;
251  const char *LircDevice = NULL;
252 #if !defined(REMOTE_KBD)
253  UseKbd = false;
254 #endif
255 #if defined(REMOTE_LIRC)
256  LircDevice = LIRC_DEVICE;
257 #endif
258 #if defined(VDR_USER)
259  VdrUser = VDR_USER;
260 #endif
261 #ifdef SDNOTIFY
262  time_t SdWatchdog = 0;
263  int SdWatchdogTimeout = 0;
264 #endif
265 
266  cArgs *Args = NULL;
267  if (argc == 1) {
268  Args = new cArgs(argv[0]);
269  if (Args->ReadDirectory(DEFAULTARGSDIR)) {
270  argc = Args->GetArgc();
271  argv = Args->GetArgv();
272  }
273  }
274 
275  cVideoDirectory::SetName(VideoDirectory);
276  cPluginManager PluginManager(DEFAULTPLUGINDIR);
277 
278  static struct option long_options[] = {
279  { "audio", required_argument, NULL, 'a' },
280  { "cachedir", required_argument, NULL, 'c' | 0x100 },
281  { "chartab", required_argument, NULL, 'c' | 0x200 },
282  { "config", required_argument, NULL, 'c' },
283  { "daemon", no_argument, NULL, 'd' },
284  { "device", required_argument, NULL, 'D' },
285  { "dirnames", required_argument, NULL, 'd' | 0x100 },
286  { "edit", required_argument, NULL, 'e' | 0x100 },
287  { "epgfile", required_argument, NULL, 'E' },
288  { "filesize", required_argument, NULL, 'f' | 0x100 },
289  { "genindex", required_argument, NULL, 'g' | 0x100 },
290  { "grab", required_argument, NULL, 'g' },
291  { "help", no_argument, NULL, 'h' },
292  { "instance", required_argument, NULL, 'i' },
293  { "lib", required_argument, NULL, 'L' },
294  { "lirc", optional_argument, NULL, 'l' | 0x100 },
295  { "localedir",required_argument, NULL, 'l' | 0x200 },
296  { "log", required_argument, NULL, 'l' },
297  { "mute", no_argument, NULL, 'm' },
298  { "no-kbd", no_argument, NULL, 'n' | 0x100 },
299  { "plugin", required_argument, NULL, 'P' },
300  { "port", required_argument, NULL, 'p' },
301  { "record", required_argument, NULL, 'r' },
302  { "resdir", required_argument, NULL, 'r' | 0x100 },
303  { "showargs", optional_argument, NULL, 's' | 0x200 },
304  { "shutdown", required_argument, NULL, 's' },
305  { "split", no_argument, NULL, 's' | 0x100 },
306  { "terminal", required_argument, NULL, 't' },
307  { "updindex", required_argument, NULL, 'u' | 0x200 },
308  { "user", required_argument, NULL, 'u' },
309  { "userdump", no_argument, NULL, 'u' | 0x100 },
310  { "version", no_argument, NULL, 'V' },
311  { "vfat", no_argument, NULL, 'v' | 0x100 },
312  { "video", required_argument, NULL, 'v' },
313  { "watchdog", required_argument, NULL, 'w' },
314  { NULL, no_argument, NULL, 0 }
315  };
316 
317  int c;
318  while ((c = getopt_long(argc, argv, "a:c:dD:e:E:g:hi:l:L:mp:P:r:s:t:u:v:Vw:", long_options, NULL)) != -1) {
319  switch (c) {
320  case 'a': AudioCommand = optarg;
321  break;
322  case 'c' | 0x100:
323  CacheDirectory = optarg;
324  break;
325  case 'c' | 0x200:
326  OverrideCharacterTable = optarg;
327  break;
328  case 'c': ConfigDirectory = optarg;
329  break;
330  case 'd': DaemonMode = true;
331  break;
332  case 'D': if (*optarg == '-') {
334  break;
335  }
336  if (isnumber(optarg)) {
337  int n = atoi(optarg);
338  if (0 <= n && n < MAXDEVICES) {
340  break;
341  }
342  }
343  fprintf(stderr, "vdr: invalid DVB device number: %s\n", optarg);
344  return 2;
345  case 'd' | 0x100: {
346  char *s = optarg;
347  if (*s != ',') {
348  int n = strtol(s, &s, 10);
349  if (n <= 0 || n >= PATH_MAX) { // PATH_MAX includes the terminating 0
350  fprintf(stderr, "vdr: invalid directory path length: %s\n", optarg);
351  return 2;
352  }
353  DirectoryPathMax = n;
354  if (!*s)
355  break;
356  if (*s != ',') {
357  fprintf(stderr, "vdr: invalid delimiter: %s\n", optarg);
358  return 2;
359  }
360  }
361  s++;
362  if (!*s)
363  break;
364  if (*s != ',') {
365  int n = strtol(s, &s, 10);
366  if (n <= 0 || n > NAME_MAX) { // NAME_MAX excludes the terminating 0
367  fprintf(stderr, "vdr: invalid directory name length: %s\n", optarg);
368  return 2;
369  }
370  DirectoryNameMax = n;
371  if (!*s)
372  break;
373  if (*s != ',') {
374  fprintf(stderr, "vdr: invalid delimiter: %s\n", optarg);
375  return 2;
376  }
377  }
378  s++;
379  if (!*s)
380  break;
381  int n = strtol(s, &s, 10);
382  if (n != 0 && n != 1) {
383  fprintf(stderr, "vdr: invalid directory encoding: %s\n", optarg);
384  return 2;
385  }
386  DirectoryEncoding = n;
387  if (*s) {
388  fprintf(stderr, "vdr: unexpected data: %s\n", optarg);
389  return 2;
390  }
391  }
392  break;
393  case 'e' | 0x100:
394  return CutRecording(optarg) ? 0 : 2;
395  case 'E': EpgDataFileName = (*optarg != '-' ? optarg : NULL);
396  break;
397  case 'f' | 0x100:
398  Setup.MaxVideoFileSize = StrToNum(optarg) / MEGABYTE(1);
403  break;
404  case 'g' | 0x100:
405  return GenerateIndex(optarg) ? 0 : 2;
406  case 'g': SetSVDRPGrabImageDir(*optarg != '-' ? optarg : NULL);
407  break;
408  case 'h': DisplayHelp = true;
409  break;
410  case 'i': if (isnumber(optarg)) {
411  InstanceId = atoi(optarg);
412  if (InstanceId >= 0)
413  break;
414  }
415  fprintf(stderr, "vdr: invalid instance id: %s\n", optarg);
416  return 2;
417  case 'l': {
418  char *p = strchr(optarg, '.');
419  if (p)
420  *p = 0;
421  if (isnumber(optarg)) {
422  int l = atoi(optarg);
423  if (0 <= l && l <= 3) {
424  SysLogLevel = l;
425  if (!p)
426  break;
427  if (isnumber(p + 1)) {
428  int l = atoi(p + 1);
429  if (0 <= l && l <= 7) {
430  int targets[] = { LOG_LOCAL0, LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4, LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7 };
431  SysLogTarget = targets[l];
432  break;
433  }
434  }
435  }
436  }
437  if (p)
438  *p = '.';
439  fprintf(stderr, "vdr: invalid log level: %s\n", optarg);
440  return 2;
441  }
442  case 'L': if (access(optarg, R_OK | X_OK) == 0)
443  PluginManager.SetDirectory(optarg);
444  else {
445  fprintf(stderr, "vdr: can't access plugin directory: %s\n", optarg);
446  return 2;
447  }
448  break;
449  case 'l' | 0x100:
450  LircDevice = optarg ? optarg : LIRC_DEVICE;
451  break;
452  case 'l' | 0x200:
453  if (access(optarg, R_OK | X_OK) == 0)
454  LocaleDirectory = optarg;
455  else {
456  fprintf(stderr, "vdr: can't access locale directory: %s\n", optarg);
457  return 2;
458  }
459  break;
460  case 'm': MuteAudio = true;
461  break;
462  case 'n' | 0x100:
463  UseKbd = false;
464  break;
465  case 'p': if (isnumber(optarg))
466  SVDRPport = atoi(optarg);
467  else {
468  fprintf(stderr, "vdr: invalid port number: %s\n", optarg);
469  return 2;
470  }
471  break;
472  case 'P': PluginManager.AddPlugin(optarg);
473  break;
474  case 'r': cRecordingUserCommand::SetCommand(optarg);
475  break;
476  case 'r' | 0x100:
477  ResourceDirectory = optarg;
478  break;
479  case 's': ShutdownHandler.SetShutdownCommand(optarg);
480  break;
481  case 's' | 0x100:
483  break;
484  case 's' | 0x200: {
485  const char *ArgsDir = optarg ? optarg : DEFAULTARGSDIR;
486  cArgs Args(argv[0]);
487  if (!Args.ReadDirectory(ArgsDir)) {
488  fprintf(stderr, "vdr: can't read arguments from directory: %s\n", ArgsDir);
489  return 2;
490  }
491  int c = Args.GetArgc();
492  char **v = Args.GetArgv();
493  for (int i = 1; i < c; i++)
494  printf("%s\n", v[i]);
495  return 0;
496  }
497  case 't': Terminal = optarg;
498  if (access(Terminal, R_OK | W_OK) < 0) {
499  fprintf(stderr, "vdr: can't access terminal: %s\n", Terminal);
500  return 2;
501  }
502  break;
503  case 'u': if (*optarg)
504  VdrUser = optarg;
505  break;
506  case 'u' | 0x100:
507  UserDump = true;
508  break;
509  case 'u' | 0x200:
510  return GenerateIndex(optarg, true) ? 0 : 2;
511  case 'V': DisplayVersion = true;
512  break;
513  case 'v' | 0x100:
514  DirectoryPathMax = 250;
515  DirectoryNameMax = 40;
516  DirectoryEncoding = true;
517  break;
518  case 'v': VideoDirectory = optarg;
519  while (optarg && *optarg && optarg[strlen(optarg) - 1] == '/')
520  optarg[strlen(optarg) - 1] = 0;
521  cVideoDirectory::SetName(VideoDirectory);
522  break;
523  case 'w': if (isnumber(optarg)) {
524  int t = atoi(optarg);
525  if (t >= 0) {
526  WatchdogTimeout = t;
527  break;
528  }
529  }
530  fprintf(stderr, "vdr: invalid watchdog timeout: %s\n", optarg);
531  return 2;
532  default: return 2;
533  }
534  }
535 
536  // Set user id in case we were started as root:
537 
538  if (VdrUser && geteuid() == 0) {
539  StartedAsRoot = true;
540  if (strcmp(VdrUser, "root") && strcmp(VdrUser, "0")) {
541  if (!SetKeepCaps(true))
542  return 2;
543  if (!SetUser(VdrUser, UserDump))
544  return 2;
545  if (!SetKeepCaps(false))
546  return 2;
547  if (!DropCaps())
548  return 2;
549  }
550  }
551 
552  // Help and version info:
553 
554  if (DisplayHelp || DisplayVersion) {
555  if (!PluginManager.HasPlugins())
556  PluginManager.AddPlugin("*"); // adds all available plugins
557  PluginManager.LoadPlugins();
558  if (DisplayHelp) {
559  printf("Usage: vdr [OPTIONS]\n\n" // for easier orientation, this is column 80|
560  " -a CMD, --audio=CMD send Dolby Digital audio to stdin of command CMD\n"
561  " --cachedir=DIR save cache files in DIR (default: %s)\n"
562  " --chartab=CHARACTER_TABLE\n"
563  " set the character table to use for strings in the\n"
564  " DVB data stream that don't begin with a character\n"
565  " table indicator, but don't use the standard default\n"
566  " character table (for instance ISO-8859-9)\n"
567  " -c DIR, --config=DIR read config files from DIR (default: %s)\n"
568  " -d, --daemon run in daemon mode\n"
569  " -D NUM, --device=NUM use only the given DVB device (NUM = 0, 1, 2...)\n"
570  " there may be several -D options (default: all DVB\n"
571  " devices will be used); if -D- is given, no DVB\n"
572  " devices will be used at all, independent of any\n"
573  " other -D options\n"
574  " --dirnames=PATH[,NAME[,ENC]]\n"
575  " set the maximum directory path length to PATH\n"
576  " (default: %d); if NAME is also given, it defines\n"
577  " the maximum directory name length (default: %d);\n"
578  " the optional ENC can be 0 or 1, and controls whether\n"
579  " special characters in directory names are encoded as\n"
580  " hex values (default: 0); if PATH or NAME are left\n"
581  " empty (as in \",,1\" to only set ENC), the defaults\n"
582  " apply\n"
583  " --edit=REC cut recording REC and exit\n"
584  " -E FILE, --epgfile=FILE write the EPG data into the given FILE (default is\n"
585  " '%s' in the cache directory)\n"
586  " '-E-' disables this\n"
587  " if FILE is a directory, the default EPG file will be\n"
588  " created in that directory\n"
589  " --filesize=SIZE limit video files to SIZE bytes (default is %dM)\n"
590  " only useful in conjunction with --edit\n"
591  " --genindex=REC generate index for recording REC and exit\n"
592  " -g DIR, --grab=DIR write images from the SVDRP command GRAB into the\n"
593  " given DIR; DIR must be the full path name of an\n"
594  " existing directory, without any \"..\", double '/'\n"
595  " or symlinks (default: none, same as -g-)\n"
596  " -h, --help print this help and exit\n"
597  " -i ID, --instance=ID use ID as the id of this VDR instance (default: 0)\n"
598  " -l LEVEL, --log=LEVEL set log level (default: 3)\n"
599  " 0 = no logging, 1 = errors only,\n"
600  " 2 = errors and info, 3 = errors, info and debug\n"
601  " if logging should be done to LOG_LOCALn instead of\n"
602  " LOG_USER, add '.n' to LEVEL, as in 3.7 (n=0..7)\n"
603  " -L DIR, --lib=DIR search for plugins in DIR (default is %s)\n"
604  " --lirc[=PATH] use a LIRC remote control device, attached to PATH\n"
605  " (default: %s)\n"
606  " --localedir=DIR search for locale files in DIR (default is\n"
607  " %s)\n"
608  " -m, --mute mute audio of the primary DVB device at startup\n"
609  " --no-kbd don't use the keyboard as an input device\n"
610  " -p PORT, --port=PORT use PORT for SVDRP (default: %d)\n"
611  " 0 turns off SVDRP\n"
612  " -P OPT, --plugin=OPT load a plugin defined by the given options\n"
613  " -r CMD, --record=CMD call CMD before and after a recording, and after\n"
614  " a recording has been edited or deleted\n"
615  " --resdir=DIR read resource files from DIR (default: %s)\n"
616  " -s CMD, --shutdown=CMD call CMD to shutdown the computer\n"
617  " --split split edited files at the editing marks (only\n"
618  " useful in conjunction with --edit)\n"
619  " --showargs[=DIR] print the arguments read from DIR and exit\n"
620  " (default: %s)\n"
621  " -t TTY, --terminal=TTY controlling tty\n"
622  " -u USER, --user=USER run as user USER; only applicable if started as\n"
623  " root; USER can be a user name or a numerical id\n"
624  " --updindex=REC update index for recording REC and exit\n"
625  " --userdump allow coredumps if -u is given (debugging)\n"
626  " -v DIR, --video=DIR use DIR as video directory (default: %s)\n"
627  " -V, --version print version information and exit\n"
628  " --vfat for backwards compatibility (same as\n"
629  " --dirnames=250,40,1)\n"
630  " -w SEC, --watchdog=SEC activate the watchdog timer with a timeout of SEC\n"
631  " seconds (default: %d); '0' disables the watchdog\n"
632  "\n",
635  PATH_MAX - 1,
636  NAME_MAX,
640  LIRC_DEVICE,
647  );
648  }
649  if (DisplayVersion)
650  printf("vdr (%s/%s) - The Video Disk Recorder\n", VDRVERSION, APIVERSION);
651  if (PluginManager.HasPlugins()) {
652  if (DisplayHelp)
653  printf("Plugins: vdr -P\"name [OPTIONS]\"\n\n");
654  for (int i = 0; ; i++) {
655  cPlugin *p = PluginManager.GetPlugin(i);
656  if (p) {
657  const char *help = p->CommandLineHelp();
658  printf("%s (%s) - %s\n", p->Name(), p->Version(), p->Description());
659  if (DisplayHelp && help) {
660  printf("\n");
661  puts(help);
662  }
663  }
664  else
665  break;
666  }
667  }
668  return 0;
669  }
670 
671  // Log file:
672 
673  if (SysLogLevel > 0)
674  openlog("vdr", LOG_CONS, SysLogTarget); // LOG_PID doesn't work as expected under NPTL
675 
676  // Check the video directory:
677 
678  if (!DirectoryOk(VideoDirectory, true)) {
679  fprintf(stderr, "vdr: can't access video directory %s\n", VideoDirectory);
680  return 2;
681  }
682 
683  // Daemon mode:
684 
685  if (DaemonMode) {
686  if (daemon(1, 0) == -1) {
687  fprintf(stderr, "vdr: %m\n");
688  esyslog("ERROR: %m");
689  return 2;
690  }
691  }
692  else if (Terminal) {
693  // Claim new controlling terminal
694  stdin = freopen(Terminal, "r", stdin);
695  stdout = freopen(Terminal, "w", stdout);
696  stderr = freopen(Terminal, "w", stderr);
697  HasStdin = true;
698  tcgetattr(STDIN_FILENO, &savedTm);
699  }
700 
701  isyslog("VDR version %s started", VDRVERSION);
702  if (StartedAsRoot && VdrUser)
703  isyslog("switched to user '%s'", VdrUser);
704  if (DaemonMode)
705  dsyslog("running as daemon (tid=%d)", cThread::ThreadId());
707 
708  // Set the system character table:
709 
710  char *CodeSet = NULL;
711  if (setlocale(LC_CTYPE, ""))
712  CodeSet = nl_langinfo(CODESET);
713  else {
714  char *LangEnv = getenv("LANG"); // last resort in case locale stuff isn't installed
715  if (LangEnv) {
716  CodeSet = strchr(LangEnv, '.');
717  if (CodeSet)
718  CodeSet++; // skip the dot
719  }
720  }
721  if (CodeSet) {
722  bool known = SI::SetSystemCharacterTable(CodeSet);
723  isyslog("codeset is '%s' - %s", CodeSet, known ? "known" : "unknown");
725  }
726 #if DEPRECATED_VDR_CHARSET_OVERRIDE
727  if (DeprecatedVdrCharsetOverride)
728  isyslog("use of environment variable VDR_CHARSET_OVERRIDE (%s) is deprecated!", DeprecatedVdrCharsetOverride);
729 #endif
731  isyslog("override character table is '%s'", OverrideCharacterTable);
733  }
734 
735  // Initialize internationalization:
736 
737  I18nInitialize(LocaleDirectory);
738 
739  // Main program loop variables - need to be here to have them initialized before any EXIT():
740 
741  cEpgDataReader EpgDataReader;
742  cOsdObject *Menu = NULL;
743  int LastChannel = 0;
744  int LastTimerChannel = -1;
745  int PreviousChannel[2] = { 1, 1 };
746  int PreviousChannelIndex = 0;
747  time_t LastChannelChanged = time(NULL);
748  time_t LastInteract = 0;
749  int MaxLatencyTime = 0;
750  bool InhibitEpgScan = false;
751  bool IsInfoMenu = false;
752  cSkin *CurrentSkin = NULL;
753  int OldPrimaryDVB = 0;
754 
755  // Load plugins:
756 
757  if (!PluginManager.LoadPlugins(true))
758  EXIT(2);
759 
760  // Directories:
761 
762  if (!ConfigDirectory)
763  ConfigDirectory = DEFAULTCONFDIR;
764  cPlugin::SetConfigDirectory(ConfigDirectory);
765  if (!CacheDirectory)
766  CacheDirectory = DEFAULTCACHEDIR;
767  cPlugin::SetCacheDirectory(CacheDirectory);
768  if (!ResourceDirectory)
769  ResourceDirectory = DEFAULTRESDIR;
770  cPlugin::SetResourceDirectory(ResourceDirectory);
771  cThemes::SetThemesDirectory("/var/lib/vdr/data/themes");
772 
773  // Configuration data:
774 
775  Setup.Load(AddDirectory(ConfigDirectory, "setup.conf"));
776  Sources.Load(AddDirectory(ConfigDirectory, "sources.conf"), true, true);
777  Diseqcs.Load(AddDirectory(ConfigDirectory, "diseqc.conf"), true, Setup.DiSEqC);
778  Scrs.Load(AddDirectory(ConfigDirectory, "scr.conf"), true);
779  cChannels::Load(AddDirectory(ConfigDirectory, "channels.conf"), false, true);
780  cTimers::Load(AddDirectory(ConfigDirectory, "timers.conf"));
781  Commands.Load(AddDirectory(ConfigDirectory, "commands.conf"));
782  RecordingCommands.Load(AddDirectory(ConfigDirectory, "reccmds.conf"));
783  SVDRPhosts.Load(AddDirectory(ConfigDirectory, "svdrphosts.conf"), true);
784  Keys.Load(AddDirectory(ConfigDirectory, "remote.conf"));
785  KeyMacros.Load(AddDirectory(ConfigDirectory, "keymacros.conf"), true);
786  Folders.Load(AddDirectory(ConfigDirectory, "folders.conf"));
787  CamResponsesLoad(AddDirectory(ConfigDirectory, "camresponses.conf"), true);
788 
790  const char *msg = "no fonts available - OSD will not show any text!";
791  fprintf(stderr, "vdr: %s\n", msg);
792  esyslog("ERROR: %s", msg);
793  }
794 
795  // Recordings:
796 
798 
799  // EPG data:
800 
801  if (EpgDataFileName) {
802  const char *EpgDirectory = NULL;
803  if (DirectoryOk(EpgDataFileName)) {
804  EpgDirectory = EpgDataFileName;
805  EpgDataFileName = DEFAULTEPGDATAFILENAME;
806  }
807  else if (*EpgDataFileName != '/' && *EpgDataFileName != '.')
808  EpgDirectory = CacheDirectory;
809  if (EpgDirectory)
810  cSchedules::SetEpgDataFileName(AddDirectory(EpgDirectory, EpgDataFileName));
811  else
812  cSchedules::SetEpgDataFileName(EpgDataFileName);
813  EpgDataReader.Start();
814  }
815 
816  // DVB interfaces:
817 
820 
821  // Initialize plugins:
822 
823  if (!PluginManager.InitializePlugins())
824  EXIT(2);
825 
826  // Primary device:
827 
829  if (!cDevice::PrimaryDevice() || !cDevice::PrimaryDevice()->HasDecoder()) {
830  if (cDevice::PrimaryDevice() && !cDevice::PrimaryDevice()->HasDecoder())
831  isyslog("device %d has no MPEG decoder", cDevice::PrimaryDevice()->DeviceNumber() + 1);
832  for (int i = 0; i < cDevice::NumDevices(); i++) {
833  cDevice *d = cDevice::GetDevice(i);
834  if (d && d->HasDecoder()) {
835  isyslog("trying device number %d instead", i + 1);
836  if (cDevice::SetPrimaryDevice(i + 1)) {
837  Setup.PrimaryDVB = i + 1;
838  break;
839  }
840  }
841  }
842  if (!cDevice::PrimaryDevice()) {
843  const char *msg = "no primary device found - using first device!";
844  fprintf(stderr, "vdr: %s\n", msg);
845  esyslog("ERROR: %s", msg);
847  EXIT(2);
848  if (!cDevice::PrimaryDevice()) {
849  const char *msg = "no primary device found - giving up!";
850  fprintf(stderr, "vdr: %s\n", msg);
851  esyslog("ERROR: %s", msg);
852  EXIT(2);
853  }
854  }
855  }
856  OldPrimaryDVB = Setup.PrimaryDVB;
857 
858  // Check for timers in automatic start time window:
859 
861 
862  // User interface:
863 
864  Interface = new cInterface;
865 
866  // Default skins:
867 
868  new cSkinLCARS;
869  new cSkinSTTNG;
870  new cSkinClassic;
872  cThemes::Load(Skins.Current()->Name(), Setup.OSDTheme, Skins.Current()->Theme());
873  CurrentSkin = Skins.Current();
874 
875  // Start plugins:
876 
877  if (!PluginManager.StartPlugins())
878  EXIT(2);
879 
880  // Set skin and theme in case they're implemented by a plugin:
881 
882  if (!CurrentSkin || CurrentSkin == Skins.Current() && strcmp(Skins.Current()->Name(), Setup.OSDSkin) != 0) {
884  cThemes::Load(Skins.Current()->Name(), Setup.OSDTheme, Skins.Current()->Theme());
885  }
886 
887  // Remote Controls:
888  if (LircDevice)
889  new cLircRemote(LircDevice);
890  if (!DaemonMode && HasStdin && UseKbd)
891  new cKbdRemote;
892  Interface->LearnKeys();
893 
894  // External audio:
895 
896  if (AudioCommand)
897  new cExternalAudio(AudioCommand);
898 
899  // Positioner:
900 
901  if (!cPositioner::GetPositioner()) // no plugin has created a positioner
902  new cDiseqcPositioner;
903 
904  // CAM data:
905 
906  ChannelCamRelations.Load(AddDirectory(CacheDirectory, "cam.data"));
907 
908  // Channel:
909 
911  dsyslog("not all devices ready after %d seconds", DEVICEREADYTIMEOUT);
913  dsyslog("not all CAM slots ready after %d seconds", DEVICEREADYTIMEOUT);
914  if (*Setup.InitialChannel) {
916  if (isnumber(Setup.InitialChannel)) { // for compatibility with old setup.conf files
917  if (const cChannel *Channel = Channels->GetByNumber(atoi(Setup.InitialChannel)))
918  Setup.InitialChannel = Channel->GetChannelID().ToString();
919  }
920  if (const cChannel *Channel = Channels->GetByChannelID(tChannelID::FromString(Setup.InitialChannel)))
921  Setup.CurrentChannel = Channel->Number();
922  }
923  if (Setup.InitialVolume >= 0)
925  {
927  Channels->SwitchTo(Setup.CurrentChannel);
928  }
929  if (MuteAudio)
930  cDevice::PrimaryDevice()->ToggleMute();
931  else
932  cDevice::PrimaryDevice()->SetVolume(Setup.CurrentVolume, true);
933 
934  // Signal handlers:
935 
936  if (signal(SIGHUP, SignalHandler) == SIG_IGN) signal(SIGHUP, SIG_IGN);
937  if (signal(SIGINT, SignalHandler) == SIG_IGN) signal(SIGINT, SIG_IGN);
938  if (signal(SIGTERM, SignalHandler) == SIG_IGN) signal(SIGTERM, SIG_IGN);
939  if (signal(SIGPIPE, SignalHandler) == SIG_IGN) signal(SIGPIPE, SIG_IGN);
940  if (WatchdogTimeout > 0)
941  if (signal(SIGALRM, Watchdog) == SIG_IGN) signal(SIGALRM, SIG_IGN);
942 
943  // Watchdog:
944 
945  if (WatchdogTimeout > 0) {
946  dsyslog("setting watchdog timer to %d seconds", WatchdogTimeout);
947  alarm(WatchdogTimeout); // Initial watchdog timer start
948  }
949 
950 #ifdef SDNOTIFY
951  if (sd_watchdog_enabled(0, NULL) > 0) {
952  uint64_t timeout;
953  SdWatchdog = time(NULL);
954  sd_watchdog_enabled(0, &timeout);
955  SdWatchdogTimeout = (int)timeout/1000000;
956  dsyslog("SD_WATCHDOG enabled with timeout set to %d seconds", SdWatchdogTimeout);
957  }
958 
959  // Startup notification:
960 
961  sd_notify(0, "READY=1\nSTATUS=Ready");
962 #endif
963 
964  // SVDRP:
965 
966  SetSVDRPPorts(SVDRPport, DEFAULTSVDRPPORT);
968 
969  // Main program loop:
970 
971 #define DELETE_MENU ((IsInfoMenu &= (Menu == NULL)), delete Menu, Menu = NULL)
972 
973  while (!ShutdownHandler.DoExit()) {
974 #ifdef DEBUGRINGBUFFERS
975  cRingBufferLinear::PrintDebugRBL();
976 #endif
977  // Attach launched player control:
979 
980  time_t Now = time(NULL);
981 
982  // Make sure we have a visible programme in case device usage has changed:
983  if (!EITScanner.Active() && cDevice::PrimaryDevice()->HasDecoder()) {
984  static time_t lastTime = 0;
985  if (!cDevice::PrimaryDevice()->HasProgramme()) {
986  if (!CamMenuActive() && Now - lastTime > MINCHANNELWAIT) { // !CamMenuActive() to avoid interfering with the CAM if a CAM menu is open
988  const cChannel *Channel = Channels->GetByNumber(cDevice::CurrentChannel());
989  if (Channel && (Channel->Vpid() || Channel->Apid(0) || Channel->Dpid(0))) {
990  if (cDevice::GetDeviceForTransponder(Channel, LIVEPRIORITY) && Channels->SwitchTo(Channel->Number())) // try to switch to the original channel...
991  ;
992  else if (LastTimerChannel > 0) {
993  Channel = Channels->GetByNumber(LastTimerChannel);
994  if (Channel && cDevice::GetDeviceForTransponder(Channel, LIVEPRIORITY) && Channels->SwitchTo(LastTimerChannel)) // ...or the one used by the last timer
995  ;
996  }
997  }
998  lastTime = Now; // don't do this too often
999  LastTimerChannel = -1;
1000  }
1001  }
1002  else
1003  lastTime = 0; // makes sure we immediately try again next time
1004  }
1005  // Update the OSD size:
1006  {
1007  static time_t lastOsdSizeUpdate = 0;
1008  if (Now != lastOsdSizeUpdate) { // once per second
1010  static int OsdState = 0;
1011  if (cOsdProvider::OsdSizeChanged(OsdState)) {
1012  if (cOsdMenu *OsdMenu = dynamic_cast<cOsdMenu *>(Menu))
1013  OsdMenu->Display();
1014  }
1015  lastOsdSizeUpdate = Now;
1016  }
1017  }
1018  // Restart the Watchdog timer:
1019  if (WatchdogTimeout > 0) {
1020  int LatencyTime = WatchdogTimeout - alarm(WatchdogTimeout);
1021  if (LatencyTime > MaxLatencyTime) {
1022  MaxLatencyTime = LatencyTime;
1023  dsyslog("max. latency time %d seconds", MaxLatencyTime);
1024  }
1025  }
1026 #ifdef SDNOTIFY
1027  // Ping systemd watchdog when half the timeout is elapsed:
1028  if (SdWatchdogTimeout && (Now - SdWatchdog) * 2 > SdWatchdogTimeout) {
1029  sd_notify(0, "WATCHDOG=1");
1030  SdWatchdog = Now;
1031  dsyslog("SD_WATCHDOG ping");
1032  }
1033 #endif
1034  // Handle channel and timer modifications:
1035  static bool ChannelsRenumber = false;
1036  {
1037  // Channels and timers need to be stored in a consistent manner,
1038  // therefore if one of them is changed, we save both.
1039  static time_t ChannelSaveTimeout = 0;
1040  static cStateKey TimersStateKey(true);
1041  static cStateKey ChannelsStateKey(true);
1042  static int ChannelsModifiedByUser = 0;
1043  const cTimers *Timers = cTimers::GetTimersRead(TimersStateKey);
1044  const cChannels *Channels = cChannels::GetChannelsRead(ChannelsStateKey);
1045  if (ChannelSaveTimeout != 1) {
1046  if (Channels) {
1047  if (Channels->ModifiedByUser(ChannelsModifiedByUser))
1048  ChannelSaveTimeout = 1; // triggers an immediate save
1049  else if (!ChannelSaveTimeout)
1050  ChannelSaveTimeout = Now + CHANNELSAVEDELTA;
1051  }
1052  if (Timers)
1053  ChannelSaveTimeout = 1; // triggers an immediate save
1054  }
1055  if (ChannelSaveTimeout && Now > ChannelSaveTimeout && !cRecordControls::Active())
1056  ChannelSaveTimeout = 1; // triggers an immediate save
1057  if (Timers && Channels) {
1058  Channels->Save();
1059  Timers->Save();
1060  ChannelSaveTimeout = 0;
1061  }
1062  if (Channels) {
1063  for (const cChannel *Channel = Channels->First(); Channel; Channel = Channels->Next(Channel)) {
1064  int ChannelModification = Channel->Modification(CHANNELMOD_ALL);
1065  if (ChannelModification & CHANNELMOD_TRANSP)
1066  ChannelsRenumber = true;
1067  if (ChannelModification & CHANNELMOD_RETUNE) {
1069  if (Channel->Number() == cDevice::CurrentChannel() && cDevice::PrimaryDevice()->HasDecoder()) {
1070  if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring()) {
1071  if (cDevice::ActualDevice()->ProvidesTransponder(Channel)) { // avoids retune on devices that don't really access the transponder
1072  isyslog("retuning due to modification of channel %d (%s)", Channel->Number(), Channel->Name());
1073  Channels->SwitchTo(Channel->Number());
1074  }
1075  }
1076  }
1077  cStatus::MsgChannelChange(Channel);
1078  }
1079  }
1080  }
1081  // State keys are removed in reverse order!
1082  if (Channels)
1083  ChannelsStateKey.Remove();
1084  if (Timers)
1085  TimersStateKey.Remove();
1086  if (ChannelSaveTimeout == 1) {
1087  // Only one of them was modified, so we reset the state keys to handle them both in the next turn:
1088  ChannelsStateKey.Reset();
1089  TimersStateKey.Reset();
1090  }
1091  }
1092  // Channel display:
1093  if (!EITScanner.Active() && cDevice::CurrentChannel() != LastChannel) {
1094  if (!Menu)
1095  Menu = new cDisplayChannel(cDevice::CurrentChannel(), LastChannel >= 0);
1096  LastChannel = cDevice::CurrentChannel();
1097  LastChannelChanged = Now;
1098  }
1099  if (Now - LastChannelChanged >= Setup.ZapTimeout && LastChannel != PreviousChannel[PreviousChannelIndex])
1100  PreviousChannel[PreviousChannelIndex ^= 1] = LastChannel;
1101  {
1102  // Timers and Recordings:
1103  static cStateKey TimersStateKey;
1104  cTimers *Timers = cTimers::GetTimersWrite(TimersStateKey);
1105  {
1106  // Assign events to timers:
1107  static cStateKey SchedulesStateKey;
1108  if (TimersStateKey.StateChanged())
1109  SchedulesStateKey.Reset(); // we assign events if either the Timers or the Schedules have changed
1110  bool TimersModified = false;
1111  if (const cSchedules *Schedules = cSchedules::GetSchedulesRead(SchedulesStateKey)) {
1112  Timers->SetSyncStateKey(StateKeySVDRPRemoteTimersPoll);
1113  if (Timers->SetEvents(Schedules))
1114  TimersModified = true;
1115  SchedulesStateKey.Remove();
1116  }
1117  TimersStateKey.Remove(TimersModified); // we need to remove the key here, so that syncing StateKeySVDRPRemoteTimersPoll takes effect!
1118  }
1119  // Must do all following calls with the exact same time!
1120  // Process ongoing recordings:
1121  Timers = cTimers::GetTimersWrite(TimersStateKey);
1122  bool TimersModified = false;
1123  if (cRecordControls::Process(Timers, Now))
1124  TimersModified = true;
1125  // Start new recordings:
1126  if (cTimer *Timer = Timers->GetMatch(Now)) {
1127  if (!cRecordControls::Start(Timers, Timer))
1128  Timer->SetPending(true);
1129  else
1130  LastTimerChannel = Timer->Channel()->Number();
1131  TimersModified = true;
1132  }
1133  // Make sure timers "see" their channel early enough:
1134  static time_t LastTimerCheck = 0;
1135  if (Now - LastTimerCheck > TIMERCHECKDELTA) { // don't do this too often
1136  InhibitEpgScan = false;
1137  for (cTimer *Timer = Timers->First(); Timer; Timer = Timers->Next(Timer)) {
1138  if (Timer->Remote())
1139  continue;
1140  bool InVpsMargin = false;
1141  bool NeedsTransponder = false;
1142  if (Timer->HasFlags(tfActive) && !Timer->Recording()) {
1143  if (Timer->HasFlags(tfVps)) {
1144  if (Timer->Matches(Now, true, Setup.VpsMargin)) {
1145  InVpsMargin = true;
1146  Timer->SetInVpsMargin(InVpsMargin);
1147  }
1148  else if (Timer->Event()) {
1149  InVpsMargin = Timer->Event()->StartTime() <= Now && Now < Timer->Event()->EndTime();
1150  NeedsTransponder = Timer->Event()->StartTime() - Now < VPSLOOKAHEADTIME * 3600 && !Timer->Event()->SeenWithin(VPSUPTODATETIME);
1151  }
1152  else {
1154  const cSchedule *Schedule = Schedules->GetSchedule(Timer->Channel());
1155  InVpsMargin = !Schedule; // we must make sure we have the schedule
1156  NeedsTransponder = Schedule && !Schedule->PresentSeenWithin(VPSUPTODATETIME);
1157  }
1158  InhibitEpgScan |= InVpsMargin | NeedsTransponder;
1159  }
1160  else
1161  NeedsTransponder = Timer->Matches(Now, true, TIMERLOOKAHEADTIME);
1162  }
1163  if (NeedsTransponder || InVpsMargin) {
1164  // Find a device that provides the required transponder:
1165  cDevice *Device = cDevice::GetDeviceForTransponder(Timer->Channel(), MINPRIORITY);
1166  if (!Device && InVpsMargin)
1167  Device = cDevice::GetDeviceForTransponder(Timer->Channel(), LIVEPRIORITY);
1168  // Switch the device to the transponder:
1169  if (Device) {
1170  bool HadProgramme = cDevice::PrimaryDevice()->HasProgramme();
1171  if (!Device->IsTunedToTransponder(Timer->Channel())) {
1172  if (Device == cDevice::ActualDevice() && !Device->IsPrimaryDevice())
1173  cDevice::PrimaryDevice()->StopReplay(); // stop transfer mode
1174  dsyslog("switching device %d to channel %d %s (%s)", Device->DeviceNumber() + 1, Timer->Channel()->Number(), *Timer->Channel()->GetChannelID().ToString(), Timer->Channel()->Name());
1175  if (Device->SwitchChannel(Timer->Channel(), false))
1177  }
1178  if (cDevice::PrimaryDevice()->HasDecoder() && HadProgramme && !cDevice::PrimaryDevice()->HasProgramme())
1179  Skins.QueueMessage(mtInfo, tr("Upcoming recording!")); // the previous SwitchChannel() has switched away the current live channel
1180  }
1181  }
1182  }
1183  LastTimerCheck = Now;
1184  }
1185  // Delete expired timers:
1186  if (Timers->DeleteExpired())
1187  TimersModified = true;
1188  // Make sure there is enough free disk space for ongoing recordings:
1189  int MaxPriority = Timers->GetMaxPriority();
1190  if (MaxPriority >= 0)
1191  AssertFreeDiskSpace(MaxPriority);
1192  TimersStateKey.Remove(TimersModified);
1193  }
1194  // Renumber channels on LCN update
1195  if (ChannelsRenumber) {
1197  Channels->ReNumber();
1198  ChannelsRenumber = false;
1199  }
1200  // Recordings:
1201  if (!Menu) {
1204  }
1205  // CAM control:
1206  if (!Menu && !cOsd::IsOpen())
1207  Menu = CamControl();
1208  // Queued messages:
1210  // User Input:
1211  cOsdObject *Interact = Menu ? Menu : cControl::Control();
1212  eKeys key = Interface->GetKey(!Interact || !Interact->NeedsFastResponse());
1213  if (ISREALKEY(key)) {
1214  EITScanner.Activity();
1215  // Cancel shutdown countdown:
1218  // Set user active for MinUserInactivity time in the future:
1220  }
1221  // Keys that must work independent of any interactive mode:
1222  switch (int(key)) {
1223  // Menu control:
1224  case kMenu: {
1225  key = kNone; // nobody else needs to see this key
1226  bool WasOpen = Interact != NULL;
1227  bool WasMenu = Interact && Interact->IsMenu();
1228  if (Menu)
1229  DELETE_MENU;
1230  else if (cControl::Control()) {
1231  if (cOsd::IsOpen())
1232  cControl::Control()->Hide();
1233  else
1234  WasOpen = false;
1235  }
1236  if (!WasOpen || !WasMenu && !Setup.MenuKeyCloses)
1237  Menu = new cMenuMain;
1238  }
1239  break;
1240  // Info:
1241  case kInfo: {
1242  if (IsInfoMenu) {
1243  key = kNone; // nobody else needs to see this key
1244  DELETE_MENU;
1245  }
1246  else if (!Menu) {
1247  IsInfoMenu = true;
1248  if (cControl::Control()) {
1249  cControl::Control()->Hide();
1250  Menu = cControl::Control()->GetInfo();
1251  if (Menu)
1252  Menu->Show();
1253  else
1254  IsInfoMenu = false;
1255  }
1256  else {
1257  cRemote::Put(kOk, true);
1258  cRemote::Put(kSchedule, true);
1259  }
1260  key = kNone; // nobody else needs to see this key
1261  }
1262  }
1263  break;
1264  // Direct main menu functions:
1265  #define DirectMainFunction(function)\
1266  { DELETE_MENU;\
1267  if (cControl::Control())\
1268  cControl::Control()->Hide();\
1269  Menu = new cMenuMain(function);\
1270  key = kNone; } // nobody else needs to see this key
1271  case kSchedule: DirectMainFunction(osSchedule); break;
1272  case kChannels: DirectMainFunction(osChannels); break;
1273  case kTimers: DirectMainFunction(osTimers); break;
1275  case kSetup: DirectMainFunction(osSetup); break;
1276  case kCommands: DirectMainFunction(osCommands); break;
1277  case kUser0 ... kUser9: cRemote::PutMacro(key); key = kNone; break;
1278  case k_Plugin: {
1279  const char *PluginName = cRemote::GetPlugin();
1280  if (PluginName) {
1281  DELETE_MENU;
1282  if (cControl::Control())
1283  cControl::Control()->Hide();
1284  cPlugin *plugin = cPluginManager::GetPlugin(PluginName);
1285  if (plugin) {
1286  Menu = plugin->MainMenuAction();
1287  if (Menu)
1288  Menu->Show();
1289  }
1290  else
1291  esyslog("ERROR: unknown plugin '%s'", PluginName);
1292  }
1293  key = kNone; // nobody else needs to see these keys
1294  }
1295  break;
1296  // Channel up/down:
1297  case kChanUp|k_Repeat:
1298  case kChanUp:
1299  case kChanDn|k_Repeat:
1300  case kChanDn:
1301  if (!Interact) {
1302  Menu = new cDisplayChannel(NORMALKEY(key));
1303  continue;
1304  }
1305  else if (cDisplayChannel::IsOpen() || cControl::Control()) {
1306  Interact->ProcessKey(key);
1307  continue;
1308  }
1309  else
1310  cDevice::SwitchChannel(NORMALKEY(key) == kChanUp ? 1 : -1);
1311  break;
1312  // Volume control:
1313  case kVolUp|k_Repeat:
1314  case kVolUp:
1315  case kVolDn|k_Repeat:
1316  case kVolDn:
1317  case kMute:
1318  if (key == kMute) {
1319  if (!cDevice::PrimaryDevice()->ToggleMute() && !Menu) {
1320  key = kNone; // nobody else needs to see these keys
1321  break; // no need to display "mute off"
1322  }
1323  }
1324  else
1325  cDevice::PrimaryDevice()->SetVolume(NORMALKEY(key) == kVolDn ? -VOLUMEDELTA : VOLUMEDELTA);
1326  if (!Menu && !cOsd::IsOpen())
1327  Menu = cDisplayVolume::Create();
1329  key = kNone; // nobody else needs to see these keys
1330  break;
1331  // Audio track control:
1332  case kAudio:
1333  if (cControl::Control())
1334  cControl::Control()->Hide();
1335  if (!cDisplayTracks::IsOpen()) {
1336  DELETE_MENU;
1337  Menu = cDisplayTracks::Create();
1338  }
1339  else
1341  key = kNone;
1342  break;
1343  // Subtitle track control:
1344  case kSubtitles:
1345  if (cControl::Control())
1346  cControl::Control()->Hide();
1348  DELETE_MENU;
1350  }
1351  else
1353  key = kNone;
1354  break;
1355  // Pausing live video:
1356  case kPlayPause:
1357  case kPause:
1358  if (!cControl::Control()) {
1359  DELETE_MENU;
1360  if (Setup.PauseKeyHandling) {
1361  if (Setup.PauseKeyHandling > 1 || Interface->Confirm(tr("Pause live video?"))) {
1363  Skins.QueueMessage(mtError, tr("No free DVB device to record!"));
1364  }
1365  }
1366  key = kNone; // nobody else needs to see this key
1367  }
1368  break;
1369  // Instant recording:
1370  case kRecord:
1371  if (!cControl::Control()) {
1372  if (Setup.RecordKeyHandling) {
1373  if (Setup.RecordKeyHandling > 1 || Interface->Confirm(tr("Start recording?"))) {
1374  if (cRecordControls::Start())
1375  Skins.QueueMessage(mtInfo, tr("Recording started"));
1376  }
1377  }
1378  key = kNone; // nobody else needs to see this key
1379  }
1380  break;
1381  // Power off:
1382  case kPower:
1383  isyslog("Power button pressed");
1384  DELETE_MENU;
1385  // Check for activity, request power button again if active:
1386  if (!ShutdownHandler.ConfirmShutdown(false) && Skins.Message(mtWarning, tr("VDR will shut down later - press Power to force"), SHUTDOWNFORCEPROMPT) != kPower) {
1387  // Not pressed power - set VDR to be non-interactive and power down later:
1388  ShutdownHandler.SetUserInactive();
1389  break;
1390  }
1391  // No activity or power button pressed twice - ask for confirmation:
1392  if (!ShutdownHandler.ConfirmShutdown(true)) {
1393  // Non-confirmed background activity - set VDR to be non-interactive and power down later:
1394  ShutdownHandler.SetUserInactive();
1395  break;
1396  }
1397  // Ask the final question:
1398  if (!Interface->Confirm(tr("Press any key to cancel shutdown"), SHUTDOWNCANCELPROMPT, true))
1399  // If final question was canceled, continue to be active:
1400  break;
1401  // Ok, now call the shutdown script:
1403  // Set VDR to be non-interactive and power down again later:
1404  ShutdownHandler.SetUserInactive();
1405  // Do not attempt to automatically shut down for a while:
1406  ShutdownHandler.SetRetry(SHUTDOWNRETRY);
1407  break;
1408  default: break;
1409  }
1410  Interact = Menu ? Menu : cControl::Control(); // might have been closed in the mean time
1411  if (Interact) {
1412  LastInteract = Now;
1413  eOSState state = Interact->ProcessKey(key);
1414  if (state == osUnknown && Interact != cControl::Control()) {
1415  if (ISMODELESSKEY(key) && cControl::Control()) {
1416  state = cControl::Control()->ProcessKey(key);
1417  if (state == osEnd) {
1418  // let's not close a menu when replay ends:
1420  continue;
1421  }
1422  }
1423  else if (Now - cRemote::LastActivity() > MENUTIMEOUT)
1424  state = osEnd;
1425  }
1426  switch (state) {
1427  case osPause: DELETE_MENU;
1429  Skins.QueueMessage(mtError, tr("No free DVB device to record!"));
1430  break;
1431  case osRecord: DELETE_MENU;
1432  if (cRecordControls::Start())
1433  Skins.QueueMessage(mtInfo, tr("Recording started"));
1434  break;
1435  case osRecordings:
1436  DELETE_MENU;
1438  Menu = new cMenuMain(osRecordings, true);
1439  break;
1440  case osReplay: DELETE_MENU;
1443  break;
1444  case osStopReplay:
1445  DELETE_MENU;
1447  break;
1448  case osPlugin: DELETE_MENU;
1449  Menu = cMenuMain::PluginOsdObject();
1450  if (Menu)
1451  Menu->Show();
1452  break;
1453  case osBack:
1454  case osEnd: if (Interact == Menu)
1455  DELETE_MENU;
1456  else
1458  break;
1459  default: ;
1460  }
1461  }
1462  else {
1463  // Key functions in "normal" viewing mode:
1464  if (key != kNone && KeyMacros.Get(key)) {
1465  cRemote::PutMacro(key);
1466  key = kNone;
1467  }
1468  switch (int(key)) {
1469  // Toggle channels:
1470  case kChanPrev:
1471  case k0: {
1472  if (PreviousChannel[PreviousChannelIndex ^ 1] == LastChannel || LastChannel != PreviousChannel[0] && LastChannel != PreviousChannel[1])
1473  PreviousChannelIndex ^= 1;
1475  Channels->SwitchTo(PreviousChannel[PreviousChannelIndex ^= 1]);
1476  break;
1477  }
1478  // Direct Channel Select:
1479  case k1 ... k9:
1480  // Left/Right rotates through channel groups:
1481  case kLeft|k_Repeat:
1482  case kLeft:
1483  case kRight|k_Repeat:
1484  case kRight:
1485  // Previous/Next rotates through channel groups:
1486  case kPrev|k_Repeat:
1487  case kPrev:
1488  case kNext|k_Repeat:
1489  case kNext:
1490  // Up/Down Channel Select:
1491  case kUp|k_Repeat:
1492  case kUp:
1493  case kDown|k_Repeat:
1494  case kDown:
1495  Menu = new cDisplayChannel(NORMALKEY(key));
1496  break;
1497  // Viewing Control:
1498  case kOk: LastChannel = -1; break; // forces channel display
1499  // Instant resume of the last viewed recording:
1500  case kPlay:
1504  }
1505  else
1506  DirectMainFunction(osRecordings); // no last viewed recording, so enter the Recordings menu
1507  break;
1508  default: break;
1509  }
1510  }
1511  if (!Menu) {
1512  if (!InhibitEpgScan)
1513  EITScanner.Process();
1514  bool Error = false;
1515  if (RecordingsHandler.Finished(Error)) {
1516  if (Error)
1517  Skins.Message(mtError, tr("Editing process failed!"));
1518  else
1519  Skins.Message(mtInfo, tr("Editing process finished"));
1520  }
1521  }
1522 
1523  // Change primary device:
1524  int NewPrimaryDVB = Setup.PrimaryDVB;
1525  if (NewPrimaryDVB != OldPrimaryDVB) {
1526  DELETE_MENU;
1528  Skins.QueueMessage(mtInfo, tr("Switching primary DVB..."));
1530  cDevice::SetPrimaryDevice(NewPrimaryDVB);
1531  OldPrimaryDVB = NewPrimaryDVB;
1532  }
1533 
1534  // SIGHUP shall cause a restart:
1535  if (LastSignal == SIGHUP) {
1536  if (ShutdownHandler.ConfirmRestart(true) && Interface->Confirm(tr("Press any key to cancel restart"), RESTARTCANCELPROMPT, true))
1537  EXIT(1);
1538  LastSignal = 0;
1539  }
1540 
1541  // Update the shutdown countdown:
1543  if (!ShutdownHandler.ConfirmShutdown(false))
1545  }
1546 
1547  if (!cControl::Control() && !cRecordControls::Active() && !RecordingsHandler.Active() && (Now - cRemote::LastActivity()) > ACTIVITYTIMEOUT) {
1548  // Shutdown:
1549  // Check whether VDR will be ready for shutdown in SHUTDOWNWAIT seconds:
1550  time_t Soon = Now + SHUTDOWNWAIT;
1551  if (ShutdownHandler.IsUserInactive(Soon) && ShutdownHandler.Retry(Soon) && !ShutdownHandler.countdown) {
1552  if (ShutdownHandler.ConfirmShutdown(false))
1553  // Time to shut down - start final countdown:
1554  ShutdownHandler.countdown.Start(tr("VDR will shut down in %s minutes"), SHUTDOWNWAIT); // the placeholder is really %s!
1555  // Dont try to shut down again for a while:
1556  ShutdownHandler.SetRetry(SHUTDOWNRETRY);
1557  }
1558  // Countdown run down to 0?
1559  if (ShutdownHandler.countdown.Done()) {
1560  // Timed out, now do a final check:
1561  if (ShutdownHandler.IsUserInactive() && ShutdownHandler.ConfirmShutdown(false))
1562  ShutdownHandler.DoShutdown(false);
1563  // Do this again a bit later:
1564  ShutdownHandler.SetRetry(SHUTDOWNRETRY);
1565  }
1566  // Handle housekeeping tasks
1567  if ((Now - LastInteract) > ACTIVITYTIMEOUT) {
1568  // Disk housekeeping:
1572  // Plugins housekeeping:
1573  PluginManager.Housekeeping();
1574  }
1575  }
1576 
1578 
1579  // Main thread hooks of plugins:
1580  PluginManager.MainThreadHook();
1581  }
1582 
1583  if (ShutdownHandler.EmergencyExitRequested())
1584  esyslog("emergency exit requested - shutting down");
1585 
1586 Exit:
1587 
1588  // Reset all signal handlers to default before Interface gets deleted:
1589  signal(SIGHUP, SIG_DFL);
1590  signal(SIGINT, SIG_DFL);
1591  signal(SIGTERM, SIG_DFL);
1592  signal(SIGPIPE, SIG_DFL);
1593  signal(SIGALRM, SIG_DFL);
1594 
1595  StopSVDRPHandler();
1598  PluginManager.StopPlugins();
1600  delete Menu;
1602  delete Interface;
1604  Remotes.Clear();
1605  Audios.Clear();
1606  Skins.Clear();
1607  SourceParams.Clear();
1608  if (ShutdownHandler.GetExitCode() != 2) {
1609  Setup.CurrentChannel = cDevice::CurrentChannel();
1611  Setup.Save();
1612  }
1616  EpgHandlers.Clear();
1617  cSchedules::Cleanup(true);
1620  PluginManager.Shutdown(true);
1621  ReportEpgBugFixStats(true);
1622  if (WatchdogTimeout > 0)
1623  dsyslog("max. latency time %d seconds", MaxLatencyTime);
1624  if (LastSignal)
1625  isyslog("caught signal %d", LastSignal);
1626  if (ShutdownHandler.EmergencyExitRequested())
1627  esyslog("emergency exit!");
1628  isyslog("exiting, exit code %d", ShutdownHandler.GetExitCode());
1629  if (SysLogLevel > 0)
1630  closelog();
1631  if (HasStdin)
1632  tcsetattr(STDIN_FILENO, TCSANOW, &savedTm);
1633 #ifdef SDNOTIFY
1634  if (ShutdownHandler.GetExitCode() == 2)
1635  sd_notify(0, "STOPPING=1\nSTATUS=Startup failed, exiting");
1636  else
1637  sd_notify(0, "STOPPING=1\nSTATUS=Exiting");
1638 #endif
1639  return ShutdownHandler.GetExitCode();
1640 }
cChannels::SwitchTo
bool SwitchTo(int Number) const
Definition: channels.c:1070
kPower
@ kPower
Definition: keys.h:39
DropCaps
static bool DropCaps(void)
Definition: vdr.c:126
SI::OverrideCharacterTable
static char * OverrideCharacterTable
Definition: si.c:332
cDisplaySubtitleTracks::Process
static void Process(eKeys Key)
Definition: menu.c:5259
MINPRIORITY
#define MINPRIORITY
Definition: config.h:40
NORMALKEY
#define NORMALKEY(k)
Definition: keys.h:79
cChannels::ModifiedByUser
bool ModifiedByUser(int &State) const
Returns true if the channels have been modified by the user since the last call to this function with...
Definition: channels.c:1106
SetUser
static bool SetUser(const char *User, bool UserDump)
Definition: vdr.c:96
EXIT
#define EXIT(v)
Definition: vdr.c:92
osRecordings
@ osRecordings
Definition: osdbase.h:23
cPositioner::DestroyPositioner
static void DestroyPositioner(void)
Destroys a previously created positioner.
Definition: positioner.c:138
cScrs::Load
bool Load(const char *FileName, bool AllowComments=false, bool MustExist=false)
Definition: diseqc.c:184
skinclassic.h
Remotes
cRemotes Remotes
Definition: remote.c:211
cConfig::Save
bool Save(void) const
Definition: config.h:167
AddDirectory
cString AddDirectory(const char *DirName, const char *FileName)
Definition: tools.c:384
SysLogLevel
int SysLogLevel
Definition: tools.c:31
k_Repeat
@ k_Repeat
Definition: keys.h:61
recording.h
Interface
cInterface * Interface
Definition: interface.c:20
cDevice::WaitForAllDevicesReady
static bool WaitForAllDevicesReady(int Timeout=0)
Waits until all devices have become ready, or the given Timeout (seconds) has expired.
Definition: device.c:126
CHANNELMOD_ALL
#define CHANNELMOD_ALL
Definition: channels.h:21
sources.h
EpgHandlers
cEpgHandlers EpgHandlers
Definition: epg.c:1384
cVideoDirectory::SetName
static void SetName(const char *Name)
Definition: videodir.c:65
AssertFreeDiskSpace
void AssertFreeDiskSpace(int Priority, bool Force)
The special Priority value -1 means that we shall get rid of any deleted recordings faster than norma...
Definition: recording.c:154
cSetup::SplitEditedFiles
int SplitEditedFiles
Definition: config.h:338
cKeyMacros::Get
const cKeyMacro * Get(eKeys Key)
Definition: keys.c:269
VPSLOOKAHEADTIME
#define VPSLOOKAHEADTIME
Definition: vdr.c:89
DEFAULTSVDRPPORT
#define DEFAULTSVDRPPORT
StopSVDRPHandler
void StopSVDRPHandler(void)
Definition: svdrp.c:2829
cRecordingsHandler::DelAll
void DelAll(void)
Deletes/terminates all operations.
Definition: recording.c:2057
transfer.h
cRemote::PutMacro
static bool PutMacro(eKeys Key)
Definition: remote.c:110
cDvbDevice::useDvbDevices
static bool useDvbDevices
Definition: dvbdevice.h:178
cSkin
Definition: skins.h:402
cTimers::GetMatch
const cTimer * GetMatch(time_t t) const
Definition: timers.c:779
cPluginManager::HasPlugins
static bool HasPlugins(void)
Definition: plugin.c:452
cSetup::InitialChannel
cString InitialChannel
Definition: config.h:368
cChannelCamRelations::Load
void Load(const char *FileName)
Definition: ci.c:3013
DEFAULTCACHEDIR
#define DEFAULTCACHEDIR
cSkins::Message
eKeys Message(eMessageType Type, const char *s, int Seconds=0)
Displays the given message, either through a currently visible display object that is capable of doin...
Definition: skins.c:250
cSkinClassic
Definition: skinclassic.h:15
kNone
@ kNone
Definition: keys.h:55
cPluginManager::GetPlugin
static cPlugin * GetPlugin(int Index)
Definition: plugin.c:457
cTimer
Definition: timers.h:27
RecordingsHandler
cRecordingsHandler RecordingsHandler
Definition: recording.c:1967
cSchedules::GetSchedulesRead
static const cSchedules * GetSchedulesRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of schedules for read access.
Definition: epg.c:1231
LOCK_CHANNELS_READ
#define LOCK_CHANNELS_READ
Definition: channels.h:267
cShutdownHandler::ConfirmRestart
bool ConfirmRestart(bool Ask)
Check for background activity that blocks restart.
Definition: shutdown.c:209
kChanDn
@ kChanDn
Definition: keys.h:41
cCountdown::Start
void Start(const char *Message, int Seconds)
Start the 5 minute shutdown warning countdown.
Definition: shutdown.c:37
KeyMacros
cKeyMacros KeyMacros
Definition: keys.c:267
cPlugin
Definition: plugin.h:20
keys.h
cRecordControls::Process
static bool Process(cTimers *Timers, time_t t)
Definition: menu.c:5576
MINVIDEOFILESIZE
#define MINVIDEOFILESIZE
Definition: recording.h:445
TIMERLOOKAHEADTIME
#define TIMERLOOKAHEADTIME
Definition: vdr.c:88
ReportEpgBugFixStats
void ReportEpgBugFixStats(bool Force)
Definition: epg.c:611
cCamSlots::WaitForAllCamSlotsReady
bool WaitForAllCamSlotsReady(int Timeout=0)
Waits until all CAM slots have become ready, or the given Timeout (seconds) has expired.
Definition: ci.c:2820
kLeft
@ kLeft
Definition: keys.h:22
osStopReplay
@ osStopReplay
Definition: osdbase.h:31
cChannel::Number
int Number(void) const
Definition: channels.h:179
menu.h
cChannel::Dpid
int Dpid(int i) const
Definition: channels.h:161
SHUTDOWNWAIT
#define SHUTDOWNWAIT
Definition: vdr.c:77
cDiseqcPositioner
Definition: diseqc.h:17
diseqc.h
cInterface::Interrupt
void Interrupt(void)
Definition: interface.h:24
cTimers::GetTimersRead
static const cTimers * GetTimersRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of timers for read access.
Definition: timers.c:843
k9
@ k9
Definition: keys.h:28
SVDRPhosts
cSVDRPhosts SVDRPhosts
Definition: config.c:280
osPause
@ osPause
Definition: osdbase.h:27
cReplayControl::LastReplayed
static const char * LastReplayed(void)
Definition: menu.c:5770
EITScanner
cEITScanner EITScanner
Definition: eitscan.c:90
cSchedule::PresentSeenWithin
bool PresentSeenWithin(int Seconds) const
Definition: epg.h:166
MINCHANNELWAIT
#define MINCHANNELWAIT
Definition: vdr.c:75
cDevice::IsTunedToTransponder
virtual bool IsTunedToTransponder(const cChannel *Channel) const
Returns true if this device is currently tuned to the given Channel's transponder.
Definition: device.c:775
LOCK_SCHEDULES_READ
#define LOCK_SCHEDULES_READ
Definition: epg.h:224
kChanUp
@ kChanUp
Definition: keys.h:40
cutter.h
kRecordings
@ kRecordings
Definition: keys.h:51
cSetup::VpsMargin
int VpsMargin
Definition: config.h:308
cRecordControls::Active
static bool Active(void)
Definition: menu.c:5608
cSetup::MaxVideoFileSize
int MaxVideoFileSize
Definition: config.h:337
VOLUMEDELTA
#define VOLUMEDELTA
Definition: device.h:33
cDisplayTracks::IsOpen
static bool IsOpen(void)
Definition: menu.h:172
cThemes::SetThemesDirectory
static void SetThemesDirectory(const char *ThemesDirectory)
Definition: themes.c:295
cSetup::Load
bool Load(const char *FileName)
Definition: config.c:543
kNext
@ kNext
Definition: keys.h:37
cOsdMenu
Definition: osdbase.h:85
cRecordingsHandler::Finished
bool Finished(bool &Error)
Returns true if all operations in the list have been finished.
Definition: recording.c:2072
cPlugin::Version
virtual const char * Version(void)=0
CamResponsesLoad
bool CamResponsesLoad(const char *FileName, bool AllowComments, bool MustExist)
Definition: ci.c:457
cTimers::SetEvents
bool SetEvents(const cSchedules *Schedules)
Definition: timers.c:882
cPluginManager::MainThreadHook
void MainThreadHook(void)
Definition: plugin.c:406
cSetup::InitialVolume
int InitialVolume
Definition: config.h:363
Keys
cKeys Keys
Definition: keys.c:156
SHUTDOWNFORCEPROMPT
#define SHUTDOWNFORCEPROMPT
Definition: vdr.c:79
themes.h
MAXDEVICES
#define MAXDEVICES
Definition: device.h:29
eKeys
eKeys
Definition: keys.h:16
plugin.h
osSchedule
@ osSchedule
Definition: osdbase.h:20
tr
#define tr(s)
Definition: i18n.h:85
DirectoryEncoding
bool DirectoryEncoding
Definition: recording.c:78
cPlugin::Description
virtual const char * Description(void)=0
cPlugin::Name
const char * Name(void)
Definition: plugin.h:34
LIVEPRIORITY
#define LIVEPRIORITY
Definition: config.h:41
kPlayPause
@ kPlayPause
Definition: keys.h:30
SetKeepCaps
static bool SetKeepCaps(bool On)
Definition: vdr.c:161
cRemote::Put
bool Put(uint64_t Code, bool Repeat=false, bool Release=false)
Definition: remote.c:124
cStatus::MsgChannelChange
static void MsgChannelChange(const cChannel *Channel)
Definition: status.c:26
skinlcars.h
cOsdProvider::UpdateOsdSize
static void UpdateOsdSize(bool Force=false)
Inquires the actual size of the video display and adjusts the OSD and font sizes accordingly.
Definition: osd.c:2037
cArgs::GetArgv
char ** GetArgv(void) const
Definition: args.h:31
TIMERCHECKDELTA
#define TIMERCHECKDELTA
Definition: vdr.c:86
cOsdObject
Definition: osdbase.h:69
cShutdownHandler::ConfirmShutdown
bool ConfirmShutdown(bool Ask)
Check for background activity that blocks shutdown.
Definition: shutdown.c:157
CHANNELMOD_TRANSP
#define CHANNELMOD_TRANSP
Definition: channels.h:27
DirectoryPathMax
int DirectoryPathMax
Definition: recording.c:76
cDevice::CurrentVolume
static int CurrentVolume(void)
Definition: device.h:622
Setup
cSetup Setup
Definition: config.c:372
args.h
cNestedItemList::Load
bool Load(const char *FileName)
Definition: config.c:234
DEFAULTWATCHDOG
#define DEFAULTWATCHDOG
device.h
svdrp.h
cSchedules::Cleanup
static void Cleanup(bool Force=false)
Definition: epg.c:1248
cSkins::QueueMessage
int QueueMessage(eMessageType Type, const char *s, int Seconds=0, int Timeout=0)
Like Message(), but this function may be called from a background thread.
Definition: skins.c:296
ShutdownHandler
cShutdownHandler ShutdownHandler
Definition: shutdown.c:27
cDisplayVolume::Create
static cDisplayVolume * Create(void)
Definition: menu.c:5040
cChannelCamRelations::Save
void Save(void)
Definition: ci.c:3047
cPositioner::GetPositioner
static cPositioner * GetPositioner(void)
Returns a previously created positioner.
Definition: positioner.c:133
RESTARTCANCELPROMPT
#define RESTARTCANCELPROMPT
Definition: vdr.c:81
kVolDn
@ kVolDn
Definition: keys.h:44
cSetup::CurrentVolume
int CurrentVolume
Definition: config.h:359
osCommands
@ osCommands
Definition: osdbase.h:26
cOsdObject::ProcessKey
virtual eOSState ProcessKey(eKeys Key)
Definition: osdbase.h:82
SI::SetOverrideCharacterTable
void SetOverrideCharacterTable(const char *CharacterTable)
Definition: si.c:334
cStateKey
Definition: thread.h:233
shutdown.h
MAXVIDEOFILESIZETS
#define MAXVIDEOFILESIZETS
Definition: recording.h:443
cLircRemote
Definition: lirc.h:17
cDevice::GetDevice
static cDevice * GetDevice(int Index)
Gets the device with the given Index.
Definition: device.c:223
kMute
@ kMute
Definition: keys.h:45
CHANNELSAVEDELTA
#define CHANNELSAVEDELTA
Definition: vdr.c:83
Audios
cAudios Audios
Definition: audio.c:27
kUp
@ kUp
Definition: keys.h:17
DEFAULTEPGDATAFILENAME
#define DEFAULTEPGDATAFILENAME
cThread::ThreadId
static tThreadId ThreadId(void)
Definition: thread.c:372
isnumber
bool isnumber(const char *s)
Definition: tools.c:346
cTimers::Load
static bool Load(const char *FileName)
Definition: timers.c:735
cRecordControls::Shutdown
static void Shutdown(void)
Definition: menu.c:5617
cSetup::ZapTimeout
int ZapTimeout
Definition: config.h:298
Folders
cNestedItemList Folders
Definition: config.c:274
InstanceId
int InstanceId
Definition: recording.c:79
channels.h
k1
@ k1
Definition: keys.h:28
cControl::Hide
virtual void Hide(void)=0
cPlugin::SetCacheDirectory
static void SetCacheDirectory(const char *Dir)
Definition: plugin.c:149
kOk
@ kOk
Definition: keys.h:20
kChannels
@ kChannels
Definition: keys.h:49
TIMERDEVICETIMEOUT
#define TIMERDEVICETIMEOUT
Definition: vdr.c:87
cDevice::IsPrimaryDevice
bool IsPrimaryDevice(void) const
Definition: device.h:213
cPluginManager::InitializePlugins
bool InitializePlugins(void)
Definition: plugin.c:363
cShutdownHandler::CheckManualStart
void CheckManualStart(int ManualStart)
Check whether the next timer is in ManualStart time window.
Definition: shutdown.c:104
cThread::SetMainThreadId
static void SetMainThreadId(void)
Definition: thread.c:377
kAudio
@ kAudio
Definition: keys.h:46
cOsdProvider::Shutdown
static void Shutdown(void)
Shuts down the OSD provider facility by deleting the current OSD provider.
Definition: osd.c:2124
cOsdObject::NeedsFastResponse
virtual bool NeedsFastResponse(void)
Definition: osdbase.h:79
cPluginManager::Shutdown
void Shutdown(bool Log=false)
Definition: plugin.c:512
cPluginManager::AddPlugin
void AddPlugin(const char *Args)
Definition: plugin.c:318
cControl::Launch
static void Launch(cControl *Control)
Definition: player.c:79
i18n.h
cDevice::Shutdown
static void Shutdown(void)
Closes down all devices.
Definition: device.c:446
cEITScanner::Process
void Process(void)
Definition: eitscan.c:128
cPluginManager::SetDirectory
void SetDirectory(const char *Directory)
Definition: plugin.c:312
cSetup::PrimaryDVB
int PrimaryDVB
Definition: config.h:261
Sources
cSources Sources
Definition: sources.c:117
cArgs::GetArgc
int GetArgc(void) const
Definition: args.h:30
cDevice
Definition: device.h:117
I18nInitialize
void I18nInitialize(const char *LocaleDir)
Detects all available locales and loads the language names and codes.
Definition: i18n.c:103
eOSState
eOSState
Definition: osdbase.h:18
cDevice::SetPrimaryDevice
static bool SetPrimaryDevice(int n)
Sets the primary device to 'n'.
Definition: device.c:187
cSetup::OSDSkin
char OSDSkin[MaxSkinName]
Definition: config.h:259
cEITScanner::Active
bool Active(void)
Definition: eitscan.h:33
CutRecording
bool CutRecording(const char *FileName)
Definition: cutter.c:726
cListBase::Clear
virtual void Clear(void)
Definition: tools.c:2229
cShutdownHandler::SetUserInactiveTimeout
void SetUserInactiveTimeout(int Seconds=-1, bool Force=false)
Set the time in the future when VDR will switch into non-interactive mode or power down.
Definition: shutdown.c:141
RemoveDeletedRecordings
void RemoveDeletedRecordings(void)
Definition: recording.c:137
interface.h
kPrev
@ kPrev
Definition: keys.h:38
cEITScanner::Activity
void Activity(void)
Definition: eitscan.c:118
SetSVDRPPorts
void SetSVDRPPorts(int TcpPort, int UdpPort)
Definition: svdrp.c:2725
videodir.h
SHUTDOWNCANCELPROMPT
#define SHUTDOWNCANCELPROMPT
Definition: vdr.c:80
cConfig::Load
bool Load(const char *FileName=NULL, bool AllowComments=false, bool MustExist=false)
Definition: config.h:120
GenerateIndex
bool GenerateIndex(const char *FileName, bool Update)
Generates the index of the existing recording with the given FileName.
Definition: recording.c:2853
cArgs
Definition: args.h:17
CamSlots
cCamSlots CamSlots
Definition: ci.c:2808
k_Plugin
@ k_Plugin
Definition: keys.h:58
cStateKey::Remove
void Remove(bool IncState=true)
Removes this key from the lock it was previously used with.
Definition: thread.c:859
cCountdown::Update
bool Update(void)
Update status display of the countdown.
Definition: shutdown.c:64
DEFAULTRESDIR
#define DEFAULTRESDIR
cChannels
Definition: channels.h:210
VDRVERSION
#define VDRVERSION
Definition: config.h:25
SetSVDRPGrabImageDir
void SetSVDRPGrabImageDir(const char *GrabImageDir)
Definition: svdrp.c:2731
ISREALKEY
#define ISREALKEY(k)
Definition: keys.h:81
cInterface::Confirm
bool Confirm(const char *s, int Seconds=10, bool WaitForTimeout=false)
Definition: interface.c:59
cTimers::DeleteExpired
bool DeleteExpired(void)
Definition: timers.c:890
osTimers
@ osTimers
Definition: osdbase.h:22
SHUTDOWNRETRY
#define SHUTDOWNRETRY
Definition: vdr.c:78
cDvbDevice::Initialize
static bool Initialize(void)
Initializes the DVB devices.
Definition: dvbdevice.c:1926
Commands
cNestedItemList Commands
Definition: config.c:275
DirectoryNameMax
int DirectoryNameMax
Definition: recording.c:77
cSetup::DiSEqC
int DiSEqC
Definition: config.h:273
cListGarbageCollector::Purge
void Purge(bool Force=false)
Definition: tools.c:2111
main
int main(int argc, char *argv[])
Definition: vdr.c:198
cRecordings::Update
static void Update(bool Wait=false)
Triggers an update of the list of recordings, which will run as a separate thread if Wait is false.
Definition: recording.c:1520
LastSignal
static int LastSignal
Definition: vdr.c:94
cSetup::CurrentChannel
int CurrentChannel
Definition: config.h:358
ListGarbageCollector
cListGarbageCollector ListGarbageCollector
Definition: tools.c:2088
k0
@ k0
Definition: keys.h:28
cOsdObject::IsMenu
bool IsMenu(void) const
Definition: osdbase.h:80
kUser9
@ kUser9
Definition: keys.h:54
cSkins::Clear
virtual void Clear(void)
Free up all registered skins.
Definition: skins.c:408
DELETE_MENU
#define DELETE_MENU
dvbdevice.h
cPluginManager::LoadPlugins
bool LoadPlugins(bool Log=false)
Definition: plugin.c:354
ChannelCamRelations
cChannelCamRelations ChannelCamRelations
Definition: ci.c:2917
cChannel::Vpid
int Vpid(void) const
Definition: channels.h:154
cThemes::Load
bool Load(const char *SkinName)
Definition: themes.c:239
cArgs::ReadDirectory
bool ReadDirectory(const char *Directory)
Definition: args.c:39
cPluginManager
Definition: plugin.h:83
dsyslog
#define dsyslog(a...)
Definition: tools.h:37
tfVps
@ tfVps
Definition: timers.h:21
cOsdProvider::OsdSizeChanged
static bool OsdSizeChanged(int &State)
Checks if the OSD size has changed and a currently displayed OSD needs to be redrawn.
Definition: osd.c:2064
cDevice::SetOccupied
void SetOccupied(int Seconds)
Sets the occupied timeout for this device to the given number of Seconds, This can be used to tune a ...
Definition: device.c:936
cKbdRemote
Definition: remote.h:105
cChannel
Definition: channels.h:89
cChannel::Apid
int Apid(int i) const
Definition: channels.h:160
SignalHandler
static void SignalHandler(int signum)
Definition: vdr.c:171
mtWarning
@ mtWarning
Definition: skins.h:37
StartSVDRPHandler
void StartSVDRPHandler(void)
Definition: svdrp.c:2813
cStateKey::StateChanged
bool StateChanged(void)
Returns true if this key is used for obtaining a write lock, and the lock's state differs from that o...
Definition: thread.c:869
cDisplayChannel
Definition: menu.h:120
Scrs
cScrs Scrs
Definition: diseqc.c:182
cShutdownHandler::SetShutdownCommand
void SetShutdownCommand(const char *ShutdownCommand)
Set the command string for shutdown command.
Definition: shutdown.c:121
osRecord
@ osRecord
Definition: osdbase.h:28
cSkinLCARS
Definition: skinlcars.h:15
MANUALSTART
#define MANUALSTART
Definition: vdr.c:82
kPause
@ kPause
Definition: keys.h:32
CiResourceHandlers
cCiResourceHandlers CiResourceHandlers
Definition: ci.c:1752
sourceparams.h
cInterface::GetKey
eKeys GetKey(bool Wait=true)
Definition: interface.c:31
DEVICEREADYTIMEOUT
#define DEVICEREADYTIMEOUT
Definition: vdr.c:84
cSkins::ProcessQueuedMessages
void ProcessQueuedMessages(void)
Processes the first queued message, if any.
Definition: skins.c:352
CamMenuActive
bool CamMenuActive(void)
Definition: menu.c:2434
cSchedules::SetEpgDataFileName
static void SetEpgDataFileName(const char *FileName)
Definition: epg.c:1241
cSetup::RecordKeyHandling
int RecordKeyHandling
Definition: config.h:303
cDisplaySubtitleTracks::IsOpen
static bool IsOpen(void)
Definition: menu.h:190
kTimers
@ kTimers
Definition: keys.h:50
cSkinSTTNG
Definition: skinsttng.h:15
MENUTIMEOUT
#define MENUTIMEOUT
Definition: vdr.c:85
ACTIVITYTIMEOUT
#define ACTIVITYTIMEOUT
Definition: vdr.c:76
cRecordings::NeedsUpdate
static bool NeedsUpdate(void)
Definition: recording.c:1512
cRemote::GetPlugin
static const char * GetPlugin(void)
Returns the name of the plugin that was set with a previous call to PutMacro() or CallPlugin().
Definition: remote.c:162
timers.h
cChannels::Load
static bool Load(const char *FileName, bool AllowComments=false, bool MustExist=false)
Definition: channels.c:879
cDvbDevice::BondDevices
static bool BondDevices(const char *Bondings)
Bonds the devices as defined in the given Bondings string.
Definition: dvbdevice.c:1989
osEnd
@ osEnd
Definition: osdbase.h:34
cPluginManager::StopPlugins
void StopPlugins(void)
Definition: plugin.c:500
cSchedules
Definition: epg.h:192
cExternalAudio
Definition: audio.h:49
cSetup::PauseKeyHandling
int PauseKeyHandling
Definition: config.h:304
cDisplayTracks::Create
static cDisplayTracks * Create(void)
Definition: menu.c:5130
cCountdown::Done
bool Done(void)
Check if countdown timer has run out without canceling.
Definition: shutdown.c:55
cCountdown::Cancel
void Cancel(void)
Cancel the 5 minute shutdown warning countdown.
Definition: shutdown.c:46
Skins
cSkins Skins
Definition: skins.c:219
cSetup::OSDTheme
char OSDTheme[MaxThemeName]
Definition: config.h:260
cReplayControl
Definition: menu.h:292
DEFAULTPLUGINDIR
#define DEFAULTPLUGINDIR
ISMODELESSKEY
#define ISMODELESSKEY(k)
Definition: keys.h:80
DEFAULTARGSDIR
#define DEFAULTARGSDIR
cDevice::ActualDevice
static cDevice * ActualDevice(void)
Returns the actual receiving device in case of Transfer Mode, or the primary device otherwise.
Definition: device.c:215
kSchedule
@ kSchedule
Definition: keys.h:48
cEpgDataReader
Definition: epg.h:227
CamControl
cOsdObject * CamControl(void)
Definition: menu.c:2425
eitscan.h
kUser0
@ kUser0
Definition: keys.h:54
cMenuMain
Definition: menu.h:104
cSetup::Save
bool Save(void)
Definition: config.c:736
kCommands
@ kCommands
Definition: keys.h:53
cDisplayVolume::Process
static void Process(eKeys Key)
Definition: menu.c:5047
cFont::GetFontFileName
static cString GetFontFileName(const char *FontName)
Returns the actual font file name for the given FontName.
Definition: font.c:479
mtError
@ mtError
Definition: skins.h:37
DEFAULTCONFDIR
#define DEFAULTCONFDIR
Watchdog
static void Watchdog(int signum)
Definition: vdr.c:187
cTimers
Definition: timers.h:116
lirc.h
kDown
@ kDown
Definition: keys.h:18
cStateKey::Reset
void Reset(void)
Resets the state of this key, so that the next call to a lock's Lock() function with this key will re...
Definition: thread.c:854
cDevice::GetDeviceForTransponder
static cDevice * GetDeviceForTransponder(const cChannel *Channel, int Priority)
Returns a device that is not currently "occupied" and can be tuned to the transponder of the given Ch...
Definition: device.c:415
osBack
@ osBack
Definition: osdbase.h:33
MEGABYTE
#define MEGABYTE(n)
Definition: tools.h:45
cDevice::SwitchChannel
bool SwitchChannel(const cChannel *Channel, bool LiveView)
Switches the device to the given Channel, initiating transfer mode if necessary.
Definition: device.c:785
SourceParams
cSourceParams SourceParams
Definition: sourceparams.c:34
cThread::Active
bool Active(void)
Checks whether the thread is still alive.
Definition: thread.c:329
cTimers::GetTimersWrite
static cTimers * GetTimersWrite(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of timers for write access.
Definition: timers.c:848
cCharSetConv::SetSystemCharacterTable
static void SetSystemCharacterTable(const char *CharacterTable)
Definition: tools.c:968
kSetup
@ kSetup
Definition: keys.h:52
DEFAULTVIDEODIR
#define DEFAULTVIDEODIR
mtInfo
@ mtInfo
Definition: skins.h:37
tfActive
@ tfActive
Definition: timers.h:19
cChannels::GetChannelsRead
static const cChannels * GetChannelsRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of channels for read access.
Definition: channels.c:850
SI::SetSystemCharacterTable
bool SetSystemCharacterTable(const char *CharacterTable)
Definition: si.c:340
cDevice::DeviceNumber
int DeviceNumber(void) const
Returns the number of this device (0 ... numDevices - 1).
Definition: device.c:160
cSetup::MenuKeyCloses
int MenuKeyCloses
Definition: config.h:266
cRecordingUserCommand::SetCommand
static void SetCommand(const char *Command)
Definition: recording.h:431
cInterface::LearnKeys
void LearnKeys(void)
Definition: interface.c:147
config.h
osSetup
@ osSetup
Definition: osdbase.h:25
kSubtitles
@ kSubtitles
Definition: keys.h:47
si.h
cInterface
Definition: interface.h:17
cDevice::SetUseDevice
static void SetUseDevice(int n)
Sets the 'useDevice' flag of the given device.
Definition: device.c:142
cPluginManager::Housekeeping
void Housekeeping(void)
Definition: plugin.c:390
cList::Next
const T * Next(const T *Object) const
< Returns the element immediately before Object in this list, or NULL if Object is the first element ...
Definition: tools.h:613
epg.h
kRight
@ kRight
Definition: keys.h:23
DirectoryOk
bool DirectoryOk(const char *DirName, bool LogErrors)
Definition: tools.c:463
cVideoDirectory::Destroy
static void Destroy(void)
Definition: videodir.c:50
cPlugin::SetConfigDirectory
static void SetConfigDirectory(const char *Dir)
Definition: plugin.c:135
cThread::Start
void bool Start(void)
Sets the description of this thread, which will be used when logging starting or stopping of the thre...
Definition: thread.c:304
kInfo
@ kInfo
Definition: keys.h:29
cDisplayTracks::Process
static void Process(eKeys Key)
Definition: menu.c:5141
DEFAULTLOCDIR
#define DEFAULTLOCDIR
audio.h
cDisplaySubtitleTracks::Create
static cDisplaySubtitleTracks * Create(void)
Definition: menu.c:5248
MAXVIDEOFILESIZEDEFAULT
#define MAXVIDEOFILESIZEDEFAULT
Definition: recording.h:446
cRecordControls::PauseLiveVideo
static bool PauseLiveVideo(void)
Definition: menu.c:5528
tools.h
kVolUp
@ kVolUp
Definition: keys.h:43
Diseqcs
cDiseqcs Diseqcs
Definition: diseqc.c:439
osReplay
@ osReplay
Definition: osdbase.h:29
osdbase.h
isyslog
#define isyslog(a...)
Definition: tools.h:36
DirectMainFunction
#define DirectMainFunction(function)
cDevice::HasDecoder
virtual bool HasDecoder(void) const
Tells whether this device has an MPEG decoder.
Definition: device.c:205
cSchedule
Definition: epg.h:150
cRecordControls::Start
static bool Start(cTimers *Timers, cTimer *Timer, bool Pause=false)
Definition: menu.c:5439
cPlugin::MainMenuAction
virtual cOsdObject * MainMenuAction(void)
Definition: plugin.c:95
LOCK_CHANNELS_WRITE
#define LOCK_CHANNELS_WRITE
Definition: channels.h:268
VPSUPTODATETIME
#define VPSUPTODATETIME
Definition: vdr.c:90
cSetup::DeviceBondings
cString DeviceBondings
Definition: config.h:369
osUnknown
@ osUnknown
Definition: osdbase.h:18
cPlugin::CommandLineHelp
virtual const char * CommandLineHelp(void)
Definition: plugin.c:48
StateKeySVDRPRemoteTimersPoll
cStateKey StateKeySVDRPRemoteTimersPoll
Controls whether a change to the local list of timers needs to result in sending a POLL to the remote...
CHANNELMOD_RETUNE
#define CHANNELMOD_RETUNE
Definition: channels.h:29
tChannelID::FromString
static tChannelID FromString(const char *s)
Definition: channels.c:24
cShutdownHandler::DoShutdown
bool DoShutdown(bool Force)
Call the shutdown script with data of the next pending timer.
Definition: shutdown.c:233
cDisplayChannel::IsOpen
static bool IsOpen(void)
Definition: menu.h:143
cSetup::FontOsd
char FontOsd[MAXFONTNAME]
Definition: config.h:328
APIVERSION
#define APIVERSION
Definition: config.h:30
cControl::GetInfo
virtual cOsdObject * GetInfo(void)
Returns an OSD object that displays information about the currently played programme.
Definition: player.c:58
kRecord
@ kRecord
Definition: keys.h:34
StrToNum
int64_t StrToNum(const char *s)
Converts the given string to a number.
Definition: tools.c:357
osChannels
@ osChannels
Definition: osdbase.h:21
esyslog
#define esyslog(a...)
Definition: tools.h:35
kChanPrev
@ kChanPrev
Definition: keys.h:42
skinsttng.h
status.h
cControl::Control
static cControl * Control(bool Hidden=false)
Returns the current replay control (if any) in case it is currently visible.
Definition: player.c:73
osPlugin
@ osPlugin
Definition: osdbase.h:24
cMenuMain::PluginOsdObject
static cOsdObject * PluginOsdObject(void)
Definition: menu.c:4470
cControl::Attach
static void Attach(void)
Definition: player.c:87
kMenu
@ kMenu
Definition: keys.h:19
cDiseqcs::Load
bool Load(const char *FileName, bool AllowComments=false, bool MustExist=false)
Definition: diseqc.c:441
cControl::Shutdown
static void Shutdown(void)
Definition: player.c:100
cRecordControls::ChannelDataModified
static void ChannelDataModified(const cChannel *Channel)
Definition: menu.c:5591
cOsdObject::Show
virtual void Show(void)
Definition: osdbase.c:70
cPluginManager::StartPlugins
bool StartPlugins(void)
Definition: plugin.c:376
cPlugin::SetResourceDirectory
static void SetResourceDirectory(const char *Dir)
Definition: plugin.c:163
kPlay
@ kPlay
Definition: keys.h:31
cTimers::GetMaxPriority
int GetMaxPriority(void) const
Returns the maximum priority of all local timers that are currently recording.
Definition: timers.c:820
cShutdownHandler::countdown
cCountdown countdown
Definition: shutdown.h:51
RecordingCommands
cNestedItemList RecordingCommands
Definition: config.c:276
cSkins::SetCurrent
bool SetCurrent(const char *Name=NULL)
Sets the current skin to the one indicated by name.
Definition: skins.c:231