summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrej Shadura <andrewsh@debian.org>2018-09-05 13:03:24 +0200
committerAndrej Shadura <andrewsh@debian.org>2018-09-05 13:03:24 +0200
commitbfb566956fd7db8a050401247396528545107d0d (patch)
tree4f0f44e9ba36daca697ab54ff7416d667f7fbe8e
Import Upstream version 0.4.1
-rw-r--r--ChangeLog103
-rw-r--r--Makefile38
-rw-r--r--README107
-rw-r--r--brightd.1.tpl100
-rw-r--r--brightd.c806
-rw-r--r--gpl.txt339
6 files changed, 1493 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..72b15d8
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,103 @@
+* brightd-0.4.1 (18. Oct 2008)
+
+18. Oct 2008; Phillip Berndt brightd.{1,x11_no_x11} Makefile
+ Merged manpages into one (using groff conditions)
+ /sbin | /bin optional in Makefile
+
+18. Oct 2008; Hannes von Haugwitz brightd.{c,1.x11,1.no_x11} Makefile:
+ Fixed bug with pidfile creation in daemon mode
+ Added different manpages for x11 and no x11 mode
+ Some additional changes in Makefile
+
+* brightd-0.4 (17. Oct 2008)
+
+17. Oct 2008; Hannes von Haugwitz brightd.{c,1} Makefile:
+ Added `-P' for PID-file creation
+ X11 support is optional from now on (but enabled by default in Makefile)
+ Some minor fixes
+
+17. Sep 2007; Richard Weinberger brightd.c:
+ Removed useless argc == 0 block
+
+* brightd-0.4_beta4 (21. Jul 2007)
+
+21. Jul 2007; Phillip Berndt brightd.c brightd.1:
+ -e does not need to contain event anymore, since
+ some people do not have event files
+
+09. Jul 2007; Phillip Berndt brightd.c brightd.1:
+ Brightness file is only opened once now
+
+* brightd-0.3_beta2 (08. July 2007)
+
+08. Jul 2007; Phillip Berndt brightd.c:
+ Modified tge way -f works, can be used twice now
+
+08. Jul 2007; Phillip Berndt brightd.c brightd.1:
+ event sources may now be filtered to prevent brightd from using undesired
+ sources such as hdaps (reported by
+ Hannes von Haugwitz <hannes@vonhaugwitz.com>)
+ Also brightd will now attempt to connect to an open X-server
+ before waiting for one to appear
+
+* brightd-0.4_beta2 (07. July 2007)
+
+07. Jul 2007; Phillip Berndt brightd.c:
+ Fading must not be that fast as the kernel's backend seems
+ to be too slow
+
+* brightd-0.4_beta1 (06. July 2007)
+
+06. July 2007; Phillip Berndt brightd.c:
+ Rewrote nearly the entire code to implement the
+ new exterimental stuff. This code should raise
+ nearly no cpu wakeups anymore
+
+ Since this is a big change, I'll release this
+ as 0.4_beta1 and skip 0.3.
+
+05. July 2007; Phillip Berndt brightd.c:
+ Switched to an experimental branch:
+ The code will now use /dev/input/event* to
+ check for user activity
+
+05. May 2007; Phillip Berndt brightd.c:
+ Added a -x parameter which will cause brightd
+ to wait for an X11-session to be opened if it
+ does not find one.
+
+29. Apr 2007; Phillip Berndt brightd.c:
+ Fixed some typos
+
+28. Apr 2007; Phillip Berndt brightd.c:
+ Fixed a minor bug which produced a warning when
+ compiling with -Wall
+
+28. Apr 2008; Phillip Berndt Makefile:
+ brightd will now be built with debugging information
+ by default and will use any $CFLAGS specified in the
+ environment
+
+*brightd-0.2 (26. Apr 2007)
+
+26. Apr 2007; Phillip Berndt brightd.c:
+ The default class is no longer "ibm" but the first
+ directory entry in the backlight directory
+ Since 2.6.22 will rename the "ibm" class, I'll
+ release this as 0.2 now.
+
+26. Apr 2007; Phillip Berndt brightd.1:
+ Replaced 1000 µs with 1 ms to prevent encoding
+ problems on non-unicode systems
+
+*brightd-0.1 (15. Apr 2007)
+
+15. Apr 2007; Phillip Berndt brightd.c:
+ brightd does use the sys-Interface now.
+ (Thanks to Evgeni Golov <sargentd at die-welt dot net> for reporting)
+ Added a manpage
+
+26 Feb 2007; Phillip Berndt brightd.c:
+ Fixed a typo
+ Added #include <string.h> to remove a warning
+ (Thanks to Thomas Ohms for reporting.)
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..8386862
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,38 @@
+PREFIX=$(DESTDIR)/usr
+BINDIR=bin/
+#NO_X11=1 # (Uncomment this to disable X11 Support)
+
+PACKAGE_VERSION=`awk '/RELEASE/ {print $$3}' brightd.c | tr -d \" | head -n1`
+
+CFLAGS=-g -Wall -pedantic
+MAN_NO_X11=1
+ifndef NO_X11
+MAN_NO_X11=0
+A_CFLAGS=-lX11 -lXss -DX11
+endif
+
+all: brightd brightd.1
+
+brightd: brightd.c
+ gcc $(CFLAGS) $(A_CFLAGS) -o $@ $@.c
+
+brightd.1:
+ sed -re 's/^\.nr no_x11 [01]/.nr no_x11 $(MAN_NO_X11)/' brightd.1.tpl > brightd.1
+
+install:
+ install -Ds brightd $(PREFIX)/$(BINDIR)/brightd
+ install -D brightd.1 $(PREFIX)/share/man/man1/brightd.1
+
+uninstall:
+ rm $(PREFIX)/$(BINDIR)/brightd
+ rm $(PREFIX)/share/man/man1/brightd.1
+
+clean:
+ rm -f brightd brightd.1
+
+# Source tarball generation
+source:
+ mkdir brightd-$(PACKAGE_VERSION)/
+ cp brightd.{1.tpl,c} ChangeLog gpl.txt Makefile README brightd-$(PACKAGE_VERSION)/
+ tar cjf brightd-$(PACKAGE_VERSION).tar.bz2 brightd-$(PACKAGE_VERSION)/
+ rm -rf brightd-$(PACKAGE_VERSION)/
diff --git a/README b/README
new file mode 100644
index 0000000..d5d0460
--- /dev/null
+++ b/README
@@ -0,0 +1,107 @@
+BRIGHTNESS CONTROL DAEMON
+----------------------------------------------------------------
+
+CHANGES IN 0.4
+ Brightd 0.4 introduces some major changes, so I'll write some
+ information on the new system here.
+
+ d-tick <jid:d-tick@jabber.zankt.net> noticed that the old code
+ caused a huge number of CPU wakeups per second. While this makes
+ the fading and reaction look quite cool, it's something quite#
+ underisable for battery live time.
+
+ Starting with this version of brightd the program calculates idle
+ times based on input on /dev/input/event* using select(2) and
+ alarm(2). xscreensaver times are honored furthermore, but not
+ pulled every few ms. Also, the brightness setting doesn't get
+ pulled anymore, which means you'll have to tell your acpid script
+ to notify brightd of any changes to the brightness. To achieve
+ this, brightd creates a FIFO into which you may echo the new
+ brightness setting.
+
+ In my case (Thinkpad R51) the lines I had to put into
+ /etc/acpi/default.sh were
+
+ if [ "${ACTION}" == "brightness" ]; then
+ echo -n "0$[${PARAMETER} / 14]" > /var/tmp/.brightd
+ fi
+
+ (acpid reported the brightness in a range between 0 and 100 while
+ brightd expects to get the levels from sysfs, who are between 0 and
+ 7)
+
+ Also note that you'll have to start brightd as root now, because
+ other users don't have read permission on /dev/input/event*.
+ Brightd will wait for X11 per default now, but you may deactivate
+ the whole X11 interaction using -x now.
+
+ "But don't you worry" - it will drop it's privileges as soon as it
+ has opened all necessary files. If you drop privileges to a user
+ also having read access to /dev/input, brightd will automatically
+ open new files in that directory upon creation (pe when you attach
+ an USB mouse)
+
+PREREQUISITES
+ A recent kernel with an extension providing access to your LCD's
+ brightness controls through /sys/class/backlight.
+ The kernel must have CONFIG_INPUT_EVDEV enabled (which is default)
+
+ For example, IBM thinkpad owners should have CONFIG_IBM_ACPI set.
+
+ Additionally, users should have write permissions:
+ chmod g+w /sys/class/backlight/*/brightness
+ chgrp users /sys/class/backlight/*/brightness
+ You might have to put this in your init.d or so
+
+COMPILING
+ If compiled with x11 support brightd needs X11 and the
+ X11 screensaver extensions (libXss) installed.
+
+ Simply change into the source directory and type "make" to
+ compile it. The output executable will be called "brightd".
+
+INSTALLATION
+ Copy brightd to some directory inside your $PATH (like
+ /usr/local/bin). Put it into an init script and enjoy.
+
+USAGE
+ See the manpage.
+
+Q&A
+
+ BRIGHTD STARTS, BUT DOES NOT WORK
+ brightd will not work in three situations. If you intend to test
+ it, avoid those:
+ - brightd won't do anything when xscreensaver is
+ deaktivated. (This prevents the screen to go dark when
+ you're watching a movie)
+ - It won't do anything when AC is plugged in.
+ - It won't do anything either when the highest brightness
+ level is chosen.
+ Use "-f" to override the latter two.
+
+ BRIGHTD STARTS, BUT DOES NOT CONNECT TO X11
+ Make sure your auth settings allow clients started on the same
+ machine by root to connect to X11. For gdm users, starting brightd
+ with
+ XAUTHORITY="/var/gdm/:0.Xauth" brightd ...
+ might help.
+
+ MY SYNAPTICS TOUCHPAD ISN'T RECOGNIZED
+ Sadly, synaptics does not create a device in /dev/input; if you
+ want to have events from your touchpad considered, use brightd < 0.3.
+
+LICENSE
+ GPL, of course. See gpl.txt
+
+AUTHOR
+ Phillip Berndt
+ www.pberndt.com
+
+ Please excuse any language mistakes. I'm no native english
+ speaker ;)
+
+CONTRIBUTORS
+ Richard Weinberger <richard at nod dot at>
+ Hannes von Haugwitz <hannes at vonhaugwitz dot com>
+
diff --git a/brightd.1.tpl b/brightd.1.tpl
new file mode 100644
index 0000000..9101f86
--- /dev/null
+++ b/brightd.1.tpl
@@ -0,0 +1,100 @@
+.\" brightd manpage
+.\" vim:fileencoding=latin-1
+.nr no_x11 0
+.nr version_maj 0
+.nr version_min 4
+.nr version_sub 1
+
+.TH brightd 1 "18 October 2008" "\n[version_maj].\n[version_min].\n[version_sub]" "brightd manual"
+.SH NAME
+brightd \- a brightness control daemon
+.SH SYNOPSIS
+
+.ie (\n[no_x11] == 0) \{
+.B brightd [-v] [-d] [-P <file>] [-u n] [-e n] [-w n] [-b s] [-f] [-c n] [-x] [-r n]
+.\}
+.el \{
+.B brightd [-v] [-d] [-P <file>] [-u n] [-e n] [-w n] [-b s] [-f] [-c n] [-r n]
+.\}
+
+.SH DESCRIPTION
+.I brightd
+is a daemon which dynamically reduces LCD brightness when you don't use your pc. The idea is adapted from iBooks.
+.SH OPTIONS
+.TP
+-v
+Output some debugging information. Will not work
+in daemon mode.
+.TP
+-d
+Will cause brightd to fork itself into background.
+You'll want to use this ;)
+.TP
+-P <file>
+Set location of pid file in daemon mode (Default is /var/run/brightd.pid).
+.TP
+-u n
+brightd will drop privileges after opening all file descriptors. With this
+setting you may choose which user to change to.
+
+You
+.B have
+.ie (\n[no_x11] == 0) \{\
+to start brightd as root; or at least as a user which might as well access
+X11-Sessions and
+.\}
+.el \{\
+to start brightd as root; or at least as a user which might access
+.\}
+.I /dev/input/event
+.TP
+-e n
+Filter used event sources by POSIX extended regexp n (for example, use
+"i8042.+event" on intel platforms to avoid having HDAPS taken into account)
+You should include "event" here, but you must not do so.
+.TP
+-w n
+The amount of seconds of inactivity to wait before
+reducing brightness
+.TP
+-b n
+Dark screen brightness
+Never reduce brightness below that value.
+Note that you won't be able to change brightness
+manually below this value as well.
+.TP
+-f
+Reduce brightness even if on the highest brightness
+level.
+By default, brightd won't do this. That way you can
+temporally disable it while reading through a text or
+so.
+If you specify this option twice, brightd will also
+reduce brightness when you're on AC.
+.TP
+-c s
+Set the backlight class to use. You may specify any subdirectoy of
+.I /sys/class/backlight
+.if (\n[no_x11] == 0) \{ .TP
+-x
+Don't query X11 for inactivity / deactivated screensavers
+.\}
+.TP
+-r n
+brightd will create a FIFO n (deleting the file if it existed before!) and read
+from it. If you tell your acpid to write brightness levels to that FIFO when
+the user changes brightness, brightd can help you with some stuff: For example,
+if brightd faded to brightness 0 and you increase brightness, brightd would
+automatically fade up to the highest level.
+
+.SH FILES
+.P
+.I /usr/bin/brightd
+.I /sys/class/backlight/*/*
+
+.SH AUTHORS
+.nf
+Phillip Berndt (mail at pberndt dot com)
+Richard Weinberger (richard at nod dot at)
+Hannes von Haugwitz (hannes at vonhaugwitz dot com)
+.fi
diff --git a/brightd.c b/brightd.c
new file mode 100644
index 0000000..244dd60
--- /dev/null
+++ b/brightd.c
@@ -0,0 +1,806 @@
+/**
+ * Brightness control daemon
+ * Copyright (c) 2006-2008, Phillip Berndt
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Compile using:
+ * gcc -lX11 -lXss -DX11 brightd.c or
+ * gcc brightd.c or
+ * use make
+ *
+ */
+#define RELEASE "0.4.1"
+/* #define DEBUG */
+/* #define X11 */
+
+/* Includes {{{ */
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#ifdef X11
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/extensions/scrnsaver.h>
+#endif
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <glob.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/select.h>
+#include <pthread.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <time.h>
+#include <regex.h>
+#include <sys/inotify.h>
+/* }}} */
+
+/* Overall program settings {{{ */
+#ifdef DEBUG
+ char verbose = 1;
+#else
+ char verbose = 0;
+#endif
+char daemonize = 0;
+char force = 0;
+int waitSeconds = 3;
+int darkBright = 0;
+int maxBright = 0;
+
+char isDark = 0;
+char savedLevel = 0;
+char beforeFade = 0;
+
+char pidfile[255];
+
+time_t lastFade = 0;
+
+char b_class[21];
+char actualBrightnessFile[255];
+char brightnessFile[255];
+
+char b_fifo[255];
+int bfifoFd = 0;
+
+FILE *brightnessFd;
+
+regex_t eventSourceFilter;
+
+#ifdef X11
+Display *display = NULL;
+#endif
+
+/* Required prototypes */
+void signalHandlerAlarm(int sig);
+/* }}} */
+
+
+/*
+ * Write an error to stderr and exit
+ */
+void error(char *str) { /* {{{ */
+ if(daemonize != 1) {
+ fputs(str, stderr);
+ fputs("\n", stderr);
+
+ #ifdef DEBUG
+ #include <errno.h>
+ printf("libc says: %s\n", strerror(errno));
+ #endif
+ }
+
+ #ifdef X11
+ /* Close display */
+ if(display) {
+ XCloseDisplay(display);
+ }
+ #endif
+
+ /* Quit */
+ exit(1);
+} /* }}} */
+
+/*
+ * Write an debug message to the console
+ */
+inline void info(char *str) { /*{{{*/
+ if(verbose == 1 && daemonize == 0) {
+ printf("%s\n", str);
+ }
+} /*}}}*/
+
+/*
+ * Function to get the brightness of the pc
+ */
+int getBrightness() { /*{{{*/
+ char line[255];
+ int retVal;
+ FILE *brightness = fopen(actualBrightnessFile, "r");
+ if(!brightness) {
+ error("Failed to open /sys/class/backlight/*/actual_brightness. Do you have the "
+ "ACPI extensions for the class supplied using -c in your kernel?");
+ }
+ fgets(line, 255, brightness);
+ retVal = atoi(line);
+ fclose(brightness);
+
+ return retVal;
+} /*}}}*/
+
+/*
+ * Function to set the brightness of the
+ * display
+ *
+ * Must be done stepwise!
+ */
+void setBrightness(int level) { /*{{{*/
+ char output[255];
+ int i, plevel;
+ int saved;
+
+ saved = alarm(0);
+ signal(SIGALRM, SIG_IGN);
+ lastFade = time(NULL);
+ plevel = getBrightness();
+ for(i=plevel; ; i += (plevel<level ? 1 : -1)) {
+ sprintf(output, "%i\n", i);
+ if(fputs(output, brightnessFd) == EOF) {
+ error("Failed to update brightness.");
+ }
+ fflush(brightnessFd);
+
+ if(i == level) {
+ break;
+ }
+
+ /* We had to disable signal handler and alarm because of this: */
+ usleep(200);
+ }
+ signal(SIGALRM, signalHandlerAlarm);
+ alarm(saved);
+} /*}}}*/
+
+/*
+ * Check whether the PC is on AC
+ */
+int isOnAC() /*{{{*/
+{
+ char line[255];
+ FILE *ac = fopen("/proc/acpi/ac_adapter/AC/state", "r");
+ if(!ac) {
+ /* Ignore this */
+ return 0;
+ }
+ fgets(line, 255, ac);
+ fclose(ac);
+
+ return strstr(line, "on-line") != NULL;
+} /*}}}*/
+
+/*
+ * Signal handler; just quit
+ */
+void signalHandlerQuit(int signal) { /*{{{*/
+ #ifdef X11
+ if(display != NULL) {
+ info("Closing display");
+ XCloseDisplay(display);
+ }
+ #endif
+ if(bfifoFd != 0) {
+ /* This may or may not work */
+ close(bfifoFd);
+ if(unlink(b_fifo) != 0) {
+ info("Failed to remove FIFO - this does only work when you didn't drop privileges");
+ }
+ }
+ error("Received signal. Exiting...");
+} /*}}}*/
+
+#ifdef X11
+/*
+ * Get IDLE time
+ * Taken from GAJIM source, src/common/idle.c
+ *
+ * Modified to return -1 when the screen saver is deactivated
+ */
+int getIdleTime() { /*{{{*/
+ static XScreenSaverInfo *mit_info = NULL;
+ int idle_time, event_base, error_base;
+
+ if (XScreenSaverQueryExtension(display, &event_base, &error_base)) {
+ if (mit_info == NULL) {
+ mit_info = XScreenSaverAllocInfo();
+ }
+ XScreenSaverQueryInfo(display, RootWindow(display, 0), mit_info);
+
+ if(mit_info->state == 3) { /* ScreenSaverDisabled */
+ idle_time = -1;
+ }
+ else {
+ idle_time = (mit_info->idle) / 1000;
+ }
+ }
+ else {
+ idle_time = 0;
+ }
+ return idle_time;
+} /*}}}*/
+#endif
+
+/*
+ * Print a help message and exit
+ */
+void printHelp() /*{{{*/
+{
+ #ifdef X11
+ printf("brightd %s\nA X11-daemon for iBook-like brightness management\nCopyright (c) 2006-2008, Phillip Berndt\n\nOptions:\n", RELEASE);
+ #else
+ printf("brightd %s\nA daemon for iBook-like brightness management\nCopyright (c) 2006-2008, Phillip Berndt\n\nOptions:\n", RELEASE);
+ #endif
+ printf(" -v Be verbose\n");
+ printf(" -d Daemonize\n");
+ printf(" -P <file> Create pid file\n");
+ printf(" -u n Drop privileges to this user (Defaults to nobody)\n");
+ printf(" -w n Wait n seconds before reducing brightness (Defaults to 3)\n");
+ printf(" -b n The brightness setting for the dark screen (Defaults zu 0)\n");
+ printf(" -f Reduce brightness even if on the highest brightness level\n");
+ printf(" Specify twice to also do so when on AC\n");
+ printf(" -e n Filter event sources using regexp n (on /dev/input/by-path\n");
+ printf(" -c n Set the backlight class to use (defaults to the first\n");
+ printf(" subnode of /sys/class/backlight)\n");
+ #ifdef X11
+ printf(" -x Don't query X11 Xss extension\n");
+ #endif
+ printf(" -r n Create a FIFO, into which acpid may write the new level when the user\n");
+ printf(" changed display brightness\n");
+ printf("\n");
+ exit(0);
+} /*}}}*/
+
+/*
+ * Load default brightness class into b_class
+ */
+void loadDefaultClass() /*{{{*/
+{
+ struct dirent *dirEntry;
+ DIR *backlightDir = opendir("/sys/class/backlight");
+ if(backlightDir) {
+ while(1) {
+ dirEntry = readdir(backlightDir);
+ if(!dirEntry) {
+ break;
+ }
+ if(dirEntry->d_name[0] == '.') {
+ continue;
+ }
+ strcpy(b_class, dirEntry->d_name);
+ if(verbose == 1) {
+ printf("Using brightness class %s\n", b_class);
+ }
+ closedir(backlightDir);
+ return;
+ }
+ closedir(backlightDir);
+ }
+ strcpy(b_class, "none");
+} /*}}}*/
+
+/*
+ * Event source filter
+ */
+inline char isEventFileValid(char *file) { /* {{{ */
+ if(*((char*)&eventSourceFilter) == 0) {
+ return 1;
+ }
+ else {
+ return regexec(&eventSourceFilter, file, 0, NULL, 0) == 0;
+ }
+} /* }}} */
+
+/**
+ * Application logic code {{{
+ */
+void signalHandlerAlarm(int sig) { /*{{{*/
+ /* Reenable the handler */
+ signal(sig, signalHandlerAlarm);
+
+ if(isDark == 0) {
+ /* Check if fading is okay */
+ if(isOnAC() && force < 2) {
+ info("Would fade, but on AC");
+ alarm(waitSeconds);
+ return;
+ }
+ if(getBrightness() == maxBright && force < 1) {
+ info("Would fade, but maximum brightness level selected");
+ alarm(waitSeconds);
+ return;
+ }
+ #ifdef X11
+ if(display != NULL && getIdleTime() < waitSeconds) {
+ info("Would fade, but screensaver denies to do so");
+ alarm(waitSeconds);
+ return;
+ }
+ #endif
+
+ /* Fade */
+ info("Fading to dark");
+ beforeFade = getBrightness();
+ savedLevel = darkBright;
+ setBrightness(darkBright);
+ isDark = 1;
+ }
+ return;
+} /*}}}*/
+
+void handleReceivedEvent() { /*{{{*/
+ int level;
+
+ /* Reset alarm */
+ alarm(waitSeconds);
+
+ /* Fade back to light */
+ if(isDark == 1) {
+ level = getBrightness();
+ if(level > beforeFade) {
+ savedLevel = level;
+ isDark = 0;
+ return;
+ }
+ if(verbose == 1 && daemonize == 0) {
+ printf("Fading to light (level %d)\n", beforeFade);
+ }
+ savedLevel = beforeFade;
+ setBrightness(beforeFade);
+ isDark = 0;
+ }
+} /*}}}*/
+
+void userChangedBrightness(int toLevel) { /*{{{*/
+ if(verbose == 1 && daemonize == 0) {
+ printf("User changed brightness level to %d\n", toLevel);
+ }
+
+ /* Reset alarm */
+ alarm(waitSeconds);
+
+ if(isDark == 1 && toLevel > darkBright) {
+ /* Fade to max immediately */
+ info("Maximum lightness, because user increased brightness");
+ setBrightness(maxBright);
+ savedLevel = maxBright;
+ isDark = 0;
+ }
+ if(toLevel < darkBright) {
+ /* Deny this */
+ info("Sorry, you can't lower brightness below darkBright");
+ setBrightness(darkBright);
+ savedLevel = darkBright;
+ }
+ savedLevel = toLevel;
+} /*}}}*/
+
+/* }}} */
+
+/*
+ * Make pid file.
+ */
+void make_pidfile(char *pidfile) {
+ FILE *fpidfile;
+ if (pidfile && (fpidfile = fopen(pidfile, "w"))) {
+ fprintf(fpidfile, "%d\n", getpid());
+ fclose(fpidfile);
+ }
+}
+
+/*
+ * The main program
+ */
+int main(int argc, char *argv[]) { /*{{{*/
+ int defaultBrightness = 0;
+ int oldBrightness = 0;
+ int newBrightness = 0;
+ int highFd = 0;
+ #ifdef X11
+ int noXCode = 0;
+ int inotifyFdX11;
+ #endif
+ int eventReceived;
+ int inotifyFdEvents;
+ int i;
+ int fd;
+ int filesCount;
+ char option;
+ char user[25];
+ char buf[255];
+ char buf2[255];
+ struct passwd *userStruct;
+ glob_t *events;
+ fd_set rfds;
+ fd_set openfds;
+ struct inotify_event *inotifyEvent;
+
+ #ifdef DEBUG
+ printf("DEBUG BUILD\n");
+ #endif
+
+ /* Load settings {{{ */
+ strcpy(user, "nobody");
+ *pidfile = 0;
+
+ loadDefaultClass();
+ opterr = 0;
+
+ regcomp(&eventSourceFilter, ".*event.*", REG_EXTENDED | REG_NOSUB);
+ #ifdef X11
+ while((option = getopt(argc, argv, "vdfxe:w:P:b:c:r:u:")) > 0) {
+ #else
+ while((option = getopt(argc, argv, "vdfe:w:P:b:c:r:u:")) > 0) {
+ #endif
+ switch(option) {
+ case 'v': /* Verbose */
+ verbose = 1;
+ break;
+ case 'w': /* Wait n seconds before fading */
+ waitSeconds = atoi(optarg);
+ if(waitSeconds <= 0) {
+ printHelp();
+ }
+ break;
+ case 'd': /* Daemonize */
+ daemonize = 1;
+ break;
+ case 'P': /* Location of pid file */
+ if(strlen(optarg) > 250) {
+ error("The filename should not be longer than 250 characters.");
+ }
+ strcpy(pidfile, optarg);
+ break;
+ case 'e': /* Event source filter */
+ /* Compile regex */
+ i = regcomp(&eventSourceFilter, optarg, REG_EXTENDED | REG_NOSUB);
+ if(i != 0) {
+ regerror(i, &eventSourceFilter, buf, 255);
+ printf("Error: %s\n", buf);
+ error("Regex compilation failed");
+ }
+ break;
+ case 'b': /* Darkest setting */
+ darkBright = atoi(optarg);
+ if(darkBright < 0 || darkBright > 5) {
+ printHelp();
+ }
+ break;
+ case 'f': /* Force fading */
+ force++;
+ break;
+ case 'u': /* User */
+ if(strlen(optarg) > 20) {
+ error("The user name should not be longer than 20 characters.");
+ }
+ strcpy(user, optarg);
+ break;
+ case 'c': /* Brightness class */
+ if(strlen(optarg) > 20) {
+ error("The class should not be longer than 20 characters.");
+ }
+ strcpy(b_class, optarg);
+ break;
+ #ifdef X11
+ case 'x': /* Deactivate X-Code */
+ noXCode = 1;
+ break;
+ #endif
+ case 'r': /* Brightness FIFO */
+ if(strlen(optarg) > 250) {
+ error("The filename should not be longer than 250 characters.");
+ }
+ strcpy(b_fifo, optarg);
+ bfifoFd = 1;
+ break;
+ default:
+ printHelp();
+ }
+ }
+
+
+ /* }}} */
+
+ /* Load some sysfs and default settings stuff {{{ */
+ /* Get the user ID */
+ userStruct = getpwnam(user);
+ if(userStruct == NULL) {
+ error("Failed to get the UID for the specified user");
+ }
+
+ /* Set files in sysfs to use */
+ sprintf(brightnessFile, "/sys/class/backlight/%s/brightness", b_class);
+ brightnessFd = fopen(brightnessFile, "w");
+ if(!brightnessFd) {
+ printf("Failed to open %s for writing.\n", brightnessFile);
+ error( "- Do you have the correct ACPI extensions in your kernel?\n"
+ "- Do you have permissions to write to that file?");
+ }
+
+ /* Load maximum brightness; abuse some not yet initialised variables to do so ;) */
+ sprintf(actualBrightnessFile, "/sys/class/backlight/%s/max_brightness", b_class);
+ maxBright = getBrightness();
+ if(verbose == 1 && daemonize == 0) {
+ printf("Maximum brightness is %d\n", maxBright);
+ }
+ sprintf(actualBrightnessFile, "/sys/class/backlight/%s/actual_brightness", b_class);
+
+ /* Load brightness */
+ defaultBrightness = newBrightness = oldBrightness = getBrightness();
+
+ /* Open all event files */
+ FD_ZERO(&openfds);
+ events = (glob_t *)malloc(sizeof(glob_t));
+ if(glob("/dev/input/by-path/*", 0, NULL, events) != 0) {
+ printf("Failed to list event devices in /dev/input/by-path/\n");
+ exit(1);
+ }
+ filesCount = events->gl_pathc;
+ for(i=0; i<filesCount; i++) {
+ if(!isEventFileValid(events->gl_pathv[i])) {
+ continue;
+ }
+ fd = open(events->gl_pathv[i], O_RDONLY | O_NONBLOCK);
+ #ifdef DEBUG
+ printf("%d: %s\n", fd, events->gl_pathv[i]);
+ #endif
+
+ if(fd == -1) {
+ printf("Failed to open %s\n", events->gl_pathv[i]);
+ error("You have to be root to run this");
+ }
+ if(fd > highFd) {
+ highFd = fd;
+ }
+ FD_SET(fd, &openfds);
+ }
+ globfree(events);
+
+ /* Create inotify mapping for that directory */
+ inotifyFdEvents = inotify_init();
+ if(inotifyFdEvents != -1) {
+ if(inotify_add_watch(inotifyFdEvents, "/dev/input/by-path/", IN_CREATE) == -1) {
+ close(inotifyFdEvents);
+ inotifyFdEvents = -1;
+ }
+ if(inotifyFdEvents > highFd) {
+ highFd = inotifyFdEvents;
+ }
+ }
+
+ /* Open FIFO */
+ if(bfifoFd == 1) {
+ info("Creating and opening FIFO");
+ unlink(b_fifo);
+ if(mkfifo(b_fifo, 0777) != 0) {
+ error("Failed to create FIFO");
+ }
+ bfifoFd = open(b_fifo, O_RDONLY | O_NONBLOCK);
+ #ifdef DEBUG
+ printf("%d: Fifo\n", bfifoFd);
+ #endif
+ if(bfifoFd == -1) {
+ error("Failed to open FIFO for reading");
+ }
+ if(bfifoFd > highFd) {
+ highFd = bfifoFd;
+ }
+ }
+ /* }}} */
+
+ /* Signal handlers, daemonize and X-Server opening {{{ */
+ /* Create signal handler for closing the display */
+ signal(SIGINT, signalHandlerQuit);
+ signal(SIGHUP, signalHandlerQuit);
+ signal(SIGALRM, signalHandlerAlarm);
+
+
+ /* Daemonize */
+ #ifndef DEBUG
+ if(daemonize == 1) {
+ daemon(0, 0);
+ }
+ #endif
+
+ /* Create PID file */
+ if(*pidfile)
+ make_pidfile(pidfile);
+
+ #ifdef X11
+ /* Wait for an X-Server to appear */
+ if(noXCode == 0) {
+ inotifyFdX11 = inotify_init();
+ if(inotifyFdX11 != -1) {
+ if(inotify_add_watch(inotifyFdX11, "/tmp/.X11-unix/", IN_CREATE) == -1) {
+ close(inotifyFdX11);
+ inotifyFdX11 = -1;
+ }
+ }
+ while(1) {
+ /* Try opening $DISPLAY first */
+ if((display = XOpenDisplay(NULL)) != NULL) {
+ info("Opened X11 Display from ENV{DISPLAY}");
+ }
+ else {
+ /* Failed to open $DISPLAY - wait for X11 to appear */
+ if(inotifyFdX11 != -1) {
+ info("Waiting for an X-Server to appear(!)");
+
+ read(inotifyFdX11, buf, sizeof(struct inotify_event) * 2);
+ inotifyEvent = (struct inotify_event *)buf;
+ strncpy(buf, inotifyEvent->name, 3);
+ buf[0] = ':';
+ buf[2] = 0;
+ if(verbose == 1 && daemonize == 0) {
+ printf("Found X-Server '%s'; I will try to open a connection to it every 5 seconds\n", buf);
+ }
+ }
+ else
+ {
+ info("inotify on /tmp/.X11-unix failed - polling for ':0'");
+ strcpy(buf, ":0");
+ }
+
+ display = XOpenDisplay(buf);
+ while(display == NULL) {
+ sleep(5);
+ display = XOpenDisplay(buf);
+ }
+ }
+
+ info("Opened a connection");
+ if(fork() == 0) {
+ break;
+ }
+ waitpid(0, NULL, 0);
+ info("Connection lost.");
+ sleep(5);
+ }
+ }
+ #endif
+
+ /* Drop privileges */
+ setegid(userStruct->pw_gid);
+ setgid(userStruct->pw_gid);
+ seteuid(userStruct->pw_uid);
+ setuid(userStruct->pw_uid);
+ /* }}} */
+
+ /* Wait for input */
+ alarm(waitSeconds);
+ while(1) {
+ eventReceived = 0;
+ rfds = openfds;
+
+ /* Add inotify and FIFO to watch list */
+ if(inotifyFdEvents != 0) {
+ FD_SET(inotifyFdEvents, &rfds);
+ }
+ if(bfifoFd != 0) {
+ FD_SET(bfifoFd, &rfds);
+ }
+
+ /* Select filepointers */
+ while(select(highFd + 1, &rfds, NULL, NULL, NULL) == -1) {
+ #ifdef DEBUG
+ info("DEBUG: Select failed.");
+ #endif
+ }
+
+ /* Check for event fd */
+ for(fd=0; fd<sizeof(fd_set) * 8; fd++) {
+ if(FD_ISSET(fd, &openfds) && FD_ISSET(fd, &rfds)) {
+ #ifdef DEBUG
+ printf("DEBUG: fd %d fired\n", fd);
+ #endif
+
+ if(read(fd, buf, 250) == -1) {
+ #ifdef DEBUG
+ printf("DEBUG: fd %d closed\n", fd);
+ #endif
+ close(fd);
+ FD_CLR(fd, &openfds);
+ if(fd == highFd) {
+ i = fd;
+ while(i > 0 && (!FD_ISSET(--i, &openfds)) && (i != bfifoFd));
+ highFd = i + 1;
+ }
+ }
+ else {
+ eventReceived = 1;
+ }
+ }
+ }
+
+ /* Event received */
+ if(eventReceived) {
+ handleReceivedEvent();
+ }
+
+ /* FIFO action */
+ if(bfifoFd != 0 && FD_ISSET(bfifoFd, &rfds)) {
+ memset(buf, 0, 5);
+ if(read(bfifoFd, buf, 2) != -1) {
+ if(strlen(buf) > 0) {
+ #ifdef DEBUG
+ printf("Fifo said: %s\n", buf);
+ #endif
+ i = atoi(buf);
+ if(savedLevel != i && lastFade + 1 < time(NULL)) {
+ userChangedBrightness(i);
+ }
+ }
+ else {
+ /* Reopen FIFO */
+ close(bfifoFd);
+ bfifoFd = open(b_fifo, O_RDONLY | O_NONBLOCK);
+ #ifdef DEBUG
+ info("Reopening FIFO");
+ #endif
+ if(bfifoFd == -1) {
+ error("Failed to open FIFO for reading");
+ }
+ if(bfifoFd > highFd) {
+ highFd = bfifoFd;
+ }
+ }
+ }
+ }
+
+ /* Inotify on /dev/input */
+ if(inotifyFdEvents != -1 && FD_ISSET(inotifyFdEvents, &rfds)) {
+ memset(buf, 0, sizeof(struct inotify_event) + 51);
+ read(inotifyFdEvents, buf, sizeof(struct inotify_event) + 50);
+ inotifyEvent = (struct inotify_event *)buf;
+ if(inotifyEvent->len > 0 && strstr(inotifyEvent->name, "event") != NULL) {
+ sprintf(buf2, "/dev/input/by-path/%s", inotifyEvent->name);
+ if(!isEventFileValid(buf2)) {
+ continue;
+ }
+ fd = open(buf2, O_RDONLY | O_NONBLOCK);
+ #ifdef DEBUG
+ printf("%d: %s\n", fd, buf2);
+ #endif
+ if(fd == -1) {
+ if(verbose == 1 && daemonize == 0) {
+ printf("Failed to open %s\n", buf2);
+ }
+ }
+ else {
+ if(fd > highFd) {
+ highFd = fd;
+ }
+ FD_SET(fd, &openfds);
+ }
+ }
+ }
+ }
+} /*}}}*/
+
+/* vim:ft=c:fileencoding=iso-8859-1:foldmethod=marker:noexpandtab
+ **/
diff --git a/gpl.txt b/gpl.txt
new file mode 100644
index 0000000..d511905
--- /dev/null
+++ b/gpl.txt
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.