From 38886de0c3e9ea5729ef23e4c653fa2822f52e8f Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Tue, 6 Apr 2021 14:43:39 +0200 Subject: xscreensaver 6.00 --- driver/prefs.c | 1702 ++------------------------------------------------------ 1 file changed, 39 insertions(+), 1663 deletions(-) (limited to 'driver/prefs.c') diff --git a/driver/prefs.c b/driver/prefs.c index b608738..a65b679 100644 --- a/driver/prefs.c +++ b/driver/prefs.c @@ -1,5 +1,5 @@ -/* dotfile.c --- management of the ~/.xscreensaver file. - * xscreensaver, Copyright (c) 1998-2020 Jamie Zawinski +/* prefs.c --- reading and writing the ~/.xscreensaver file. + * xscreensaver, Copyright © 1998-2021 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -14,311 +14,20 @@ # include "config.h" #endif -#include - -#ifdef HAVE_UNISTD_H -# include -#endif - #include -#include +#include #include #include #include #include -#include /* for PATH_MAX */ -#include -#include - -#ifndef VMS -# include -#else /* VMS */ -# include "vms-pwd.h" -#endif /* VMS */ - - -/* This file doesn't need the Xt headers, so stub these types out... */ -#undef XtPointer -#define XtAppContext void* -#define XtIntervalId void* -#define XtPointer void* -#define Widget void* - - -/* Just in case there's something pathological about stat.h... */ -#ifndef S_IRUSR -# define S_IRUSR 00400 -#endif -#ifndef S_IWUSR -# define S_IWUSR 00200 -#endif -#ifndef S_IXUSR -# define S_IXUSR 00100 -#endif -#ifndef S_IXGRP -# define S_IXGRP 00010 -#endif -#ifndef S_IXOTH -# define S_IXOTH 00001 +#ifdef HAVE_UNISTD_H +# include #endif - -#include "version.h" +#include "blurb.h" #include "prefs.h" -#include "resources.h" - -/* don't use realpath() on fedora system */ -#ifdef _FORTIFY_SOURCE -#undef HAVE_REALPATH -#endif - - -extern char *progname; -extern char *progclass; -extern const char *blurb (void); - - - -static void get_screenhacks (Display *, saver_preferences *); -static char *format_command (const char *cmd, Bool wrap_p); -static void merge_system_screenhacks (Display *, saver_preferences *, - screenhack **system_list, int count); -static void stop_the_insanity (saver_preferences *p); - - -static char * -chase_symlinks (const char *file) -{ -# ifdef HAVE_REALPATH - if (file) - { -# ifndef PATH_MAX -# ifdef MAXPATHLEN -# define PATH_MAX MAXPATHLEN -# else -# define PATH_MAX 2048 -# endif -# endif - char buf[PATH_MAX]; - if (realpath (file, buf)) - return strdup (buf); - -/* sprintf (buf, "%.100s: realpath %.200s", blurb(), file); - perror(buf);*/ - } -# endif /* HAVE_REALPATH */ - return 0; -} - - -static Bool -i_am_a_nobody (uid_t uid) -{ - struct passwd *p; - - p = getpwnam ("nobody"); - if (! p) p = getpwnam ("noaccess"); - if (! p) p = getpwnam ("daemon"); - - if (! p) /* There is no nobody? */ - return False; - - return (uid == p->pw_uid); -} - - -const char * -init_file_name (void) -{ - static char *file = 0; - - if (!file) - { - uid_t uid = getuid (); - const char *home = getenv("HOME"); - - if (i_am_a_nobody (uid) || !home || !*home) - { - /* If we're running as nobody, then use root's .xscreensaver file - (since ~root/.xscreensaver and ~nobody/.xscreensaver are likely - to be different -- if we didn't do this, then xscreensaver-demo - would appear to have no effect when the luser is running as root.) - */ - struct passwd *p = getpwuid (uid); - uid = 0; - if (!p || !p->pw_name || !*p->pw_name) - { - fprintf (stderr, "%s: couldn't get user info of uid %d\n", - blurb(), getuid ()); - } - else if (!p->pw_dir || !*p->pw_dir) - { - fprintf (stderr, "%s: couldn't get home directory of \"%s\"\n", - blurb(), (p->pw_name ? p->pw_name : "???")); - } - else - { - home = p->pw_dir; - } - } - if (home && *home) - { - const char *name = ".xscreensaver"; - file = (char *) malloc(strlen(home) + strlen(name) + 2); - strcpy(file, home); - if (!*home || home[strlen(home)-1] != '/') - strcat(file, "/"); - strcat(file, name); - } - else - { - file = ""; - } - } - - if (file && *file) - return file; - else - return 0; -} - - -static const char * -init_file_tmp_name (void) -{ - static char *file = 0; - if (!file) - { - const char *name = init_file_name(); - const char *suffix = ".tmp"; - - char *n2 = chase_symlinks (name); - if (n2) name = n2; - if (!name || !*name) - file = ""; - else - { - file = (char *) malloc(strlen(name) + strlen(suffix) + 2); - strcpy(file, name); - strcat(file, suffix); - } - - if (n2) free (n2); - } - - if (file && *file) - return file; - else - return 0; -} - -static int -get_byte_resource (Display *dpy, char *name, char *class) -{ - char *s = get_string_resource (dpy, name, class); - char *s2 = s; - int n = 0; - if (!s) return 0; - - while (isspace(*s2)) s2++; - while (*s2 >= '0' && *s2 <= '9') - { - n = (n * 10) + (*s2 - '0'); - s2++; - } - while (isspace(*s2)) s2++; - if (*s2 == 'k' || *s2 == 'K') n <<= 10; - else if (*s2 == 'm' || *s2 == 'M') n <<= 20; - else if (*s2 == 'g' || *s2 == 'G') n <<= 30; - else if (*s2) - { - LOSE: - fprintf (stderr, "%s: %s must be a number of bytes, not \"%s\".\n", - progname, name, s); - free (s); - return 0; - } - s2++; - if (*s2 == 'b' || *s2 == 'B') s2++; - while (isspace(*s2)) s2++; - if (*s2) goto LOSE; - - free (s); - return n; -} - - -static const char * const prefs[] = { - "timeout", - "cycle", - "lock", - "lockVTs", /* not saved */ - "lockTimeout", - "passwdTimeout", - "visualID", - "installColormap", - "verbose", - "timestamp", - "splash", - "splashDuration", - "quad", - "demoCommand", - "prefsCommand", - "newLoginCommand", - "helpURL", /* not saved */ - "loadURL", /* not saved */ - "newLoginCommand", /* not saved */ - "externalUngrabCommand", /* not saved */ - "nice", - "memoryLimit", - "fade", - "unfade", - "fadeSeconds", - "fadeTicks", - "captureStderr", - "captureStdout", /* not saved -- obsolete */ - "logFile", /* not saved */ - "ignoreUninstalledPrograms", - "font", - "dpmsEnabled", - "dpmsQuickOff", - "dpmsStandby", - "dpmsSuspend", - "dpmsOff", - "dpmsFullThrottle", - "grabDesktopImages", - "grabVideoFrames", - "chooseRandomImages", - "imageDirectory", - "mode", - "selected", - "textMode", - "textLiteral", - "textFile", - "textProgram", - "textURL", - "", - "programs", - "", - "pointerPollTime", - "pointerHysteresis", - "windowCreationTimeout", - "initialDelay", - "sgiSaverExtension", /* not saved -- obsolete */ - "mitSaverExtension", /* not saved -- obsolete */ - "xidleExtension", /* not saved -- obsolete */ - "GetViewPortIsFullOfLies", - "procInterrupts", - "xinputExtensionDev", - "overlayStderr", - "overlayTextBackground", /* not saved -- X resources only */ - "overlayTextForeground", /* not saved -- X resources only */ - "bourneShell", /* not saved -- X resources only */ - "authWarningSlack", - 0 -}; static char * strip (char *s) @@ -336,85 +45,49 @@ strip (char *s) return s; } - -/* Reading - */ - -static int -handle_entry (XrmDatabase *db, const char *key, const char *value, - const char *filename, int line) -{ - int i; - for (i = 0; prefs[i]; i++) - if (*prefs[i] && !strcasecmp(key, prefs[i])) - { - char *val = strdup(value); - char *spec = (char *) malloc(strlen(progclass) + strlen(prefs[i]) +10); - strcpy(spec, progclass); - strcat(spec, "."); - strcat(spec, prefs[i]); - - XrmPutStringResource (db, spec, val); - - free(spec); - free(val); - return 0; - } - - fprintf(stderr, "%s: %s:%d: unknown option \"%s\"\n", - blurb(), filename, line, key); - return 1; -} - -static int -parse_init_file (saver_preferences *p) +/* Parse the .xscreensaver or XScreenSaver.ad file and run the callback + for each key-value pair. +*/ +int +parse_init_file (const char *name, + void (*handler) (int lineno, + const char *key, const char *val, + void *closure), + void *closure) { - time_t write_date = 0; - const char *name = init_file_name(); int line = 0; struct stat st; FILE *in; int buf_size = 1024; - char *buf; + char *buf = 0; if (!name) return 0; + if (stat (name, &st) != 0) goto FAIL; - if (stat(name, &st) != 0) - { - p->init_file_date = 0; - return 0; - } + buf = (char *) malloc (buf_size); + if (!buf) goto FAIL; in = fopen(name, "r"); if (!in) { - char *buf = (char *) malloc(1024 + strlen(name)); - sprintf(buf, "%s: error reading \"%s\"", blurb(), name); - perror(buf); - free(buf); - return -1; + sprintf (buf, "%s: error reading \"%.100s\"", blurb(), name); + perror (buf); + goto FAIL; } - if (fstat (fileno(in), &st) == 0) + if (fstat (fileno (in), &st) != 0) { - write_date = st.st_mtime; - } - else - { - char *buf = (char *) malloc(1024 + strlen(name)); - sprintf(buf, "%s: couldn't re-stat \"%s\"", blurb(), name); - perror(buf); - free(buf); + sprintf (buf, "%s: couldn't re-stat \"%.100s\"", blurb(), name); + perror (buf); + free (buf); return -1; } - buf = (char *) malloc(buf_size); - while (fgets (buf, buf_size-1, in)) { char *key, *value; - int L = strlen(buf); + int L = strlen (buf); line++; while (L > 2 && @@ -427,13 +100,13 @@ parse_init_file (saver_preferences *p) L -= 2; } buf_size += 1024; - buf = (char *) realloc(buf, buf_size); - if (!buf) exit(1); + buf = (char *) realloc (buf, buf_size); + if (!buf) goto FAIL; line++; if (!fgets (buf + L, buf_size-L-1, in)) break; - L = strlen(buf); + L = strlen (buf); } /* Now handle other backslash escapes. */ @@ -455,7 +128,7 @@ parse_init_file (saver_preferences *p) } } - key = strip(buf); + key = strip (buf); if (*key == '#' || *key == '!' || *key == ';' || *key == '\n' || *key == 0) @@ -464,1320 +137,23 @@ parse_init_file (saver_preferences *p) value = strchr (key, ':'); if (!value) { - fprintf(stderr, "%s: %s:%d: unparsable line: %s\n", blurb(), - name, line, key); + fprintf (stderr, "%s: %s:%d: unparsable line: %s\n", blurb(), + name, line, key); continue; } else { *value++ = 0; - value = strip(value); + value = strip (value); } - if (!p->db) abort(); - handle_entry (&p->db, key, value, name, line); + handler (line, key, value, closure); } fclose (in); - free(buf); - - p->init_file_date = write_date; + free (buf); return 0; -} - - -Bool -init_file_changed_p (saver_preferences *p) -{ - const char *name = init_file_name(); - struct stat st; - - if (!name) return False; - - if (stat(name, &st) != 0) - return False; - - if (p->init_file_date == st.st_mtime) - return False; - - return True; -} - - -/* Writing - */ - -static int -tab_to (FILE *out, int from, int to) -{ - int tab_width = 8; - int to_mod = (to / tab_width) * tab_width; - while (from < to_mod) - { - fprintf(out, "\t"); - from = (((from / tab_width) + 1) * tab_width); - } - while (from < to) - { - fprintf(out, " "); - from++; - } - return from; -} - -static char * -stab_to (char *out, int from, int to) -{ - int tab_width = 8; - int to_mod = (to / tab_width) * tab_width; - while (from < to_mod) - { - *out++ = '\t'; - from = (((from / tab_width) + 1) * tab_width); - } - while (from < to) - { - *out++ = ' '; - from++; - } - return out; -} - -static int -string_columns (const char *string, int length, int start) -{ - int tab_width = 8; - int col = start; - const char *end = string + length; - while (string < end) - { - if (*string == '\n') - col = 0; - else if (*string == '\t') - col = (((col / tab_width) + 1) * tab_width); - else - col++; - string++; - } - return col; -} - - -static void -write_entry (FILE *out, const char *key, const char *value) -{ - char *v = strdup(value ? value : ""); - char *v2 = v; - char *nl = 0; - int col; - Bool programs_p = (!strcmp(key, "programs")); - int tab = (programs_p ? 32 : 16); - Bool first = True; - - fprintf(out, "%s:", key); - col = strlen(key) + 1; - - if (strlen(key) > 14) - col = tab_to (out, col, 20); - - while (1) - { - if (!programs_p) - v2 = strip(v2); - nl = strchr(v2, '\n'); - if (nl) - *nl = 0; - - if (first && programs_p) - { - col = tab_to (out, col, 77); - fprintf (out, " \\\n"); - col = 0; - } - - if (first) - first = False; - else - { - col = tab_to (out, col, 75); - fprintf (out, " \\n\\\n"); - col = 0; - } - - if (!programs_p) - col = tab_to (out, col, tab); - - if (programs_p && - string_columns(v2, strlen (v2), col) + col > 75) - { - int L = strlen (v2); - int start = 0; - int end = start; - while (start < L) - { - while (v2[end] == ' ' || v2[end] == '\t') - end++; - while (v2[end] != ' ' && v2[end] != '\t' && - v2[end] != '\n' && v2[end] != 0) - end++; - if (string_columns (v2 + start, (end - start), col) >= 74) - { - col = tab_to (out, col, 75); - fprintf(out, " \\\n"); - col = tab_to (out, 0, tab + 2); - while (v2[start] == ' ' || v2[start] == '\t') - start++; - } - - col = string_columns (v2 + start, (end - start), col); - while (start < end) - fputc(v2[start++], out); - } - } - else - { - fprintf (out, "%s", v2); - col += string_columns(v2, strlen (v2), col); - } - - if (nl) - v2 = nl + 1; - else - break; - } - - fprintf(out, "\n"); - free(v); -} - -int -write_init_file (Display *dpy, - saver_preferences *p, const char *version_string, - Bool verbose_p) -{ - int status = -1; - const char *name = init_file_name(); - const char *tmp_name = init_file_tmp_name(); - char *n2 = chase_symlinks (name); - struct stat st; - int i, j; - - /* Kludge, since these aren't in the saver_preferences struct as strings... - */ - char *visual_name; - char *programs; - Bool overlay_stderr_p; - char *stderr_font; - FILE *out; - - if (!name) goto END; - - if (n2) name = n2; - - /* Throttle the various timeouts to reasonable values before writing - the file to disk. */ - stop_the_insanity (p); - - - if (verbose_p) - fprintf (stderr, "%s: writing \"%s\".\n", blurb(), name); - - unlink (tmp_name); - out = fopen(tmp_name, "w"); - if (!out) - { - char *buf = (char *) malloc(1024 + strlen(name)); - sprintf(buf, "%s: error writing \"%s\"", blurb(), name); - perror(buf); - free(buf); - goto END; - } - - /* Give the new .xscreensaver file the same permissions as the old one; - except ensure that it is readable and writable by owner, and not - executable. Extra hack: if we're running as root, make the file - be world-readable (so that the daemon, running as "nobody", will - still be able to read it.) - */ - if (stat(name, &st) == 0) - { - mode_t mode = st.st_mode; - mode |= S_IRUSR | S_IWUSR; /* read/write by user */ - mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH); /* executable by none */ - - if (getuid() == (uid_t) 0) /* read by group/other */ - mode |= S_IRGRP | S_IROTH; - - if (fchmod (fileno(out), mode) != 0) - { - char *buf = (char *) malloc(1024 + strlen(name)); - sprintf (buf, "%s: error fchmodding \"%s\" to 0%o", blurb(), - tmp_name, (unsigned int) mode); - perror(buf); - free(buf); - goto END; - } - } - - /* Kludge, since these aren't in the saver_preferences struct... */ - visual_name = get_string_resource (dpy, "visualID", "VisualID"); - programs = 0; - overlay_stderr_p = get_boolean_resource (dpy, "overlayStderr", "Boolean"); - stderr_font = get_string_resource (dpy, "font", "Font"); - - i = 0; - { - char *ss; - char **hack_strings = (char **) - calloc (p->screenhacks_count, sizeof(char *)); - - for (j = 0; j < p->screenhacks_count; j++) - { - hack_strings[j] = format_hack (dpy, p->screenhacks[j], True); - i += strlen (hack_strings[j]); - i += 2; - } - - ss = programs = (char *) malloc(i + 10); - *ss = 0; - for (j = 0; j < p->screenhacks_count; j++) - { - strcat (ss, hack_strings[j]); - free (hack_strings[j]); - ss += strlen(ss); - *ss++ = '\n'; - *ss = 0; - } - free (hack_strings); - } - - { - struct passwd *pw = getpwuid (getuid ()); - char *whoami = (pw && pw->pw_name && *pw->pw_name - ? pw->pw_name - : ""); - time_t now = time ((time_t *) 0); - char *timestr = (char *) ctime (&now); - char *nl = (char *) strchr (timestr, '\n'); - if (nl) *nl = 0; - fprintf (out, - "# %s Preferences File\n" - "# Written by %s %s for %s on %s.\n" - "# https://www.jwz.org/xscreensaver/\n" - "\n", - progclass, progname, version_string, whoami, timestr); - } - - for (j = 0; prefs[j]; j++) - { - char buf[255]; - const char *pr = prefs[j]; - enum pref_type { pref_str, pref_int, pref_bool, pref_byte, pref_time - } type = pref_str; - const char *s = 0; - int i = 0; - Bool b = False; - Time t = 0; - - if (pr && !*pr) - { - fprintf(out, "\n"); - continue; - } - -# undef CHECK -# define CHECK(X) else if (!strcmp(pr, X)) - if (!pr || !*pr) ; - CHECK("timeout") type = pref_time, t = p->timeout; - CHECK("cycle") type = pref_time, t = p->cycle; - CHECK("lock") type = pref_bool, b = p->lock_p; - CHECK("lockVTs") continue; /* don't save, unused */ - CHECK("lockTimeout") type = pref_time, t = p->lock_timeout; - CHECK("passwdTimeout") type = pref_time, t = p->passwd_timeout; - CHECK("visualID") type = pref_str, s = visual_name; - CHECK("installColormap") type = pref_bool, b = p->install_cmap_p; - CHECK("verbose") type = pref_bool, b = p->verbose_p; - CHECK("timestamp") type = pref_bool, b = p->timestamp_p; - CHECK("splash") type = pref_bool, b = p->splash_p; - CHECK("splashDuration") type = pref_time, t = p->splash_duration; -# ifdef QUAD_MODE - CHECK("quad") type = pref_bool, b = p->quad_p; -# else /* !QUAD_MODE */ - CHECK("quad") continue; /* don't save */ -# endif /* !QUAD_MODE */ - CHECK("demoCommand") type = pref_str, s = p->demo_command; - CHECK("prefsCommand") type = pref_str, s = p->prefs_command; -/* CHECK("helpURL") type = pref_str, s = p->help_url; */ - CHECK("helpURL") continue; /* don't save */ -/* CHECK("loadURL") type = pref_str, s = p->load_url_command; */ - CHECK("loadURL") continue; /* don't save */ -/* CHECK("newLoginCommand") type = pref_str, s = p->new_login_command; */ - CHECK("newLoginCommand") continue; /* don't save */ - CHECK("externalUngrabCommand") continue; /* don't save */ - CHECK("nice") type = pref_int, i = p->nice_inferior; - CHECK("memoryLimit") type = pref_byte, i = p->inferior_memory_limit; - CHECK("fade") type = pref_bool, b = p->fade_p; - CHECK("unfade") type = pref_bool, b = p->unfade_p; - CHECK("fadeSeconds") type = pref_time, t = p->fade_seconds; - CHECK("fadeTicks") type = pref_int, i = p->fade_ticks; - CHECK("captureStderr") type = pref_bool, b = p->capture_stderr_p; - CHECK("captureStdout") continue; /* don't save */ - CHECK("logFile") continue; /* don't save */ - CHECK("ignoreUninstalledPrograms") - type = pref_bool, b = p->ignore_uninstalled_p; - - CHECK("font") type = pref_str, s = stderr_font; - - CHECK("dpmsEnabled") type = pref_bool, b = p->dpms_enabled_p; - CHECK("dpmsQuickOff") type = pref_bool, b = p->dpms_quickoff_p; - CHECK("dpmsStandby") type = pref_time, t = p->dpms_standby; - CHECK("dpmsSuspend") type = pref_time, t = p->dpms_suspend; - CHECK("dpmsOff") type = pref_time, t = p->dpms_off; - CHECK("dpmsFullThrottle") continue; /* don't save */ - - CHECK("grabDesktopImages") type =pref_bool, b = p->grab_desktop_p; - CHECK("grabVideoFrames") type =pref_bool, b = p->grab_video_p; - CHECK("chooseRandomImages")type =pref_bool, b = p->random_image_p; - CHECK("imageDirectory") type =pref_str, s = p->image_directory; - - CHECK("mode") type = pref_str, - s = (p->mode == ONE_HACK ? "one" : - p->mode == BLANK_ONLY ? "blank" : - p->mode == DONT_BLANK ? "off" : - p->mode == RANDOM_HACKS_SAME - ? "random-same" - : "random"); - CHECK("selected") type = pref_int, i = p->selected_hack; - - CHECK("textMode") type = pref_str, - s = (p->tmode == TEXT_URL ? "url" : - p->tmode == TEXT_LITERAL ? "literal" : - p->tmode == TEXT_FILE ? "file" : - p->tmode == TEXT_PROGRAM ? "program" : - "date"); - CHECK("textLiteral") type = pref_str, s = p->text_literal; - CHECK("textFile") type = pref_str, s = p->text_file; - CHECK("textProgram") type = pref_str, s = p->text_program; - CHECK("textURL") type = pref_str, s = p->text_url; - - CHECK("programs") type = pref_str, s = programs; - CHECK("pointerPollTime") type = pref_time, t = p->pointer_timeout; - CHECK("pointerHysteresis")type = pref_int, i = p->pointer_hysteresis; - CHECK("windowCreationTimeout")type=pref_time,t= p->notice_events_timeout; - CHECK("initialDelay") type = pref_time, t = p->initial_delay; - CHECK("sgiSaverExtension") continue; /* don't save */ - CHECK("mitSaverExtension") continue; /* don't save */ - CHECK("xidleExtension") continue; /* don't save */ - CHECK("procInterrupts") type = pref_bool, b = p->use_proc_interrupts; - CHECK("xinputExtensionDev") type = pref_bool, b = p->use_xinput_extension; - CHECK("GetViewPortIsFullOfLies") type = pref_bool, - b = p->getviewport_full_of_lies_p; - CHECK("overlayStderr") type = pref_bool, b = overlay_stderr_p; - CHECK("overlayTextBackground") continue; /* don't save */ - CHECK("overlayTextForeground") continue; /* don't save */ - CHECK("bourneShell") continue; /* don't save */ - CHECK("authWarningSlack") type = pref_int, i = p->auth_warning_slack; - else abort(); -# undef CHECK - - switch (type) - { - case pref_str: - break; - case pref_int: - sprintf(buf, "%d", i); - s = buf; - break; - case pref_bool: - s = b ? "True" : "False"; - break; - case pref_time: - { - unsigned int hour = 0, min = 0, sec = (unsigned int) (t/1000); - if (sec >= 60) - { - min += (sec / 60); - sec %= 60; - } - if (min >= 60) - { - hour += (min / 60); - min %= 60; - } - sprintf (buf, "%u:%02u:%02u", hour, min, sec); - s = buf; - } - break; - case pref_byte: - { - if (i >= (1<<30) && i == ((i >> 30) << 30)) - sprintf(buf, "%dG", i >> 30); - else if (i >= (1<<20) && i == ((i >> 20) << 20)) - sprintf(buf, "%dM", i >> 20); - else if (i >= (1<<10) && i == ((i >> 10) << 10)) - sprintf(buf, "%dK", i >> 10); - else - sprintf(buf, "%d", i); - s = buf; - } - break; - default: - abort(); - break; - } - - if (pr && (!strcmp(pr, "mode") || !strcmp(pr, "textMode"))) - fprintf(out, "\n"); - - write_entry (out, pr, s); - } - - fprintf(out, "\n"); - - if (visual_name) free(visual_name); - if (stderr_font) free(stderr_font); - if (programs) free(programs); - - if (fclose(out) == 0) - { - time_t write_date = 0; - - if (stat(tmp_name, &st) == 0) - { - write_date = st.st_mtime; - } - else - { - char *buf = (char *) malloc(1024 + strlen(tmp_name) + strlen(name)); - sprintf(buf, "%s: couldn't stat \"%s\"", blurb(), tmp_name); - perror(buf); - unlink (tmp_name); - free(buf); - goto END; - } - - if (rename (tmp_name, name) != 0) - { - char *buf = (char *) malloc(1024 + strlen(tmp_name) + strlen(name)); - sprintf(buf, "%s: error renaming \"%s\" to \"%s\"", - blurb(), tmp_name, name); - perror(buf); - unlink (tmp_name); - free(buf); - goto END; - } - else - { - p->init_file_date = write_date; - - /* Since the .xscreensaver file is used for IPC, let's try and make - sure that the bits actually land on the disk right away. */ - sync (); - - status = 0; /* wrote and renamed successfully! */ - } - } - else - { - char *buf = (char *) malloc(1024 + strlen(name)); - sprintf(buf, "%s: error closing \"%s\"", blurb(), name); - perror(buf); - free(buf); - unlink (tmp_name); - goto END; - } - - END: - if (n2) free (n2); - return status; -} - - -/* Parsing the resource database - */ - -void -free_screenhack (screenhack *hack) -{ - if (hack->visual) free (hack->visual); - if (hack->name) free (hack->name); - free (hack->command); - memset (hack, 0, sizeof(*hack)); - free (hack); -} - -static void -free_screenhack_list (screenhack **list, int count) -{ - int i; - if (!list) return; - for (i = 0; i < count; i++) - if (list[i]) - free_screenhack (list[i]); - free (list); -} - - - -/* Populate `saver_preferences' with the contents of the resource database. - Note that this may be called multiple times -- it is re-run each time - the ~/.xscreensaver file is reloaded. - - This function can be very noisy, since it issues resource syntax errors - and so on. - */ -void -load_init_file (Display *dpy, saver_preferences *p) -{ - static Bool first_time = True; - - screenhack **system_default_screenhacks = 0; - int system_default_screenhack_count = 0; - - if (first_time) - { - /* Get the programs resource before the .xscreensaver file has been - parsed and merged into the resource database for the first time: - this is the value of *programs from the app-defaults file. - Then clear it out so that it will be parsed again later, after - the init file has been read. - */ - get_screenhacks (dpy, p); - system_default_screenhacks = p->screenhacks; - system_default_screenhack_count = p->screenhacks_count; - p->screenhacks = 0; - p->screenhacks_count = 0; - } - - if (parse_init_file (p) != 0) /* file might have gone away */ - if (!first_time) return; - - first_time = False; - - p->xsync_p = get_boolean_resource (dpy, "synchronous", "Synchronous"); - p->verbose_p = get_boolean_resource (dpy, "verbose", "Boolean"); - p->timestamp_p = get_boolean_resource (dpy, "timestamp", "Boolean"); - p->lock_p = get_boolean_resource (dpy, "lock", "Boolean"); - p->fade_p = get_boolean_resource (dpy, "fade", "Boolean"); - p->unfade_p = get_boolean_resource (dpy, "unfade", "Boolean"); - p->fade_seconds = 1000 * get_seconds_resource (dpy, "fadeSeconds", "Time"); - p->fade_ticks = get_integer_resource (dpy, "fadeTicks", "Integer"); - p->install_cmap_p = get_boolean_resource (dpy, "installColormap", "Boolean"); - p->nice_inferior = get_integer_resource (dpy, "nice", "Nice"); - p->inferior_memory_limit = get_byte_resource (dpy, "memoryLimit", - "MemoryLimit"); - p->splash_p = get_boolean_resource (dpy, "splash", "Boolean"); -# ifdef QUAD_MODE - p->quad_p = get_boolean_resource (dpy, "quad", "Boolean"); -# endif - p->capture_stderr_p = get_boolean_resource (dpy, "captureStderr", "Boolean"); - p->ignore_uninstalled_p = get_boolean_resource (dpy, - "ignoreUninstalledPrograms", - "Boolean"); - - p->initial_delay = 1000 * get_seconds_resource (dpy, "initialDelay", "Time"); - p->splash_duration = 1000 * get_seconds_resource (dpy, "splashDuration", "Time"); - p->timeout = 1000 * get_minutes_resource (dpy, "timeout", "Time"); - p->lock_timeout = 1000 * get_minutes_resource (dpy, "lockTimeout", "Time"); - p->cycle = 1000 * get_minutes_resource (dpy, "cycle", "Time"); - p->passwd_timeout = 1000 * get_seconds_resource (dpy, "passwdTimeout", "Time"); - p->pointer_timeout = 1000 * get_seconds_resource (dpy, "pointerPollTime", "Time"); - p->pointer_hysteresis = get_integer_resource (dpy, "pointerHysteresis","Integer"); - p->notice_events_timeout = 1000*get_seconds_resource(dpy, - "windowCreationTimeout", - "Time"); - - p->dpms_enabled_p = get_boolean_resource (dpy, "dpmsEnabled", "Boolean"); - p->dpms_quickoff_p = get_boolean_resource (dpy, "dpmsQuickOff", "Boolean"); - p->dpms_standby = 1000 * get_minutes_resource (dpy, "dpmsStandby", "Time"); - p->dpms_suspend = 1000 * get_minutes_resource (dpy, "dpmsSuspend", "Time"); - p->dpms_off = 1000 * get_minutes_resource (dpy, "dpmsOff", "Time"); - p->dpms_full_throttle_p = get_boolean_resource (dpy, "dpmsFullThrottle", "Boolean"); - - p->grab_desktop_p = get_boolean_resource (dpy, "grabDesktopImages", "Boolean"); - p->grab_video_p = get_boolean_resource (dpy, "grabVideoFrames", "Boolean"); - p->random_image_p = get_boolean_resource (dpy, "chooseRandomImages", "Boolean"); - p->image_directory = get_string_resource (dpy, - "imageDirectory", - "ImageDirectory"); - - p->text_literal = get_string_resource (dpy, "textLiteral", "TextLiteral"); - p->text_file = get_string_resource (dpy, "textFile", "TextFile"); - p->text_program = get_string_resource (dpy, "textProgram", "TextProgram"); - p->text_url = get_string_resource (dpy, "textURL", "TextURL"); - - p->shell = get_string_resource (dpy, "bourneShell", "BourneShell"); - - p->demo_command = get_string_resource(dpy, "demoCommand", "URL"); - p->prefs_command = get_string_resource(dpy, "prefsCommand", "URL"); - p->help_url = get_string_resource(dpy, "helpURL", "URL"); - p->load_url_command = get_string_resource(dpy, "loadURL", "LoadURL"); - p->new_login_command = get_string_resource(dpy, - "newLoginCommand", - "NewLoginCommand"); - p->external_ungrab_command = get_string_resource(dpy, - "externalUngrabCommand", - "ExternalUngrabCommand"); - p->auth_warning_slack = get_integer_resource(dpy, "authWarningSlack", - "Integer"); - - /* If "*splash" is unset, default to true. */ - { - char *s = get_string_resource (dpy, "splash", "Boolean"); - if (s) - free (s); - else - p->splash_p = True; - } - - /* If "*grabDesktopImages" is unset, default to true. */ - { - char *s = get_string_resource (dpy, "grabDesktopImages", "Boolean"); - if (s) - free (s); - else - p->grab_desktop_p = True; - } - - p->use_xidle_extension = get_boolean_resource (dpy, "xidleExtension","Boolean"); -#if 0 /* obsolete. */ - p->use_sgi_saver_extension = get_boolean_resource (dpy, - "sgiSaverExtension", - "Boolean"); -#endif -#ifdef HAVE_XINPUT - p->use_xinput_extension = get_boolean_resource (dpy, "xinputExtensionDev", - "Boolean"); -#endif -#if 0 /* broken and evil. */ - p->use_mit_saver_extension = get_boolean_resource (dpy, - "mitSaverExtension", - "Boolean"); -#endif - - p->use_proc_interrupts = get_boolean_resource (dpy, - "procInterrupts", "Boolean"); - - p->getviewport_full_of_lies_p = - get_boolean_resource (dpy, "GetViewPortIsFullOfLies", "Boolean"); - - get_screenhacks (dpy, p); /* Parse the "programs" resource. */ - - { - char *s = get_string_resource (dpy, "selected", "Integer"); - if (!s || !*s) - p->selected_hack = -1; - else - p->selected_hack = get_integer_resource (dpy, "selected", "Integer"); - if (s) free (s); - if (p->selected_hack < 0 || p->selected_hack >= p->screenhacks_count) - p->selected_hack = -1; - } - - { - char *s = get_string_resource (dpy, "mode", "Mode"); - if (s && !strcasecmp (s, "one")) p->mode = ONE_HACK; - else if (s && !strcasecmp (s, "blank")) p->mode = BLANK_ONLY; - else if (s && !strcasecmp (s, "off")) p->mode = DONT_BLANK; - else if (s && !strcasecmp (s, "random-same")) p->mode = RANDOM_HACKS_SAME; - else p->mode = RANDOM_HACKS; - if (s) free (s); - } - - { - char *s = get_string_resource (dpy, "textMode", "TextMode"); - if (s && !strcasecmp (s, "url")) p->tmode = TEXT_URL; - else if (s && !strcasecmp (s, "literal")) p->tmode = TEXT_LITERAL; - else if (s && !strcasecmp (s, "file")) p->tmode = TEXT_FILE; - else if (s && !strcasecmp (s, "program")) p->tmode = TEXT_PROGRAM; - else p->tmode = TEXT_DATE; - if (s) free (s); - } - - if (system_default_screenhack_count) /* note: first_time is also true */ - { - merge_system_screenhacks (dpy, p, system_default_screenhacks, - system_default_screenhack_count); - free_screenhack_list (system_default_screenhacks, - system_default_screenhack_count); - system_default_screenhacks = 0; - system_default_screenhack_count = 0; - } - - if (p->debug_p) - { - p->xsync_p = True; - p->verbose_p = True; - p->timestamp_p = True; - p->initial_delay = 0; - } - - /* Throttle the various timeouts to reasonable values after reading the - disk file. */ - stop_the_insanity (p); -} - - -/* If there are any hacks in the system-wide defaults that are not in - the ~/.xscreensaver file, add the new ones to the end of the list. - This does *not* actually save the file. - */ -static void -merge_system_screenhacks (Display *dpy, saver_preferences *p, - screenhack **system_list, int system_count) -{ - /* Yeah yeah, this is an N^2 operation, but I don't have hashtables handy, - so fuck it. */ - - int made_space = 0; - int i; - for (i = 0; i < system_count; i++) - { - int j; - Bool matched_p = False; - - for (j = 0; j < p->screenhacks_count; j++) - { - char *name; - if (!system_list[i]->name) - system_list[i]->name = make_hack_name (dpy, - system_list[i]->command); - - name = p->screenhacks[j]->name; - if (!name) - name = make_hack_name (dpy, p->screenhacks[j]->command); - - matched_p = !strcasecmp (name, system_list[i]->name); - - if (name != p->screenhacks[j]->name) - free (name); - - if (matched_p) - break; - } - - if (!matched_p) - { - /* We have an entry in the system-wide list that is not in the - user's .xscreensaver file. Add it to the end. - Note that p->screenhacks is a single malloc block, not a - linked list, so we have to realloc it. - */ - screenhack *oh = system_list[i]; - screenhack *nh = (screenhack *) malloc (sizeof(screenhack)); - - if (made_space == 0) - { - made_space = 10; - p->screenhacks = (screenhack **) - realloc (p->screenhacks, - (p->screenhacks_count + made_space + 1) - * sizeof(screenhack)); - if (!p->screenhacks) abort(); - } - - nh->enabled_p = oh->enabled_p; - nh->visual = oh->visual ? strdup(oh->visual) : 0; - nh->name = oh->name ? strdup(oh->name) : 0; - nh->command = oh->command ? strdup(oh->command) : 0; - - p->screenhacks[p->screenhacks_count++] = nh; - p->screenhacks[p->screenhacks_count] = 0; - made_space--; - -#if 0 - fprintf (stderr, "%s: noticed new hack: %s\n", blurb(), - (nh->name ? nh->name : make_hack_name (dpy, nh->command))); -#endif - } - } -} - - - -/* Parsing the programs resource. - */ - -screenhack * -parse_screenhack (const char *line) -{ - screenhack *h = (screenhack *) calloc (1, sizeof(*h)); - const char *s; - - h->enabled_p = True; - - while (isspace(*line)) line++; /* skip whitespace */ - if (*line == '-') /* handle "-" */ - { - h->enabled_p = False; - line++; - while (isspace(*line)) line++; /* skip whitespace */ - } - - s = line; /* handle "visual:" */ - while (*line && *line != ':' && *line != '"' && !isspace(*line)) - line++; - if (*line != ':') - line = s; - else - { - h->visual = (char *) malloc (line-s+1); - strncpy (h->visual, s, line-s); - h->visual[line-s] = 0; - if (*line == ':') line++; /* skip ":" */ - while (isspace(*line)) line++; /* skip whitespace */ - } - - if (*line == '"') /* handle "name" */ - { - line++; - s = line; - while (*line && *line != '"') - line++; - h->name = (char *) malloc (line-s+1); - strncpy (h->name, s, line-s); - h->name[line-s] = 0; - if (*line == '"') line++; /* skip "\"" */ - while (isspace(*line)) line++; /* skip whitespace */ - } - - h->command = format_command (line, False); /* handle command */ - return h; -} - - -static char * -format_command (const char *cmd, Bool wrap_p) -{ - int tab = 30; - int col = tab; - char *cmd2 = (char *) calloc (1, 2 * (strlen (cmd) + 1)); - const char *in = cmd; - char *out = cmd2; - while (*in) - { - /* shrink all whitespace to one space, for the benefit of the "demo" - mode display. We only do this when we can easily tell that the - whitespace is not significant (no shell metachars). - */ - switch (*in) - { - case '\'': case '"': case '`': case '\\': - /* Metachars are scary. Copy the rest of the line unchanged. */ - while (*in) - *out++ = *in++, col++; - break; - - case ' ': case '\t': - /* Squeeze all other whitespace down to one space. */ - while (*in == ' ' || *in == '\t') - in++; - *out++ = ' ', col++; - break; - - default: - /* Copy other chars unchanged. */ - *out++ = *in++, col++; - break; - } - } - - *out = 0; - - /* Strip trailing whitespace */ - while (out > cmd2 && isspace (out[-1])) - *(--out) = 0; - - return cmd2; -} - - -/* Returns a new string describing the shell command. - This may be just the name of the program, capitalized. - It also may be something from the resource database (gotten - by looking for "hacks.XYZ.name", where XYZ is the program.) - */ -char * -make_hack_name (Display *dpy, const char *shell_command) -{ - char *s = strdup (shell_command); - char *s2; - char res_name[255]; - - for (s2 = s; *s2; s2++) /* truncate at first whitespace */ - if (isspace (*s2)) - { - *s2 = 0; - break; - } - - s2 = strrchr (s, '/'); /* if pathname, take last component */ - if (s2) - { - s2 = strdup (s2+1); - free (s); - s = s2; - } - - if (strlen (s) > 50) /* 51 is hereby defined as "unreasonable" */ - s[50] = 0; - - sprintf (res_name, "hacks.%s.name", s); /* resource? */ - s2 = get_string_resource (dpy, res_name, res_name); - if (s2) - { - free (s); - return s2; - } - - for (s2 = s; *s2; s2++) /* if it has any capitals, return it */ - if (*s2 >= 'A' && *s2 <= 'Z') - return s; - - if (s[0] >= 'a' && s[0] <= 'z') /* else cap it */ - s[0] -= 'a'-'A'; - if (s[0] == 'X' && s[1] >= 'a' && s[1] <= 'z') /* (magic leading X) */ - s[1] -= 'a'-'A'; - if (s[0] == 'G' && s[1] == 'l' && - s[2] >= 'a' && s[2] <= 'z') /* (magic leading GL) */ - s[1] -= 'a'-'A', - s[2] -= 'a'-'A'; - return s; -} - - -char * -format_hack (Display *dpy, screenhack *hack, Bool wrap_p) -{ - int tab = 32; - int size; - char *h2, *out, *s; - int col = 0; - - char *def_name = make_hack_name (dpy, hack->command); - - /* Don't ever write out a name for a hack if it's the same as the default. - */ - if (hack->name && !strcmp (hack->name, def_name)) - { - free (hack->name); - hack->name = 0; - } - free (def_name); - - size = (2 * (strlen(hack->command) + - (hack->visual ? strlen(hack->visual) : 0) + - (hack->name ? strlen(hack->name) : 0) + - tab)); - h2 = (char *) malloc (size); - out = h2; - - if (!hack->enabled_p) *out++ = '-'; /* write disabled flag */ - - if (hack->visual && *hack->visual) /* write visual name */ - { - if (hack->enabled_p) *out++ = ' '; - *out++ = ' '; - strcpy (out, hack->visual); - out += strlen (hack->visual); - *out++ = ':'; - *out++ = ' '; - } - - *out = 0; - col = string_columns (h2, strlen (h2), 0); - - if (hack->name && *hack->name) /* write pretty name */ - { - int L = (strlen (hack->name) + 2); - if (L + col < tab) - out = stab_to (out, col, tab - L - 2); - else - *out++ = ' '; - *out++ = '"'; - strcpy (out, hack->name); - out += strlen (hack->name); - *out++ = '"'; - *out = 0; - - col = string_columns (h2, strlen (h2), 0); - if (wrap_p && col >= tab) - out = stab_to (out, col, 77); - else - *out++ = ' '; - - if (out >= h2+size) abort(); - } - - *out = 0; - col = string_columns (h2, strlen (h2), 0); - out = stab_to (out, col, tab); /* indent */ - - if (out >= h2+size) abort(); - s = format_command (hack->command, wrap_p); - strcpy (out, s); - out += strlen (s); - free (s); - *out = 0; - - return h2; -} - - -static void -get_screenhacks (Display *dpy, saver_preferences *p) -{ - int i, j; - int start = 0; - int end = 0; - int size; - char *d; - - d = get_string_resource (dpy, "monoPrograms", "MonoPrograms"); - if (d && !*d) { free(d); d = 0; } - if (!d) - d = get_string_resource (dpy, "colorPrograms", "ColorPrograms"); - if (d && !*d) { free(d); d = 0; } - - if (d) - { - fprintf (stderr, - "%s: the `monoPrograms' and `colorPrograms' resources are obsolete;\n\ - see the manual for details.\n", blurb()); - free(d); - } - - d = get_string_resource (dpy, "programs", "Programs"); - - free_screenhack_list (p->screenhacks, p->screenhacks_count); - p->screenhacks = 0; - p->screenhacks_count = 0; - - if (!d || !*d) - return; - - size = strlen (d); - - - /* Count up the number of newlines (which will be equal to or larger than - one less than the number of hacks.) - */ - for (i = j = 0; d[i]; i++) - if (d[i] == '\n') - j++; - j++; - - p->screenhacks = (screenhack **) calloc (j + 1, sizeof (screenhack *)); - - /* Iterate over the lines in `d' (the string with newlines) - and make new strings to stuff into the `screenhacks' array. - */ - p->screenhacks_count = 0; - while (start < size) - { - /* skip forward over whitespace. */ - while (d[start] == ' ' || d[start] == '\t' || d[start] == '\n') - start++; - - /* skip forward to newline or end of string. */ - end = start; - while (d[end] != 0 && d[end] != '\n') - end++; - - /* null terminate. */ - d[end] = 0; - - p->screenhacks[p->screenhacks_count++] = parse_screenhack (d + start); - if (p->screenhacks_count >= i) - abort(); - - start = end+1; - } - - free (d); - - if (p->screenhacks_count == 0) - { - free (p->screenhacks); - p->screenhacks = 0; - } -} - - -/* Make sure all the values in the preferences struct are sane. - */ -static void -stop_the_insanity (saver_preferences *p) -{ - if (p->passwd_timeout <= 0) p->passwd_timeout = 30000; /* 30 secs */ - if (p->timeout < 15000) p->timeout = 15000; /* 15 secs */ - if (p->cycle != 0 && p->cycle < 2000) p->cycle = 2000; /* 2 secs */ - if (p->pointer_timeout <= 0) p->pointer_timeout = 5000; /* 5 secs */ - if (p->notice_events_timeout <= 0) - p->notice_events_timeout = 10000; /* 10 secs */ - if (p->fade_seconds <= 0 || p->fade_ticks <= 0) - p->fade_p = False; - if (! p->fade_p) p->unfade_p = False; - - /* The DPMS settings may have the value 0. - But if they are negative, or are a range less than 10 seconds, - reset them to sensible defaults. (Since that must be a mistake.) - */ - if (p->dpms_standby != 0 && - p->dpms_standby < 10 * 1000) - p->dpms_standby = 2 * 60 * 60 * 1000; /* 2 hours */ - if (p->dpms_suspend != 0 && - p->dpms_suspend < 10 * 1000) - p->dpms_suspend = 2 * 60 * 60 * 1000; /* 2 hours */ - if (p->dpms_off != 0 && - p->dpms_off < 10 * 1000) - p->dpms_off = 4 * 60 * 60 * 1000; /* 4 hours */ - - /* suspend may not be greater than off, unless off is 0. - standby may not be greater than suspend, unless suspend is 0. - */ - if (p->dpms_off != 0 && - p->dpms_suspend > p->dpms_off) - p->dpms_suspend = p->dpms_off; - if (p->dpms_suspend != 0 && - p->dpms_standby > p->dpms_suspend) - p->dpms_standby = p->dpms_suspend; - - /* These fixes above ignores the case - suspend = 0 and standby > off ... - */ - if (p->dpms_off != 0 && - p->dpms_standby > p->dpms_off) - p->dpms_standby = p->dpms_off; - - - if (p->dpms_standby == 0 && /* if *all* are 0, then DPMS is disabled */ - p->dpms_suspend == 0 && - p->dpms_off == 0 && - !(p->dpms_quickoff_p) /* ... but we want to do DPMS quick off */ - ) - p->dpms_enabled_p = False; - - - /* Set watchdog timeout to about half of the cycle timeout, but - don't let it be faster than 1/2 minute or slower than 1 minute. - */ - p->watchdog_timeout = p->cycle * 0.6; - if (p->watchdog_timeout < 27000) p->watchdog_timeout = 27000; /* 27 secs */ - if (p->watchdog_timeout > 57000) p->watchdog_timeout = 57000; /* 57 secs */ - - if (p->pointer_hysteresis < 0) p->pointer_hysteresis = 0; -/* if (p->pointer_hysteresis > 100) p->pointer_hysteresis = 100; */ - - if (p->auth_warning_slack < 0) p->auth_warning_slack = 0; - if (p->auth_warning_slack > 300) p->auth_warning_slack = 300; -} - - -Bool -senesculent_p (void) -{ - /* If you are in here because you're planning on disabling this warning - before redistributing my software, please don't. - - I sincerely request that you do one of the following: - - 1: leave this code intact and this warning in place, -OR- - - 2: Remove xscreensaver from your distribution. - - I would seriously prefer that you not distribute my software at all - than that you distribute one version and then never update it for - years. - - I am *constantly* getting email from users reporting bugs that have - been fixed for literally years who have no idea that the software - they are running is years out of date. Yes, it would be great if we - lived in the ideal world where people checked that they were running - the latest release before they report a bug, but we don't. To most - people, "running the latest release" is synonymous with "running the - latest release that my distro packages for me." - - When they even bother to tell me what version they're running, I - say, "That version is three years old!", and they say "But this is - the latest version my distro ships". Then I say, "your distro - sucks", and they say "but I don't know how to compile from source, - herp derp I eat paste", and *everybody* goes away unhappy. - - It wastes an enormous amount of my time, but worse than that, it - does a grave disservice to the users, who are stuck experiencing - bugs that are already fixed! These users think they are running the - latest release, and they are not. They would like to be running the - actual latest release, but they don't know how, because their distro - makes that very difficult for them. It's terrible for everyone, and - kind of makes me regret ever having released this software in the - first place. - - So seriously. I ask that if you're planning on disabling this - obsolescence warning, that you instead just remove xscreensaver from - your distro entirely. Everybody will be happier that way. Check - out gnome-screensaver instead, I understand it's really nice. - - Of course, my license allows you to ignore me and do whatever the - fuck you want, but as the author, I hope you will have the common - courtesy of complying with my request. - - Thank you! - - jwz, 2014, 2016, 2018. - - PS: In particular, since Debian refuses to upgrade software on any - kind of rational timeline, I have asked that they stop shipping - xscreensaver at all. They have refused. Instead of upgrading the - software, they simply patched out this warning. - - If you want to witness the sad state of the open source peanut - gallery, look no farther than the comments on my blog: - http://jwz.org/b/yiYo - - Many of these people fall back on their go-to argument of, "If it is - legal, it must be right." If you believe in that rhetorical device - then you are a terrible person, and possibly a sociopath. - - There are also the armchair lawyers who say "Well, instead of - *asking* people to do the right thing out of common courtesy, you - should just change your license to prohibit them from acting - amorally." Again, this is the answer of a sociopath, but that aside, - if you devote even a second's thought to this you will realize that - the end result of this would be for distros like Debian to just keep - shipping the last version with the old license and then never - upgrading it again -- which would be the worst possible outcome for - everyone involved, most especially the users. - */ - time_t now = time ((time_t *) 0); /* d */ - struct tm *tm = localtime (&now); /* o */ - const char *s = screensaver_id; /* n */ - char mon[4], year[5]; /* ' */ - int m, y, mrnths; /* t */ - s = strchr (s, ' '); if (!s) abort(); s++; /* */ - s = strchr (s, '('); if (!s) abort(); s++; /* d */ - s = strchr (s, '-'); if (!s) abort(); s++; /* o */ - strncpy (mon, s, 3); /* o */ - mon[3] = 0; /* */ - s = strchr (s, '-'); if (!s) abort(); s++; /* e */ - strncpy (year, s, 4); /* e */ - year[4] = 0; /* t */ - y = atoi (year); /* , */ - if (!strcmp(mon, "Jan")) m = 0; /* */ - else if (!strcmp(mon, "Feb")) m = 1; /* s */ - else if (!strcmp(mon, "Mar")) m = 2; /* t */ - else if (!strcmp(mon, "Apr")) m = 3; /* o */ - else if (!strcmp(mon, "May")) m = 4; /* p */ - else if (!strcmp(mon, "Jun")) m = 5; /* , */ - else if (!strcmp(mon, "Jul")) m = 6; /* */ - else if (!strcmp(mon, "Aug")) m = 7; /* s */ - else if (!strcmp(mon, "Sep")) m = 8; /* t */ - else if (!strcmp(mon, "Oct")) m = 9; /* a */ - else if (!strcmp(mon, "Nov")) m = 10; /* a */ - else if (!strcmp(mon, "Dec")) m = 11; /* a */ - else abort(); /* h */ - mrnths = ((((tm->tm_year + 1900) * 12) + tm->tm_mon) - /* h */ - (y * 12 + m)); /* h */ - /* p */ - return (mrnths >= 34); /* . */ + FAIL: + if (buf) free (buf); + return -1; } -- cgit v1.2.3-55-g7522