Index: .gitignore
===================================================================
--- .gitignore	(revision 0237078c137da62703c024b5068c515c8086916f)
+++ .gitignore	(revision 0237078c137da62703c024b5068c515c8086916f)
@@ -0,0 +1,11 @@
+*~
+vm*
+ksplice*
+voldaemon
+log
+printcap
+debian/files
+debian/*.debhelper
+debian/gutenbach.substvars
+debian/gutenbach
+debian/gutenbach.debhelper.log
Index: .gitmodules
===================================================================
--- .gitmodules	(revision 9a301c8a994ce93b00343df3e3aeac5989d0aeba)
+++ .gitmodules	(revision 9a301c8a994ce93b00343df3e3aeac5989d0aeba)
@@ -0,0 +1,18 @@
+[submodule "plugins/itunes"]
+	path = plugins/itunes
+	url = /afs/sipb/project/sipbmp3/itunes-plugin.git/
+[submodule "web"]
+	path = web
+	url = /afs/sipb/project/sipbmp3/sipbmp3web.git/
+[submodule "gutenbach/debian/lib"]
+	path = gutenbach/debian/lib
+	url = /afs/sipb/project/sipbmp3/sipbmp3.git/
+[submodule "gutenbach-queue"]
+	path = gutenbach-queue
+	url = /afs/sipb/project/sipbmp3/gutenbach-queue.git/
+[submodule "gutenbach-remctl"]
+	path = gutenbach-remctl
+	url = /afs/sipb/project/sipbmp3/sipbmp3-remctl.git
+[submodule "plugins/gutenbach-rhythmbox-plugin"]
+	path = plugins/gutenbach-rhythmbox-plugin
+	url = /afs/sipb/project/sipbmp3/rhythmbox-plugin.git
Index: debian/.gitignore
===================================================================
--- debian/.gitignore	(revision 78ebe7526b641cb0177050f6a78fb68c506ffbeb)
+++ debian/.gitignore	(revision 78ebe7526b641cb0177050f6a78fb68c506ffbeb)
@@ -0,0 +1,1 @@
+*~
Index: debian/changelog
===================================================================
--- debian/changelog	(revision 773766631830ea5f12a8d625adc90e5e2a66b594)
+++ debian/changelog	(revision 773766631830ea5f12a8d625adc90e5e2a66b594)
@@ -0,0 +1,105 @@
+gutenbach (2.03) unstable; urgency=low
+
+  * Update permissions again, to allow everybody to access the server
+
+ -- Jessica Hamrick <jhamrick@mit.edu>  Tue, 08 Jun 2010 19:07:09 -0400
+
+gutenbach (2.02) unstable; urgency=low
+
+  * Fix print server permissions problems such that remote
+  users can user cups-lpq and cups-lprm
+
+ -- Jessica Hamrick <jhamrick@mit.edu>  Mon, 31 May 2010 23:51:52 -0400
+
+gutenbach (2.01) unstable; urgency=low
+
+  * Handle SIGTERM in the gutenbach backend, so jobs don't
+  keep playing even after being dequeued.
+
+ -- Jessica Hamrick <jhamrick@mit.edu>  Mon, 31 May 2010 22:23:53 -0400
+
+gutenbach (2.0) unstable; urgency=low
+
+  * Changed from using LPRng to CUPS
+
+ -- Jessica Hamrick <jhamrick@mit.edu>  Thu, 13 May 2010 17:40:53 -0400
+
+gutenbach (1.01) unstable; urgency=low
+
+  * Implemented debconf to retrieve printer and zephyr class names.
+  * Made uninstall cleaner (and when you purge, it purges
+  configuration files and changes)
+
+ -- Jessica Hamrick <jhamrick@mit.edu>  Wed, 16 Sep 2009 15:58:40 -0400
+
+gutenbach (1.0) unstable; urgency=low
+
+  * Initial release.
+
+ -- Jessica Hamrick <jhamrick@mit.edu>  Tue, 08 Sep 2009 18:38:12 -0400
+
+gutenbach-client (1.01-1) unstable; urgency=low
+
+  * Make package no longer Debian native.
+
+ -- Jessica Hamrick <jhamrick@mit.edu>  Sat, 26 Jun 2010 19:20:08 -0400
+
+gutenbach-client (1.01) unstable; urgency=low
+
+  * Fix debhelper compatibility to 5 (for backwards compatibility)
+
+ -- Jessica Hamrick <jhamrick@mit.edu>  Sat, 26 Jun 2010 18:01:02 -0400
+
+gutenbach-client (1.0) unstable; urgency=low
+
+  * Initial package build
+  * gbq - show queue
+  * gbr - queue file
+  * gbrm - remove file
+  * gutenbach-client-config - add, list, or delete queues
+
+ -- Jessica Hamrick <jhamrick@mit.edu>  Sat, 26 Jun 2010 16:56:28 -0400
+
+gutenbach-client (0.01) unstable; urgency=low
+
+  * Created skeleton package.
+
+ -- Jessica Hamrick <jhamrick@mit.edu>  Sat, 19 Jun 2010 00:23:53 -0400
+
+gutenbach-queue (1.02) unstable; urgency=low
+
+  * Prevent the screen from turning off when
+  view-gutenbach-queue is running.
+
+ -- Jessica Hamrick <jhamrick@mit.edu>  Mon, 14 Dec 2009 20:24:37 -0500
+
+gutenbach-queue (1.01) unstable; urgency=low
+
+  * Changed the chown in the postinst to
+  daemon:daemon instaed of daemon:pika
+
+ -- Jessica Hamrick <jhamrick@mit.edu>  Mon, 14 Dec 2009 20:23:50 -0500
+
+gutenbach-queue (1.0) unstable; urgency=low
+
+  * Initial release.
+
+ -- Jessica Hamrick <jhamrick@mit.edu>  Mon, 14 Dec 2009 20:03:48 -0500
+
+gutenbach-remctl (1.02) unstable; urgency=low
+
+  * Depend on version 2.0 or greater of gutenbach
+
+ -- Jessica Hamrick <jhamrick@mit.edu>  Thu, 13 May 2010 17:42:53 -0400
+
+gutenbach-remctl (1.01) unstable; urgency=low
+
+  * Just say the new volume, not who changed it.
+
+ -- Jessica Hamrick <jhamrick@mit.edu>  Mon, 14 Dec 2009 22:04:43 -0500
+
+gutenbach-remctl (1.0) unstable; urgency=low
+
+  * Initial release.
+
+ -- Jessica Hamrick <jhamrick@mit.edu>  Mon, 14 Dec 2009 22:03:44 -0500
Index: debian/compat
===================================================================
--- debian/compat	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ debian/compat	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,1 @@
+5
Index: debian/control
===================================================================
--- debian/control	(revision 773766631830ea5f12a8d625adc90e5e2a66b594)
+++ debian/control	(revision 773766631830ea5f12a8d625adc90e5e2a66b594)
@@ -0,0 +1,38 @@
+Source: gutenbach
+Section: sound
+Priority: extra
+Maintainer: Jessica Hamrick <jhamrick@mit.edu>
+Build-Depends: cdbs, debhelper (>= 7.4.15ubuntu1)
+Standards-Version: 3.8.4
+
+Package: gutenbach
+Architecture: all
+Pre-Depends: debconf
+Depends: ${shlibs:Depends}, ${misc:Depends}, mplayer, libimage-exiftool-perl, cups, debathena-cupsys-config, sysv-rc, adduser, debathena-zephyr-config, libzephyr4-krb5, alsa-base
+Conflicts: pulseaudio
+Provides: pulseaudio
+Description: Server for playing music files from a remote machine
+ Allows remote machines to play music files on this machine
+ by "printing" them with the Common UNIX Printing System (CUPS).
+
+Package: gutenbach-client
+Architecture: all
+Pre-Depends: debconf
+Depends: ${shlibs:Depends}, ${misc:Depends}, cups, libnet-cups-perl
+Description: Client-side helper scripts for interacting with
+ the Gutenbach music player.
+
+Package: gutenbach-queue
+Architecture: all
+Pre-Depends: debconf
+Depends: ${shlibs:Depends}, ${misc:Depends}, daemon, gutenbach
+Description: Displays metadat about the current songs in the 
+ queue for the gutenbach music spooler, and also the song that
+ is currently playing.
+
+Package: gutenbach-remctl
+Architecture: all
+Pre-Depends: debconf
+Depends: ${shlibs:Depends}, ${misc:Depends}, gutenbach (>= 2.0), alsa-utils, cd-discid, remctl-server
+Description: Allows a remote user to control the volume, view
+ the current status of the queue, or play tracks from a cd.
Index: debian/copyright
===================================================================
--- debian/copyright	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ debian/copyright	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,1 @@
+Copyright 2009 Jessica Hamrick
Index: debian/gutenbach-queue.dirs
===================================================================
--- debian/gutenbach-queue.dirs	(revision e87e682008b20061e88abcb383650485c76c3f88)
+++ debian/gutenbach-queue.dirs	(revision e87e682008b20061e88abcb383650485c76c3f88)
@@ -0,0 +1,2 @@
+usr/lib/gutenbach
+usr/lib/gutenbach/queue
Index: debian/gutenbach-queue.init
===================================================================
--- debian/gutenbach-queue.init	(revision e87e682008b20061e88abcb383650485c76c3f88)
+++ debian/gutenbach-queue.init	(revision e87e682008b20061e88abcb383650485c76c3f88)
@@ -0,0 +1,91 @@
+#!/bin/bash
+### BEGIN INIT INFO
+# Provides:          gutenbach-queue
+# Required-Start:    $remote_fs $syslog
+# Required-Stop:     $remote_fs $syslog
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Starts the queue daemon for gutenbach.
+# Description:       Starts the queue daemon for gutenbach.
+### END INIT INFO
+
+case "$1" in
+    start)
+	daemon -F /var/run/gutenbach/gutenbach-queue.pid --name gutenbach-queue --running
+	if [ "$?" == 0 ]; then
+	    echo "The gutenbach queue daemon is already running."
+	else
+	    if [ ! -e /var/run/gutenbach/current_queue ]; then
+		touch /var/run/gutenbach/current_queue
+		chmod ugoa+r /var/run/gutenbach/current_queue
+            fi
+            if [ ! -e /var/run/gutenbach/queue_times ]; then
+		touch /var/run/gutenbach/queue_times
+            fi
+            if [ ! -e /var/run/gutenbach/exiftool_data ]; then
+		touch /var/run/gutenbach/exiftool_data
+	    fi
+            if [ ! -e /var/run/gutenbach/current_queue_temp ]; then
+		touch /var/run/gutenbach/current_queue_temp
+            fi
+
+	    echo "Starting gutenbach daemon..."
+	    daemon -F /var/run/gutenbach/gutenbach-queue.pid --name gutenbach-queue -u daemon /usr/lib/gutenbach/queue/build-gutenbach-queue
+	    echo "Done."
+	fi
+	;;
+
+    stop)
+	daemon -F /var/run/gutenbach/gutenbach-queue.pid --stop --name gutenbach-queue
+	/usr/lib/gutenbach/queue/kill-gutenbach-queue
+
+	if [ -e /var/run/gutenbach/current_queue ]; then
+            rm /var/run/gutenbach/current_queue
+	fi
+        if [ -e /var/run/gutenbach/queue_times ]; then
+            rm /var/run/gutenbach/queue_times
+	fi
+        if [ -e /var/run/gutenbach/exiftool_data ]; then
+            rm /var/run/gutenbach/exiftool_data
+	fi
+        if [ -e /var/run/gutenbach/current_queue_temp ]; then
+            rm /var/run/gutenbach/current_queue_temp
+        fi
+	;;
+
+    restart)
+	daemon -F /var/run/gutenbach/gutenbach-queue.pid --stop --name gutenbach-queue
+        /usr/lib/gutenbach/queue/kill-gutenbach-queue
+
+	if [ -e /var/run/gutenbach/current_queue ]; then
+	    rm /var/run/gutenbach/current_queue
+	fi
+	if [ -e /var/run/gutenbach/queue_times ]; then
+	    rm /var/run/gutenbach/queue_times
+	fi
+	if [ -e /var/run/gutenbach/exiftool_data ]; then
+	    rm /var/run/gutenbach/exiftool_data
+	fi
+	if [ -e /var/run/gutenbach/current_queue_temp ]; then
+	    rm /var/run/gutenbach/current_queue_temp
+	fi
+
+	touch /var/run/gutenbach/current_queue
+	chmod ugoa+r /var/run/gutenbach/current_queue
+	touch /var/run/gutenbach/queue_times
+	touch /var/run/gutenbach/exiftool_data
+	touch /var/run/gutenbach/current_queue_temp
+
+	echo "Starting gutenbach daemon..."
+	daemon -F /var/run/gutenbach/gutenbach-queue.pid --name gutenbach-queue -u daemon /usr/lib/gutenbach/queue/build-gutenbach-queue
+	echo "Done."
+	;;
+
+    force-reload)
+	;;
+
+    *)
+	echo "Usage: $0 {start|stop|restart}"
+	exit 1
+	;;
+esac
Index: debian/gutenbach-queue.install
===================================================================
--- debian/gutenbach-queue.install	(revision e87e682008b20061e88abcb383650485c76c3f88)
+++ debian/gutenbach-queue.install	(revision e87e682008b20061e88abcb383650485c76c3f88)
@@ -0,0 +1,1 @@
+debian/lib/* /usr/lib/gutenbach/queue/
Index: debian/gutenbach-queue.postinst
===================================================================
--- debian/gutenbach-queue.postinst	(revision e87e682008b20061e88abcb383650485c76c3f88)
+++ debian/gutenbach-queue.postinst	(revision e87e682008b20061e88abcb383650485c76c3f88)
@@ -0,0 +1,51 @@
+#!/bin/sh
+# postinst script for gutenbach-queue
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+#        * <postinst> `configure' <most-recently-configured-version>
+#        * <old-postinst> `abort-upgrade' <new version>
+#        * <conflictor's-postinst> `abort-remove' `in-favour' <package>
+#          <new-version>
+#        * <postinst> `abort-remove'
+#        * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
+#          <failed-install-package> <version> `removing'
+#          <conflicting-package> <version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+. /usr/share/debconf/confmodule
+
+case "$1" in
+    configure|reconfigure)
+	chmod +x /usr/lib/gutenbach/queue/build-gutenbach-queue
+	chmod +x /usr/lib/gutenbach/queue/kill-gutenbach-queue
+	chmod +x /usr/lib/gutenbach/queue/view-gutenbach-queue
+	chmod +x /usr/lib/gutenbach/queue/queue
+	
+	if [ ! -e /usr/bin/view-gutenbach-queue ]; then
+	    ln -s /usr/lib/gutenbach/queue/view-gutenbach-queue /usr/bin/view-gutenbach-queue
+	fi
+
+	chown -R daemon:daemon /var/run/gutenbach
+	chmod og+rw /var/run/gutenbach
+    ;;
+
+    abort-upgrade|abort-remove|abort-deconfigure)
+    ;;
+
+    *)
+        echo "postinst called with unknown argument \`$1'" >&2
+        exit 1
+    ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
Index: debian/gutenbach-queue.postrm
===================================================================
--- debian/gutenbach-queue.postrm	(revision e87e682008b20061e88abcb383650485c76c3f88)
+++ debian/gutenbach-queue.postrm	(revision e87e682008b20061e88abcb383650485c76c3f88)
@@ -0,0 +1,48 @@
+#!/bin/sh
+# postrm script for gutenbach-queue
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+#        * <postrm> `remove'
+#        * <postrm> `purge'
+#        * <old-postrm> `upgrade' <new-version>
+#        * <new-postrm> `failed-upgrade' <old-version>
+#        * <new-postrm> `abort-install'
+#        * <new-postrm> `abort-install' <old-version>
+#        * <new-postrm> `abort-upgrade' <old-version>
+#        * <disappearer's-postrm> `disappear' <overwriter>
+#          <overwriter-version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+
+case "$1" in
+    purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
+	if [ "$1" = "purge" ]; then
+	    if [ -e /usr/lib/gutenbach/queue ]; then
+		echo "Removing /usr/lib/gutenbach/queue/ ..." >&2
+		rm -r  /usr/lib/gutenbach/queue
+	    fi
+
+	    if [ -e /usr/bin/view-gutenbach-queue ]; then
+		echo "Removing /usr/bin/view-gutenbach-queue ..." >&2
+		rm /usr/bin/view-gutenbach-queue
+	    fi
+     	fi
+    ;;
+
+    *)
+        echo "postrm called with unknown argument \`$1'" >&2
+        exit 1
+    ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
Index: debian/gutenbach-remctl.dirs
===================================================================
--- debian/gutenbach-remctl.dirs	(revision 78ebe7526b641cb0177050f6a78fb68c506ffbeb)
+++ debian/gutenbach-remctl.dirs	(revision 78ebe7526b641cb0177050f6a78fb68c506ffbeb)
@@ -0,0 +1,3 @@
+usr/lib/gutenbach
+usr/lib/gutenbach/remctl
+etc/remctl/conf.d
Index: debian/gutenbach-remctl.init
===================================================================
--- debian/gutenbach-remctl.init	(revision 78ebe7526b641cb0177050f6a78fb68c506ffbeb)
+++ debian/gutenbach-remctl.init	(revision 78ebe7526b641cb0177050f6a78fb68c506ffbeb)
@@ -0,0 +1,114 @@
+#!/bin/bash
+### BEGIN INIT INFO
+# Provides:          gutenbach-remctl
+# Required-Start:    $remote_fs $syslog
+# Required-Stop:     $remote_fs $syslog
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Starts remctld.
+# Description:       Starts remctld.
+### END INIT INFO
+
+case "$1" in
+    start)
+	if [ -e /var/run/gutenbach/remctld.pid ]; then
+	    pid=$(cat /var/run/gutenbach/remctld.pid)
+	    if [ -n "$pid" ]; then
+		kill -0 "$pid"
+		if [ "$?" == 0 ]; then
+		    echo "Ending remctld..." >&2
+		    kill "$pid" || true
+		fi
+	    fi
+	fi
+
+	pid=$(sudo lsof -i :4373 | grep remctld | sed s/remctld\ // | sed s/\ .*//)
+	if [ -n "$pid" ]; then
+	    kill -0 "$pid"
+	    if [ "$?" == 0 ]; then
+		echo "Ending remctld socket binding..." >&2
+		kill "$pid" || true
+	    fi
+	fi
+
+	echo "Starting remctld..." >&2
+	remctld -m -P /var/run/gutenbach/remctld.pid &
+	;;
+
+    stop)
+	if [ -e /var/run/gutenbach/remctld.pid ]; then
+	    pid=$(cat /var/run/gutenbach/remctld.pid)
+	    if [ -n "$pid" ]; then
+		kill -0 "$pid"
+		if [ "$?" == 0 ]; then
+		    echo "Ending remctld..." >&2
+		    kill "$pid" || true
+		fi
+	    fi
+	fi
+
+	pid=$(sudo lsof -i :4373 | grep remctld | sed s/remctld\ // | sed s/\ .*//)
+	if [ -n "$pid" ]; then
+	    kill -0 "$pid"
+	    if [ "$?" == 0 ]; then
+		echo "Ending remctld socket binding..." >&2
+		kill "$pid" || true
+	    fi
+	fi
+	;;
+
+    restart)
+	if [ -e /var/run/gutenbach/remctld.pid ]; then
+	    pid=$(cat /var/run/gutenbach/remctld.pid)
+	    if [ -n "$pid" ]; then
+		kill -0 "$pid"
+		if [ "$?" == 0 ]; then
+		    echo "Ending remctld..." >&2
+		    kill "$pid" || true
+		fi
+	    fi
+	fi
+
+	pid=$(sudo lsof -i :4373 | grep remctld | sed s/remctld\ // | sed s/\ .*//)
+	if [ -n "$pid" ]; then
+	    kill -0 "$pid"
+	    if [ "$?" == 0 ]; then
+		echo "Ending remctld socket binding..." >&2
+		kill "$pid" || true
+	    fi
+	fi
+
+	echo "Starting remctld..." >&2
+	remctld -m -P /var/run/gutenbach/remctld.pid &
+	;;
+
+    force-reload)
+	if [ -e /var/run/gutenbach/remctld.pid ]; then
+	    pid=$(cat /var/run/gutenbach/remctld.pid)
+	    if [ -n "$pid" ]; then
+		kill -0 "$pid"
+		if [ "$?" == 0 ]; then
+		    echo "Ending remctld..." >&2
+		    kill "$pid" || true
+		fi
+	    fi
+	fi
+
+	pid=$(sudo lsof -i :4373 | grep remctld | sed s/remctld\ // | sed s/\ .*//)
+	if [ -n "$pid" ]; then
+	    kill -0 "$pid"
+	    if [ "$?" == 0 ]; then
+		echo "Ending remctld socket binding..." >&2
+		kill "$pid" || true
+	    fi
+	fi
+
+	echo "Starting remctld..." >&2
+	remctld -m -P /var/run/gutenbach/remctld.pid &
+	;;
+
+    *)
+	echo "Usage: $0 {start|stop|restart}"
+	exit 1
+	;;
+esac
Index: debian/gutenbach-remctl.install
===================================================================
--- debian/gutenbach-remctl.install	(revision 78ebe7526b641cb0177050f6a78fb68c506ffbeb)
+++ debian/gutenbach-remctl.install	(revision 78ebe7526b641cb0177050f6a78fb68c506ffbeb)
@@ -0,0 +1,2 @@
+debian/lib/for-gutenbach/* /usr/lib/gutenbach/remctl/
+debian/lib/for-remctl/* /etc/remctl/conf.d/
Index: debian/gutenbach-remctl.postinst
===================================================================
--- debian/gutenbach-remctl.postinst	(revision 78ebe7526b641cb0177050f6a78fb68c506ffbeb)
+++ debian/gutenbach-remctl.postinst	(revision 78ebe7526b641cb0177050f6a78fb68c506ffbeb)
@@ -0,0 +1,52 @@
+#!/bin/sh
+# postinst script for gutenbach-remctl
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+#        * <postinst> `configure' <most-recently-configured-version>
+#        * <old-postinst> `abort-upgrade' <new version>
+#        * <conflictor's-postinst> `abort-remove' `in-favour' <package>
+#          <new-version>
+#        * <postinst> `abort-remove'
+#        * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
+#          <failed-install-package> <version> `removing'
+#          <conflicting-package> <version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+case "$1" in
+    configure|reconfigure)
+	chmod +x /usr/lib/gutenbach/remctl/cd-cddb
+	chmod +x /usr/lib/gutenbach/remctl/cd-cddb-get
+	chmod +x /usr/lib/gutenbach/remctl/cd-play
+	chmod +x /usr/lib/gutenbach/remctl/status-clear
+	chmod +x /usr/lib/gutenbach/remctl/status-get
+	chmod +x /usr/lib/gutenbach/remctl/volume-down
+	chmod +x /usr/lib/gutenbach/remctl/volume-get
+	chmod +x /usr/lib/gutenbach/remctl/volume-help
+	chmod +x /usr/lib/gutenbach/remctl/volume-is-muted
+	chmod +x /usr/lib/gutenbach/remctl/volume-mute
+	chmod +x /usr/lib/gutenbach/remctl/volume-set
+	chmod +x /usr/lib/gutenbach/remctl/volume-show
+	chmod +x /usr/lib/gutenbach/remctl/volume-up
+	chmod +x /usr/lib/gutenbach/remctl/volume-zephyr
+    ;;
+
+    abort-upgrade|abort-remove|abort-deconfigure)
+    ;;
+
+    *)
+        echo "postinst called with unknown argument \`$1'" >&2
+        exit 1
+    ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
Index: debian/gutenbach-remctl.postrm
===================================================================
--- debian/gutenbach-remctl.postrm	(revision 78ebe7526b641cb0177050f6a78fb68c506ffbeb)
+++ debian/gutenbach-remctl.postrm	(revision 78ebe7526b641cb0177050f6a78fb68c506ffbeb)
@@ -0,0 +1,49 @@
+#!/bin/sh
+# postrm script for gutenbach-remctl
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+#        * <postrm> `remove'
+#        * <postrm> `purge'
+#        * <old-postrm> `upgrade' <new-version>
+#        * <new-postrm> `failed-upgrade' <old-version>
+#        * <new-postrm> `abort-install'
+#        * <new-postrm> `abort-install' <old-version>
+#        * <new-postrm> `abort-upgrade' <old-version>
+#        * <disappearer's-postrm> `disappear' <overwriter>
+#          <overwriter-version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+
+case "$1" in
+    purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
+	if [ "$1" = "purge" ]; then
+	    if [ -e /usr/lib/gutenbach/remctl ]; then
+		echo "Removing /usr/lib/gutenbach/remctl/ ..." >&2
+		rm -r  /usr/lib/gutenbach/remctl
+	    fi
+
+	    if [ -e /etc/remctl/conf.d ]; then
+		echo "Removing /etc/remctl/conf.d ..." >&2
+		rm /etc/remctl/conf.d
+		mkdir /etc/remctl/conf.d
+	    fi
+     	fi
+    ;;
+
+    *)
+        echo "postrm called with unknown argument \`$1'" >&2
+        exit 1
+    ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
Index: debian/gutenbach.config
===================================================================
--- debian/gutenbach.config	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ debian/gutenbach.config	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,29 @@
+#!/bin/sh -e
+
+# Source debconf library.
+. /usr/share/debconf/confmodule
+
+printername=""
+zephyrclass=""
+hostname=""
+
+if [ -e /usr/lib/gutenbach/config/printername ]; then
+    printername=$(cat /usr/lib/gutenbach/config/printername)
+    db_set gutenbach/printername "$printername"
+fi
+
+if [ -e /usr/lib/gutenbach/config/zephyrclass ]; then
+    zephyrclass=$(cat /usr/lib/gutenbach/config/zephyrclass)
+    db_set gutenbach/zephyrclass "$zephyrclass"
+fi
+
+if [ -e /usr/lib/gutenbach/config/hostname ]; then
+    hostname=$(cat /usr/lib/gutenbach/config/hostname)
+    db_set gutenbach/hostname "$hostname"
+fi
+
+db_input high gutenbach/printername || true
+db_input high gutenbach/zephyrclass || true
+db_input high gutenbach/hostname || true
+db_go || true
+
Index: debian/gutenbach.dirs
===================================================================
--- debian/gutenbach.dirs	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ debian/gutenbach.dirs	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,5 @@
+usr/lib/gutenbach
+usr/lib/gutenbach/inst
+usr/lib/gutenbach/rm
+usr/lib/gutenbach/config
+etc/
Index: debian/gutenbach.init
===================================================================
--- debian/gutenbach.init	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ debian/gutenbach.init	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,49 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides:          gutenbach
+# Required-Start:    $remote_fs $syslog cups
+# Required-Stop:     $remote_fs $syslog
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Starts lpd for gutenbach.
+# Description:       Starts lpd for gutenbach and creates
+#  files for use by gutenbach.
+### END INIT INFO
+
+case "$1" in
+  start)
+    mkdir /var/run/gutenbach
+    touch /var/run/gutenbach/status
+    chmod 0777 /var/run/gutenbach/status
+    
+    ;;
+
+  stop)
+    
+    if [ -e /var/run/gutenbach ]; then
+	rm -r /var/run/gutenbach
+    fi
+
+    ;;
+
+  restart)
+    
+    if [ -e /var/run/gutenbach ]; then
+	rm -r /var/run/gutenbach
+    fi
+
+
+    mkdir /var/run/gutenbach
+    touch /var/run/gutenbach/status
+    chmod 0777 /var/run/gutenbach/status
+
+    ;;
+
+  reload|force-reload|status)
+    ;;
+
+  *)
+    echo "Usage: /etc/init.d/gutenbach {start|stop|restart}" >&2
+    exit 1
+    ;;
+esac
Index: debian/gutenbach.install
===================================================================
--- debian/gutenbach.install	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ debian/gutenbach.install	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,4 @@
+debian/lib/gutenbach /usr/lib/cups/backend
+debian/lib/* /usr/lib/gutenbach/
+debian/inst/* /usr/lib/gutenbach/inst/
+debian/rm/* /usr/lib/gutenbach/rm/
Index: debian/gutenbach.postinst
===================================================================
--- debian/gutenbach.postinst	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ debian/gutenbach.postinst	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,65 @@
+#!/bin/sh
+# postinst script for gutenbach
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+#        * <postinst> `configure' <most-recently-configured-version>
+#        * <old-postinst> `abort-upgrade' <new version>
+#        * <conflictor's-postinst> `abort-remove' `in-favour' <package>
+#          <new-version>
+#        * <postinst> `abort-remove'
+#        * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
+#          <failed-install-package> <version> `removing'
+#          <conflicting-package> <version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+. /usr/share/debconf/confmodule
+
+case "$1" in
+    configure|reconfigure)
+	if [ ! -d /usr/lib/gutenbach/config ]; then
+	    mkdir /usr/lib/gutenbach/config
+	fi
+
+	db_get gutenbach/zephyrclass
+	echo "$RET" > /usr/lib/gutenbach/config/zephyrclass
+	db_get gutenbach/printername
+	echo "$RET" > /usr/lib/gutenbach/config/printername
+	db_get gutenbach/hostname
+	echo "$RET" > /usr/lib/gutenbach/config/hostname
+
+	chmod +x /usr/lib/gutenbach/inst/create-filter-config
+	chmod +x /usr/lib/gutenbach/inst/cups-add-printer
+	chmod +x /usr/lib/gutenbach/inst/cups-set-perms
+	/usr/lib/gutenbach/inst/create-filter-config
+	/usr/lib/gutenbach/inst/cups-add-printer
+	/usr/lib/gutenbach/inst/cups-set-perms
+
+
+	inaudio=$(groups lp | grep audio || true)
+	if [ -z "$inaudio" ]; then
+	    adduser lp audio
+	fi
+
+	db_stop
+    ;;
+
+    abort-upgrade|abort-remove|abort-deconfigure)
+    ;;
+
+    *)
+        echo "postinst called with unknown argument \`$1'" >&2
+        exit 1
+    ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
Index: debian/gutenbach.postrm
===================================================================
--- debian/gutenbach.postrm	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ debian/gutenbach.postrm	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,54 @@
+#!/bin/sh
+# postrm script for gutenbach
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+#        * <postrm> `remove'
+#        * <postrm> `purge'
+#        * <old-postrm> `upgrade' <new-version>
+#        * <new-postrm> `failed-upgrade' <old-version>
+#        * <new-postrm> `abort-install'
+#        * <new-postrm> `abort-install' <old-version>
+#        * <new-postrm> `abort-upgrade' <old-version>
+#        * <disappearer's-postrm> `disappear' <overwriter>
+#          <overwriter-version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+
+case "$1" in
+    purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
+	if [ "$1" = "purge" ]; then
+	    if [ -d /usr/lib/gutenbach ]; then
+		echo "Removing /usr/lib/gutenbach/..." >&2
+		rm -r /usr/lib/gutenbach
+	    fi
+
+	    if [ -e /usr/share/debconf/confmodule ]; then
+		echo "Purging debconf database entries..." >&2
+		. /usr/share/debconf/confmodule
+		db_purge
+	    fi
+	fi
+
+	inaudio=$(groups daemon | grep audio || true)
+	if [ ! -z "$inaudio" ]; then
+	    deluser daemon audio
+	fi
+    ;;
+
+    *)
+        echo "postrm called with unknown argument \`$1'" >&2
+        exit 1
+    ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
Index: debian/gutenbach.preinst
===================================================================
--- debian/gutenbach.preinst	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ debian/gutenbach.preinst	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,36 @@
+#!/bin/sh
+# preinst script for gutenbach
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+#        * <new-preinst> `install'
+#        * <new-preinst> `install' <old-version>
+#        * <new-preinst> `upgrade' <old-version>
+#        * <old-preinst> `abort-upgrade' <new-version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+. /usr/share/debconf/confmodule
+
+case "$1" in
+    install|upgrade)
+    ;;
+
+    abort-upgrade)
+    ;;
+
+    *)
+        echo "preinst called with unknown argument \`$1'" >&2
+        exit 1
+    ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
Index: debian/gutenbach.prerm
===================================================================
--- debian/gutenbach.prerm	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ debian/gutenbach.prerm	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,48 @@
+#!/bin/sh
+# prerm script for gutenbach
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+#        * <prerm> `remove'
+#        * <old-prerm> `upgrade' <new-version>
+#        * <new-prerm> `failed-upgrade' <old-version>
+#        * <conflictor's-prerm> `remove' `in-favour' <package> <new-version>
+#        * <deconfigured's-prerm> `deconfigure' `in-favour'
+#          <package-being-installed> <version> `removing'
+#          <conflicting-package> <version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+
+case "$1" in
+    remove|upgrade|deconfigure)
+
+	if [ -e /usr/lib/gutenbach/rm/cups-revert-perms ]; then
+	    chmod +x /usr/lib/gutenbach/rm/cups-revert-perms
+	    /usr/lib/gutenbach/rm/cups-revert-perms
+	fi
+
+	if [ -e /usr/lib/gutenbach/rm/cups-remove-printer ]; then
+	    chmod +x /usr/lib/gutenbach/rm/cups-remove-printer
+	    /usr/lib/gutenbach/rm/cups-remove-printer
+	fi
+    ;;
+
+    failed-upgrade)
+    ;;
+
+    *)
+        echo "prerm called with unknown argument \`$1'" >&2
+        exit 1
+    ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
Index: debian/gutenbach.templates
===================================================================
--- debian/gutenbach.templates	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ debian/gutenbach.templates	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,25 @@
+Template: gutenbach/printername
+Type: string
+_Description: Your gutenbach printer name:
+ gutenbach creates a printer to which you can print music
+ files.  gutenbach needs to know what you want to call the 
+ printer, and then after installation, you will be able
+ to do:
+ lpr -Pprintername@hostname your-music-file-.mp3 
+
+Template: gutenbach/zephyrclass
+Type: string
+_Description: Your gutenbach zephyr class:
+ When gutenbach plays a song, it sends a message to a zephyr
+ class with the song information (title, artist, album,
+ etc).  Please specify which class you would you these 
+ zephyrs to be sent to.  If you don't know what this is,
+ or you don't want zephyrs to be sent, just leave this 
+ field blank.
+
+Template: gutenbach/hostname
+Type: string
+_Description: The hostname to be displayed:
+ When gutenbach sends a zephyr, it will display the hostname.
+ If your hostname is particularly long, you may want to set
+ this to an abbreviation or something else shorter.
Index: debian/po/POTFILES.in
===================================================================
--- debian/po/POTFILES.in	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ debian/po/POTFILES.in	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,1 @@
+[type: gettext/rfc822deb] gutenbach.templates
Index: debian/po/templates.pot
===================================================================
--- debian/po/templates.pot	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ debian/po/templates.pot	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,64 @@
+# Gutenbach Translation File.
+#
+# This file is distributed under the same license as the GUTENBACH package.
+# Jessica B. Hamrick <jhamrick@mit.edu>, 2010.
+#
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: gutenbach@mit.edu\n"
+"POT-Creation-Date: 2010-06-14 18:36-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: string
+#. Description
+#: ../gutenbach.templates:1001
+msgid "Your gutenbach printer name:"
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../gutenbach.templates:1001
+msgid ""
+"gutenbach creates a printer to which you can print music files.  gutenbach "
+"needs to know what you want to call the  printer, and then after "
+"installation, you will be able to do: lpr -Pprintername@hostname your-music-"
+"file-.mp3"
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../gutenbach.templates:2001
+msgid "Your gutenbach zephyr class:"
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../gutenbach.templates:2001
+msgid ""
+"When gutenbach plays a song, it sends a message to a zephyr class with the "
+"song information (title, artist, album, etc).  Please specify which class "
+"you would you these  zephyrs to be sent to.  If you don't know what this is, "
+"or you don't want zephyrs to be sent, just leave this  field blank."
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../gutenbach.templates:3001
+msgid "The hostname to be displayed:"
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../gutenbach.templates:3001
+msgid ""
+"When gutenbach sends a zephyr, it will display the hostname. If your "
+"hostname is particularly long, you may want to set this to an abbreviation "
+"or something else shorter."
+msgstr ""
Index: debian/rules
===================================================================
--- debian/rules	(revision 7cf3a465c72c2c72d74a3df48b5f6e8e378cfb54)
+++ debian/rules	(revision 7cf3a465c72c2c72d74a3df48b5f6e8e378cfb54)
@@ -0,0 +1,6 @@
+#!/usr/bin/make -f
+
+DEB_MAKE_INSTALL_TARGET=install DESTDIR=$(DEB_DESTDIR)
+
+include /usr/share/cdbs/1/rules/debhelper.mk
+include /usr/share/cdbs/1/class/makefile.mk
Index: debian/source/format
===================================================================
--- debian/source/format	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ debian/source/format	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,1 @@
+1.0
Index: gutenbach-client/Makefile
===================================================================
--- gutenbach-client/Makefile	(revision 0deef9e258fce28cac566b226c4b623057566190)
+++ gutenbach-client/Makefile	(revision 0deef9e258fce28cac566b226c4b623057566190)
@@ -0,0 +1,5 @@
+all:
+
+install:
+	mkdir -p $(DESTDIR)/usr/bin/
+	install -m 755 bin/* $(DESTDIR)/usr/bin/
Index: gutenbach-client/bin/gbq
===================================================================
--- gutenbach-client/bin/gbq	(revision 0deef9e258fce28cac566b226c4b623057566190)
+++ gutenbach-client/bin/gbq	(revision 0deef9e258fce28cac566b226c4b623057566190)
@@ -0,0 +1,54 @@
+#!/usr/bin/perl
+
+# Written by Jessica Hamrick (C) 2010
+
+use strict;
+use warnings;
+
+use Net::CUPS;
+use Net::CUPS::Destination;
+
+my $usage = "Usage: gbq QUEUE\n";
+
+my $q = $ARGV[0];
+
+if (!$q) {
+    print $usage;
+    exit 1
+}
+
+my $configpath = "$ENV{'HOME'}/.gutenbach/$q";
+if (! -e $configpath) {
+    print "Queue '$q' does not exist!\n";
+    exit 1;
+}
+
+my ($host, $queue);
+
+if (-r $configpath) {
+    local $/;
+    my $fh;
+    open $fh, $configpath;
+    eval <$fh>;
+}
+
+my $cups = Net::CUPS->new();
+$cups->setServer("$host");
+my $printer = $cups->getDestination("$queue");
+
+print "Queue listing for queue '$queue' on '$host'\n\n";
+print "Job ID\t\tOwner\t\tFile\n";
+print "-----------------------------------------------------------------\n";
+
+my @jobs = $printer->getJobs(0, 0);
+my ($job_ref, $jobid);
+
+foreach $jobid(@jobs) 
+{       
+	$job_ref = $printer->getJob($jobid);
+	my $id = $job_ref->{'id'};
+	my $user = $job_ref->{'user'};
+	my $title = $job_ref->{'title'};
+
+	print "$id\t\t$user\t\t$title\n";
+}
Index: gutenbach-client/bin/gbr
===================================================================
--- gutenbach-client/bin/gbr	(revision 0deef9e258fce28cac566b226c4b623057566190)
+++ gutenbach-client/bin/gbr	(revision 0deef9e258fce28cac566b226c4b623057566190)
@@ -0,0 +1,34 @@
+#!/usr/bin/perl
+
+# Written by Jessica Hamrick (C) 2010
+
+use strict;
+use warnings;
+
+my $usage = "Usage: gbr QUEUE FILE\n";
+
+my $q = $ARGV[0];
+my $file = $ARGV[1];
+
+if (!$q or !$file) {
+    print $usage;
+    exit 1
+}
+
+my $configpath = "$ENV{'HOME'}/.gutenbach/$q";
+if (! -e $configpath) {
+    print "Queue '$q' does not exist!\n";
+    exit 1;
+}
+
+my ($host, $queue);
+
+if (-r $configpath) {
+    local $/;
+    my $fh;
+    open $fh, $configpath;
+    eval <$fh>;
+}
+
+my @args = ("lp", "-h$host", "-d$queue", "$file");
+exec (@args) or die "Couldn't execute lp command";
Index: gutenbach-client/bin/gbrm
===================================================================
--- gutenbach-client/bin/gbrm	(revision 0deef9e258fce28cac566b226c4b623057566190)
+++ gutenbach-client/bin/gbrm	(revision 0deef9e258fce28cac566b226c4b623057566190)
@@ -0,0 +1,41 @@
+#!/usr/bin/perl
+
+# Written by Jessica Hamrick (C) 2010
+
+use strict;
+use warnings;
+
+my $usage = "Usage: gbq QUEUE ID\n";
+
+my $q = $ARGV[0];
+my $id = $ARGV[1];
+
+if (!$q or !$id) {
+    print $usage;
+    exit 1
+}
+
+my $configpath = "$ENV{'HOME'}/.gutenbach/$q";
+if (! -e $configpath) {
+    print "Queue '$q' does not exist!\n";
+    exit 1;
+}
+
+my ($host, $queue);
+
+if (-r $configpath) {
+    local $/;
+    my $fh;
+    open $fh, $configpath;
+    eval <$fh>;
+}
+
+my @args;
+
+if ($id eq "all") {
+    @args = ("cancel", "-a", "-h$host", "$queue");
+}
+else {
+    @args = ("cancel", "-h$host", "$id", "$queue");
+}
+exec (@args) or die "Couldn't execute cancel command";
Index: gutenbach-client/bin/gutenbach-client-config
===================================================================
--- gutenbach-client/bin/gutenbach-client-config	(revision 0deef9e258fce28cac566b226c4b623057566190)
+++ gutenbach-client/bin/gutenbach-client-config	(revision 0deef9e258fce28cac566b226c4b623057566190)
@@ -0,0 +1,84 @@
+#!/usr/bin/perl
+
+# Written by Jessica Hamrick, (C) 2010
+
+use strict;
+use warnings;
+use Getopt::Long;
+
+my $usage = 
+    "Usage: gutenbach-client-config [-l|--list|-a|--add|-d|--delete] [QUEUE] [--host=HOST]\n" .
+    "\n" .
+    "\t-l, --list\t\tList available queues\n" .
+    "\t-a, --add QUEUE\t\tAdd a queue (must be used with -h)\n" .
+    "\t-d, --delete QUEUE\tDelete a queue)\n" .
+    "\t-h, --host HOST\t\tHostname for the queue\n";
+
+my $list = 0;
+my $add = "";
+my $delete = "";
+my $host = "";
+
+GetOptions ('l|list' => \$list,
+            'a|add=s' => \$add,
+            'd|delete=s' => \$delete,
+	    'h|host=s' => \$host);
+
+my $configpath = "$ENV{'HOME'}/.gutenbach";
+
+if (! -e $configpath) {
+    mkdir "$configpath";
+}
+
+# list the existing queues
+if ($list and !$add and !$delete) {
+    my @queues = glob("$configpath/*") or die "Couldn't find configuration files at '$configpath'";
+
+    print "Queue\t\tHost\n";
+    foreach my $q (@queues) {
+	my ($host, $queue);
+
+	if (-r $q) {
+	    local $/;
+	    my $fh;
+	    open $fh, $q;
+	    eval <$fh>;
+	}
+
+	print "$queue\t\t$host\n";
+    }
+}
+
+# add a new queue
+elsif (!$list and $add and !$delete) {
+    if (!$host) {
+	print $usage;
+	exit 1;
+    }
+
+    if (-e "$configpath/$add") {
+	print "Warning: queue '$add' already exists\n";
+    }
+
+    open CONFIG, "> $configpath/$add" or die "Couldn't open config file '$configpath/$add'";
+    print CONFIG "\$host = \"$host\";\n";
+    print CONFIG "\$queue = \"$add\";\n";
+    close CONFIG;
+
+    print "Added queue '$add' on host '$host'\n"
+}
+
+# delete an existing queue
+elsif (!$list and !$add and $delete) {
+    if (! -e "$configpath/$delete") {
+	print "Error: queue '$delete' already exists\n";
+	exit 1;
+    }
+
+    unlink("$configpath/$delete") or die "Couldn't remove config file '$configpath/$delete'";
+}
+
+else {
+    print $usage;
+    exit 1;
+}
Index: gutenbach-itunes-plugin/README
===================================================================
--- gutenbach-itunes-plugin/README	(revision a411a9fcaa6fb77ba124f135279f79fcb52a367d)
+++ gutenbach-itunes-plugin/README	(revision a411a9fcaa6fb77ba124f135279f79fcb52a367d)
@@ -0,0 +1,58 @@
+-----------------
+iTunes -> gutenbach
+-----------------
+This is a simple little script which sends
+music from an iTunes library to the gutenbach
+lpr server.
+
+* Changelog
+29 Nov 2009 -> changed the name from sipbmp3 to gutenbach
+23 Aug 2009 -> broder spun loop into shell script instead of
+    applescript so that iTunes doesn't hang
+9 Jan 2009 -> price added 'quoted form'
+7 Jan 2009 -> kmill created initial version
+
+* System Requirements
+This script will only work under Mac OS X as
+it uses AppleScript.
+
+* Installation
+There are two parts:
+
+1) Launch the Printer Setup Utility and add
+   an IP Printer with the LPD protocol with
+   the following information:
+    Address: hostname
+    Queue: gutenbach
+   It is not necessary to specify the driver.
+
+   *** Note that you MUST give the printer name as the same name as
+       the queue, NOT the address (which it seems to default to). ***
+
+2) Create the directory ~/Library/iTunes/Scripts
+   and place the scripts you want within.
+
+3) Edit those scripts such, replacing "hostname" with the hostname of
+your printer and "gutenbach" with the printername.
+
+* Usage
+When in iTunes, select the songs which you
+would like to hear in the office, and click
+the script you want from the script menu from
+the menu bar.  The script menu looks like a
+little scroll icon.  There will be no
+feedback beyond the pleasant sounds you now
+hear around you.
+
+* Todo
+As it is, there is no feedback, even in the
+event of failure.  This is decidedly not
+optimal.
+
+* And so...
+Do whatever you want with it.  I'd like to
+have a copy if you extend it.
+
+Kyle Miller
+kmill@mit.edu
+
Index: gutenbach-itunes-plugin/gutenbach - Get Queue.applescript
===================================================================
--- gutenbach-itunes-plugin/gutenbach - Get Queue.applescript	(revision e52000947ec07db3b47b94c45736b6ed62a55860)
+++ gutenbach-itunes-plugin/gutenbach - Get Queue.applescript	(revision e52000947ec07db3b47b94c45736b6ed62a55860)
@@ -0,0 +1,21 @@
+-- -----------------
+-- iTunes -> gutenbach
+-- -----------------
+-- This is a simple little script which gets the current queue on gutenbach--
+-- Changelog:
+--
+-- 10 Oct 2009 -> pquimby created this script
+--
+-- Installation:
+-- For installation instructions see the INSTALL file in the snippets/sipbmp3-iTunes folder--
+
+--
+-- Usage:
+--
+-- Run this script from iTunes
+
+set message to (do shell script "lpq -Pgutenbach")
+tell application "iTunes"
+	display dialog "gutenbach currently is playing: " & "
+" & message buttons "OK" default button "OK"
+end tell
Index: gutenbach-itunes-plugin/gutenbach - Queue Music.applescript
===================================================================
--- gutenbach-itunes-plugin/gutenbach - Queue Music.applescript	(revision e52000947ec07db3b47b94c45736b6ed62a55860)
+++ gutenbach-itunes-plugin/gutenbach - Queue Music.applescript	(revision e52000947ec07db3b47b94c45736b6ed62a55860)
@@ -0,0 +1,50 @@
+-- -----------------
+-- iTunes -> gutenbach
+-- -----------------
+-- This is a simple little script which sends
+-- music from an iTunes library to the gutenbach
+-- lpr server.
+--
+-- Changelog:
+--
+-- 23 Aug 2009 -> broder spun loop into shell script instead of
+--     applescript so that iTunes doesn't hang
+-- 9 Jan 2009 -> price added 'quoted form'
+-- 7 Jan 2009 -> kmill created initial version
+--
+-- Installation:
+--
+-- 1) Launch the Printer Setup Utility and add
+--    an IP Printer with the LPD protocol with
+--    the following information:
+--     Address: zygorthian-space-raiders.mit.edu
+--     Queue: gutenbach
+--    It is not necessary to specify the driver.
+--
+-- 2) Create the directory ~/Library/iTunes/Scripts
+--    and place the "Send to gutenbach.scpt" file
+--    within.
+--
+-- Usage:
+--
+-- When in iTunes, select the songs which you
+-- would like to hear in the office, and click
+-- "Send to gutenbach" in the script menu from
+-- the menu bar.  The script menu looks like a
+-- little scroll icon.  There will be no
+-- feedback beyond the pleasant sounds you now
+-- hear around you.
+
+set ts to ""
+
+tell application "iTunes"
+	repeat with t in selection
+		if class of t is (file track) then
+			set loc to POSIX path of (get location of t)
+			set ts to ts & " " & (quoted form of loc)
+		end if
+	end repeat
+end tell
+
+set command to "(for t in " & ts & "; do lpr -o raw -Pgutenbach \"$t\"; done) >/dev/null 2>&1 </dev/null &"
+do shell script command
Index: gutenbach-itunes-plugin/gutenbach - Remove All.applescript
===================================================================
--- gutenbach-itunes-plugin/gutenbach - Remove All.applescript	(revision e52000947ec07db3b47b94c45736b6ed62a55860)
+++ gutenbach-itunes-plugin/gutenbach - Remove All.applescript	(revision e52000947ec07db3b47b94c45736b6ed62a55860)
@@ -0,0 +1,15 @@
+-- ------------------
+-- iTunes -> gutenbach
+-- ------------------
+
+-- Changelog:
+--
+-- 10 Oct 2009 -> pquimby created initial version
+--
+
+-- For installation instructions see the INSTALL file in the snippets/sipbmp3-iTunes folder--
+
+-- Usage:
+--  This script will remove all of your songs queued to gutenbach
+
+do shell script "lprm -Pgutenbach -"
Index: gutenbach-itunes-plugin/gutenbach - Toggle Mute.applescript
===================================================================
--- gutenbach-itunes-plugin/gutenbach - Toggle Mute.applescript	(revision e52000947ec07db3b47b94c45736b6ed62a55860)
+++ gutenbach-itunes-plugin/gutenbach - Toggle Mute.applescript	(revision e52000947ec07db3b47b94c45736b6ed62a55860)
@@ -0,0 +1,20 @@
+-- -----------------
+-- iTunes -> gutenbach
+-- -----------------
+
+-- Changelog:
+-- 10 Nov 2009 -> pquimby created initial version
+
+-- Installation:
+-- For installation instructions see the INSTALL file in the snippets/sipbmp3-iTunes folder--
+
+-- Usage:
+--
+-- Running this script will toggle the mute on gutenbach on or off.
+
+tell application "iTunes"
+	set vol to sound volume
+end tell
+
+set command to "/usr/local/bin/remctl hostname volume set " & vol
+do shell script command
Index: gutenbach-itunes-plugin/gutenbach - Volume Get.applescript
===================================================================
--- gutenbach-itunes-plugin/gutenbach - Volume Get.applescript	(revision e52000947ec07db3b47b94c45736b6ed62a55860)
+++ gutenbach-itunes-plugin/gutenbach - Volume Get.applescript	(revision e52000947ec07db3b47b94c45736b6ed62a55860)
@@ -0,0 +1,20 @@
+-- ------------------
+-- iTunes -> gutenbach
+-- ------------------
+
+-- Changelog:
+--
+-- 10 Oct 2009 -> pquimby created initial version
+--
+
+--For installation instructions see the INSTALL file in the snippets/sipbmp3-iTunes folder
+
+-- Usage:
+--  This script will get the volume of gutenbach and put it on your iTunes volume scaled to the max value of 31 (which is the max volume for gutenbach at the time this script was written).
+
+
+tell application "iTunes"
+	set currentVolume to (do shell script "/usr/local/bin/remctl hostname volume get")
+	set currentVolume to currentVolume / 31 * 100
+	set the sound volume to currentVolume
+end tell
Index: gutenbach-itunes-plugin/gutenbach - Volume Set.applescript
===================================================================
--- gutenbach-itunes-plugin/gutenbach - Volume Set.applescript	(revision e52000947ec07db3b47b94c45736b6ed62a55860)
+++ gutenbach-itunes-plugin/gutenbach - Volume Set.applescript	(revision e52000947ec07db3b47b94c45736b6ed62a55860)
@@ -0,0 +1,16 @@
+-- Changelog:
+--
+-- 5 April 2009 -> pquimby created initial version
+--
+
+-- Usage:
+--  This script will set the volume of gutenbach (assuming you have remctl) to your iTunes volume scaled to the max value of 31 (which is the max volume for gutenbach at the time this script was written).
+
+-- Ex:// If your iTunes volume is set at 50% then you will set the gutenbach volume to .50*31 or roughly 15.
+
+tell application "iTunes"
+	set vol to (sound volume * 31 / 100)
+end tell
+
+set command to "/usr/local/bin/remctl hostname volume set " & vol
+do shell script command
Index: gutenbach-queue/README
===================================================================
--- gutenbach-queue/README	(revision 4333c72d20cc2519729ff7e0a71e54c7872a0a1d)
+++ gutenbach-queue/README	(revision 4333c72d20cc2519729ff7e0a71e54c7872a0a1d)
@@ -0,0 +1,10 @@
+gutenbach-queue is a package which provides a program to display the
+live queue for the Gutenbach Music Spooler.
+
+Questions and comments should be directed to gutenbach@mit.edu
+
+TODO:
+- figure out why it always displays : '' by '' as the last item in the
+  queue
+- do something smart about there being multiple daemons running?
+- be more efficient
Index: gutenbach-queue/lib/build-gutenbach-queue
===================================================================
--- gutenbach-queue/lib/build-gutenbach-queue	(revision e87e682008b20061e88abcb383650485c76c3f88)
+++ gutenbach-queue/lib/build-gutenbach-queue	(revision e87e682008b20061e88abcb383650485c76c3f88)
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+if [ -e /var/run/gutenbach/current_queue_temp ]; then
+    rm /var/run/gutenbach/current_queue_temp
+fi
+
+while true; do
+    time=$(date)
+    echo "This is a work in progress!  Please send bugs to jhamrick." >> /var/run/gutenbach/current_queue_temp
+    echo ""
+    echo "As of $time:" >> /var/run/gutenbach/current_queue_temp
+    /usr/lib/gutenbach/queue/queue >> /var/run/gutenbach/current_queue_temp
+    mv /var/run/gutenbach/current_queue_temp /var/run/gutenbach/current_queue
+    chmod ugoa+r /var/run/gutenbach/current_queue
+done
Index: gutenbach-queue/lib/kill-gutenbach-queue
===================================================================
--- gutenbach-queue/lib/kill-gutenbach-queue	(revision e87e682008b20061e88abcb383650485c76c3f88)
+++ gutenbach-queue/lib/kill-gutenbach-queue	(revision e87e682008b20061e88abcb383650485c76c3f88)
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+echo "Stopping view-gutenbach-queue..."
+killall -q "/usr/lib/gutenbach/queue/view-gutenbach-queue"
+echo "Stopping build-gutenbach-queue..."
+killall -q "/usr/lib/gutenbach/queue/build-gutenbach-queue"
+echo "Stopping queue..."
+killall -q "/usr/lib/gutenbach/queue/queue"
+echo "Stopping exiftool..."
+killall -q "/usr/bin/exiftool"
+echo "Stopping watch..."
+killall -q "/usr/bin/watch"
+echo "Done."
Index: gutenbach-queue/lib/queue
===================================================================
--- gutenbach-queue/lib/queue	(revision e87e682008b20061e88abcb383650485c76c3f88)
+++ gutenbach-queue/lib/queue	(revision e87e682008b20061e88abcb383650485c76c3f88)
@@ -0,0 +1,59 @@
+#!/bin/bash
+
+found_current=
+
+if [ -e "/var/run/gutenbach/queue_times" ]; then
+    rm "/var/run/gutenbach/queue_times"
+fi
+
+if [ -e /usr/lib/gutenbach/config/printername ]; then
+    printername=$(cat /usr/lib/gutenbach/config/printername)
+
+    cd /var/spool/lpd/"$printername"/
+    for i in $(ls . | grep ^hf); do
+	done=$(cat "$i" | grep done)
+    if [ ! -n "$done" ]; then
+	timestamp=$(cat "$i" | grep ^job_time= | sed 's/.*=//')
+	echo "$timestamp:$i" >> /var/run/gutenbach/queue_times
+    fi
+    done
+
+    if [ -e /var/run/gutenbach/queue_times ]; then
+	for i in $(sort /var/run/gutenbach/queue_times); do
+	    i=$(echo "$i" | sed 's/.*://')
+	    prefix="df"${i:2}
+	    for j in "$prefix"*; do song="$j"; done
+
+	    user=$(cat "$i" | grep ^P=)
+	    user=${user:2}
+	    
+	    if [ -e /var/run/gutenbach/exiftool_data ]; then
+		rm /var/run/gutenbach/exiftool_data
+	    fi
+
+	    exiftool "$song" >> /var/run/gutenbach/exiftool_data
+	    title=$(cat /var/run/gutenbach/exiftool_data | grep "^Title " | sed 's/.*: //')
+	    artist=$(cat /var/run/gutenbach/exiftool_data | grep "^Artist " | sed 's/.*: //')
+
+	    if [ -z "$found_current" ]; then
+		host=$(cat "$i" | grep ^H=)
+		host=${host:2}
+		filenm="$(cat $i | grep "^filenames" | sed -e 's/filenames=//')"
+		album=$(cat /var/run/gutenbach/exiftool_data | grep "^Album " | sed 's/.*: //')
+		echo "$user@$host is currently playing: "
+		echo "$filenm"
+		echo "'$title'"
+		echo "by '$artist'"
+		echo "on '$album'"
+		echo ""
+		echo "Coming up in the queue:"
+		found_current="true" 
+	    else
+		echo "$user: '$title' by '$artist'"
+	    fi
+	done
+    fi
+else
+    echo "Error: Printer name configuration file /usr/lib/gutenbach/config/printername does not exist!"
+    exit 1
+fi
Index: gutenbach-queue/lib/view-gutenbach-queue
===================================================================
--- gutenbach-queue/lib/view-gutenbach-queue	(revision e87e682008b20061e88abcb383650485c76c3f88)
+++ gutenbach-queue/lib/view-gutenbach-queue	(revision e87e682008b20061e88abcb383650485c76c3f88)
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+daemon --running --name gutenbach-queue -F /var/run/gutenbach/gutenbach-queue.pid
+if [ "$?" == 0 ]; then
+    setterm -blank 0
+    watch -t -n 1 cat /var/run/gutenbach/current_queue
+else
+    echo "The gutenbach queue daemon is not running.  Please start it at /etc/init.d/gutenbach-queue."
+fi
Index: gutenbach-remctl/README
===================================================================
--- gutenbach-remctl/README	(revision cc0d7053781e98c7ca1c2ab048d9941ddb3866c0)
+++ gutenbach-remctl/README	(revision cc0d7053781e98c7ca1c2ab048d9941ddb3866c0)
@@ -0,0 +1,10 @@
+gutenbach-remctl is a package which provides a remctl configuration,
+enabling users to remotely adjust settings such as volume.
+
+Questions and comments should be directed to gutenbach@mit.edu
+
+TODO:
+- need to add logging to see what's going wrong if a command fails
+- figure out how to determine the correct channel/mixer
+- better yet, figure out how to use pulse, and don't have to worry
+  about what the correct channel or mixer is at all
Index: gutenbach-remctl/cd
===================================================================
--- gutenbach-remctl/cd	(revision 53936a5ce93f322effc45c0b2fadff6a4d0478ec)
+++ gutenbach-remctl/cd	(revision 53936a5ce93f322effc45c0b2fadff6a4d0478ec)
@@ -0,0 +1,3 @@
+cd cddb     /usr/lib/gutenbach/remctl/cd-cddb     ANYUSER
+cd cddb-get /usr/lib/gutenbach/remctl/cd-cddb-get ANYUSER
+cd play     /usr/lib/gutenbach/remctl/cd-play     ANYUSER
Index: gutenbach-remctl/cd-cddb
===================================================================
--- gutenbach-remctl/cd-cddb	(revision 6bb3ffb249dc254896b2f89be72367ae76fad5e9)
+++ gutenbach-remctl/cd-cddb	(revision 6bb3ffb249dc254896b2f89be72367ae76fad5e9)
@@ -0,0 +1,20 @@
+#!/bin/sh
+PATH="$(dirname $0):$PATH"
+
+die () {
+    echo "$@";
+    exit 1;
+}
+
+CACHE=$(cd-cddb-get) || die "Unable to fetch CDDB information."
+
+. "$CACHE"
+
+echo "Artist: $DARTIST";
+echo "Album: $DALBUM";
+echo "Tracks: $TRACKS";
+
+for i in $(seq 1 $TRACKS); do
+    echo -n "Track $i: "
+    eval 'echo $TRACK'$i
+done
Index: gutenbach-remctl/cd-cddb-get
===================================================================
--- gutenbach-remctl/cd-cddb-get	(revision 53936a5ce93f322effc45c0b2fadff6a4d0478ec)
+++ gutenbach-remctl/cd-cddb-get	(revision 53936a5ce93f322effc45c0b2fadff6a4d0478ec)
@@ -0,0 +1,37 @@
+#!/bin/sh
+PATH="$(dirname $0):$PATH"
+
+CDDBURL="http://freedb.freedb.org/~cddb/cddb.cgi"
+MYUSER="gutenbach"
+MYHOST=`hostname`".mit.edu"
+
+DISCID=$(cd-discid /dev/cdrom 2>/dev/null) || exit 1
+
+set -- $DISCID
+
+ID="$1"
+TRACKS="$2"
+
+mkdir -p /var/cache/gutenbach
+
+CACHEFILE="/var/cache/gutenbach/$ID"
+
+if [ ! -e "$CACHEFILE" ]; then
+
+    CD=$(cddb-tool query "$CDDBURL" 3 "$MYUSER" "$MYHOST" $DISCID) \
+	|| exit 2;
+
+    file=$(tempfile)
+
+    cddb-tool read "$CDDBURL" 3 "$MYUSER" "$MYHOST" \
+	$(echo "$CD" | head -1 | awk '{print $2 " " $3}') > "$file"  \
+	|| exit 3;
+
+    echo "TRACKS=$TRACKS"   >  "$CACHEFILE"
+    cddb-tool parse "$file" >> "$CACHEFILE"
+
+    rm "$file"
+fi
+
+echo "$CACHEFILE"
+exit 0;
Index: gutenbach-remctl/cd-play
===================================================================
--- gutenbach-remctl/cd-play	(revision 53936a5ce93f322effc45c0b2fadff6a4d0478ec)
+++ gutenbach-remctl/cd-play	(revision 53936a5ce93f322effc45c0b2fadff6a4d0478ec)
@@ -0,0 +1,37 @@
+#!/bin/sh
+PATH="$(dirname $0):$PATH"
+
+CDDB=
+
+CACHE=$(cd-cddb-get)
+
+printername=$(/usr/lib/gutenbach/gutenbach-get-config queue)
+
+if [ "$?" = 0 ]; then
+    CDDB=1
+fi
+
+. "$CACHE"
+
+play_one () {
+    T=$1
+    if [ -n "$CDDB" ]; then
+	DESC=" - "$(eval 'echo $TRACK'$T)
+    fi
+
+    echo "cdda://$(($T - 1))" | mit-lpr -P"$queue"@localhost -J "Track $T$DESC";
+    echo "Queued Track $T$DESC";
+}
+
+TOPLAY="$2"
+
+if [ -z "$TOPLAY" -o "$TOPLAY" = "all" ]; then
+    for i in $(seq 1 "$TRACKS"); do
+	play_one $i
+    done
+else
+    shift;
+    for i in "$@"; do
+	play_one $i
+    done
+fi
Index: gutenbach-remctl/status
===================================================================
--- gutenbach-remctl/status	(revision 53936a5ce93f322effc45c0b2fadff6a4d0478ec)
+++ gutenbach-remctl/status	(revision 53936a5ce93f322effc45c0b2fadff6a4d0478ec)
@@ -0,0 +1,2 @@
+status get   /usr/lib/gutenbach/remctl/status-get   ANYUSER
+status clear /usr/lib/gutenbach/remctl/status-clear ANYUSER
Index: gutenbach-remctl/status-clear
===================================================================
--- gutenbach-remctl/status-clear	(revision 53936a5ce93f322effc45c0b2fadff6a4d0478ec)
+++ gutenbach-remctl/status-clear	(revision 53936a5ce93f322effc45c0b2fadff6a4d0478ec)
@@ -0,0 +1,3 @@
+#!/bin/sh
+PATH="$(dirname $0):$PATH"
+> /var/run/gutenbach/status
Index: gutenbach-remctl/status-get
===================================================================
--- gutenbach-remctl/status-get	(revision 53936a5ce93f322effc45c0b2fadff6a4d0478ec)
+++ gutenbach-remctl/status-get	(revision 53936a5ce93f322effc45c0b2fadff6a4d0478ec)
@@ -0,0 +1,3 @@
+#!/bin/sh
+PATH="$(dirname $0):$PATH"
+cat /var/run/gutenbach/status
Index: gutenbach-remctl/voldaemon.c
===================================================================
--- gutenbach-remctl/voldaemon.c	(revision 9c6635060a1adeb1457077d8413e99210ccd878d)
+++ gutenbach-remctl/voldaemon.c	(revision 9c6635060a1adeb1457077d8413e99210ccd878d)
@@ -0,0 +1,319 @@
+/*
+ * $Id: voldaemon.c,v 1.1 2008-09-27 08:49:10 root Exp $
+ * $Source: /tmp/tmp.UFBNno9997/RCS/voldaemon.c,v $
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <assert.h>
+#include <netinet/in.h>
+
+
+#define LISTEN_PORT 8930
+#define MULTI_PORT 8931
+#define MULTI_ADDR "224.0.1.20"
+
+/* Block queries from off this subnet net 18.*/
+#define OUR_SUBNET      187
+
+typedef struct volmessage{
+  char A;
+  char request;
+  char value;
+  unsigned char ip_3;
+  unsigned char ip_2;
+  unsigned char ip_1;
+  unsigned char ip_0;
+  char ZE;
+} volmessage;
+
+#define MESSAGE_SIZE (sizeof(volmessage))
+
+/* The client makes requests using the following packets.  Responses
+   to queries and status reports from the server follow the same
+   pattern
+
+  Request/Response
+
+  'AVxiiiiZ'     Volume
+  'AMxiiiiZ'     Mute
+  'AQQiiiiZ'     Query 
+
+  Response Only
+  'AVeiiiiE'     Volume Set Error 
+  'AMeiiiiE'     Mute Set Error 
+  'AEeiiiiE'     Unknown error 
+
+   e=1  Permission denied (invalid IP)
+   e=2  Invalid request (Bad Packet)
+   
+*/
+
+void message(char *m){
+  write(STDERR_FILENO,m,strlen(m));
+}
+
+void abortm(char *m){
+  message(m);
+  message("Errno = ");
+  message(strerror(errno));
+  message("\n");
+  exit(1);
+}
+
+struct in_addr multiaddr={0};
+
+int multicast(volmessage *m){
+  static int sockfd=-1;
+  static struct sockaddr_in dest;
+  int destlen=sizeof(dest);
+
+  if(sockfd==-1)
+    if((sockfd=socket(AF_INET,SOCK_DGRAM,0))<0)
+      abortm("Could not open multicast socket\n");
+
+  if(multiaddr.s_addr==0)
+    multiaddr.s_addr = inet_addr(MULTI_ADDR);
+      /*inet_aton(MULTI_ADDR,&multiaddr);*/
+
+  memset(&dest,0,sizeof(dest));
+  dest.sin_family=AF_INET;
+  dest.sin_addr.s_addr=multiaddr.s_addr;
+  dest.sin_port=htons(MULTI_PORT);
+
+  if(sendto(sockfd,m,MESSAGE_SIZE,0,(struct sockaddr *)&dest,destlen)<0){
+    message("Multicast send error\n");
+    return(1);
+  }
+  return(0);
+}
+
+int sockfd=-1,volfd;
+static struct sockaddr_in me,you;
+static int youlen=sizeof(you);
+struct in_addr multiaddr;
+
+int opensock(){
+  if((sockfd=socket(AF_INET,SOCK_DGRAM,0))<0)
+    abortm("Could not open listen socket\n");
+
+  memset(&me,0,sizeof(me));
+  me.sin_family=AF_INET;
+  me.sin_addr.s_addr=htonl(INADDR_ANY);
+  me.sin_port=htons(LISTEN_PORT);
+
+  if(bind(sockfd,(struct sockaddr *)&me,sizeof(me))<0)
+    abortm("Could not bind to listen port\n");
+
+  listen(sockfd,5);
+  return(sockfd);
+}
+
+/*  -1 blocks
+    0  nonblocking
+    +n timeout 
+*/
+
+int
+fetch (int usec, volmessage *m) {
+  fd_set fdset;
+  int retval;
+  struct timeval tv;
+  if(sockfd==-1)
+    opensock();
+
+  FD_ZERO(&fdset);
+  FD_SET(sockfd, &fdset);
+
+  tv.tv_sec = 0;
+  tv.tv_usec = usec;
+  retval = select(sockfd+1,
+		  &fdset, NULL, NULL,
+		  ((usec == -1) ? NULL : &tv));
+  if (retval == 1) {
+    /* Select got us a single descriptor to play with, as we
+     * expected. Pull a message from it. */
+    int youlen = sizeof(you);
+    retval = recvfrom(sockfd,
+		      m, MESSAGE_SIZE,
+		      0,
+		      (struct sockaddr *)&you, &youlen);
+    if(retval < MESSAGE_SIZE || m->A != 'A' || m->ZE != 'Z') {
+      message("Packet receive error\n");
+      return(0);
+    } else {
+      return(1);
+    }
+  } else {
+    if (retval == 0) {
+      /* This means the timeout finished. */
+    } else if (retval == -1) {
+      fprintf(stderr, "Select error. errno = %d (%s).\n",
+	      errno, strerror(errno));
+    } else {
+      fprintf(stderr, "Select returned unexpected value %d.\n", retval);
+    }
+    /* Whatever error we get, we just return 0. */
+    return(0);
+  }
+}
+
+
+int
+reply (volmessage *m) {
+  int retval;
+  assert(sockfd != -1);
+  
+  retval = sendto(sockfd,
+		  m, MESSAGE_SIZE,
+		  0,
+		  (struct sockaddr *)&you, youlen);
+  if(retval < 0){
+    message("Reply error\n");
+    return(1);
+  }
+  return(0);
+}
+  
+int vol_iterate(int newval){
+  static int val=0;
+  char command[100];
+  
+
+  if (val==newval)
+    return(0);
+
+  if (val<newval) {
+    val+=8;
+    if(val>newval)
+      val=newval;
+  } else {
+    val-=8;
+    if(val<newval)
+      val=newval;
+  }
+  sprintf(command,"/usr/bin/aumix -v %d",val);
+  fprintf(stderr,"Setting volume to %d\n",val);
+  system(command);
+  return(1);
+}
+
+int main(){
+  unsigned char volume=32,mute=0,ip_3=0,ip_2=0,ip_1=0,ip_0=0;
+  int messagestatus=1,volstatus=1;
+  volmessage m;
+
+  system("/usr/bin/aumix -v 0");
+  system("/usr/bin/aumix -i 100");
+  system("/usr/bin/aumix -l 100");
+
+  message("\nSIPB volume daemon running\n");
+
+  /* We want to process messages quickly, then get to the business of
+     controlling ther hardware when no messages are in the queue. 
+     The select on the message fetch also does our timing for volume
+     iteration */
+
+  while(1){
+    if(messagestatus==1)
+      /* Messages likely pending.  Process quickly */
+      messagestatus=fetch(0,&m);
+    else
+      if(volstatus==1){
+	/* No messages, but volume to be updated */
+	messagestatus=fetch(50,&m);
+	if(messagestatus==0)volstatus=vol_iterate(mute?0:volume);
+      }else{
+	/* Steady state.  Wait (almost) forever until a message */
+	m.ip_0=ip_0;
+	m.ip_1=ip_1;
+	m.ip_2=ip_2;
+	m.ip_3=ip_3;
+	m.A='A';
+	m.request='V';
+	m.value=volume;
+	m.ZE='Z';
+    	multicast(&m);
+	m.A='A';
+	m.request='M';
+	m.value=mute;
+	m.ZE='Z';
+    	multicast(&m);
+	messagestatus=fetch(400000,&m);
+      }
+
+    if(messagestatus){
+      int error=0;
+      m.ip_3=(ntohl(you.sin_addr.s_addr)>>24)&0xff;
+      m.ip_2=(ntohl(you.sin_addr.s_addr)>>16)&0xff;
+      m.ip_1=(ntohl(you.sin_addr.s_addr)>>8)&0xff;
+      m.ip_0=ntohl(you.sin_addr.s_addr)&0xff;
+
+      if(m.ip_3!=18 || m.ip_2!=OUR_SUBNET){
+	error=1;
+      }
+
+      switch(m.request){
+      case 'V':
+	if(error){
+	  m.value=error;
+	  m.ZE='E';
+	  reply(&m);
+	  message("Request from off subnet rejected\n");
+	}else{
+	  ip_0=m.ip_0;
+	  ip_1=m.ip_1;
+	  ip_2=m.ip_2;
+	  ip_3=m.ip_3;
+	  volume=m.value;
+	  reply(&m);
+	  multicast(&m);
+	  volstatus=1;
+	}
+	break;
+      case 'M':
+	if(error){
+	  m.value=error;
+	  m.ZE='E';
+	  reply(&m);	  
+	  message("Request from off subnet rejected\n");
+	}else{
+	  ip_0=m.ip_0;
+	  ip_1=m.ip_1;
+	  ip_2=m.ip_2;
+	  ip_3=m.ip_3;
+	  mute=(m.value?1:0);
+	  m.value=mute;
+	  reply(&m);
+	  multicast(&m);
+	  volstatus=1;
+	}
+	break;
+      case 'Q':
+	m.ip_0=ip_0;
+	m.ip_1=ip_1;
+	m.ip_2=ip_2;
+	m.ip_3=ip_3;
+	m.request='V';
+	m.value=volume;
+	reply(&m);
+	m.request='M';
+	m.value=mute;
+	reply(&m);
+	break;
+      default:
+	reply((volmessage *)"AE20000E");
+	break;
+      }
+    }
+  }
+}
Index: gutenbach-remctl/volume
===================================================================
--- gutenbach-remctl/volume	(revision 53936a5ce93f322effc45c0b2fadff6a4d0478ec)
+++ gutenbach-remctl/volume	(revision 53936a5ce93f322effc45c0b2fadff6a4d0478ec)
@@ -0,0 +1,25 @@
+volume set  /usr/lib/gutenbach/remctl/volume-set	 ANYUSER 
+volume get  /usr/lib/gutenbach/remctl/volume-get    ANYUSER
+volume show /usr/lib/gutenbach/remctl/volume-show   ANYUSER
+volume mute /usr/lib/gutenbach/remctl/volume-mute   ANYUSER 
+volume up   /usr/lib/gutenbach/remctl/volume-up     ANYUSER 
+volume down /usr/lib/gutenbach/remctl/volume-down   ANYUSER 
+volume is-muted /usr/lib/gutenbach/remctl/volume-is-muted   ANYUSER 
+
+v set  /usr/lib/gutenbach/remctl/volume-set    ANYUSER 
+v get  /usr/lib/gutenbach/remctl/volume-get    ANYUSER
+v show /usr/lib/gutenbach/remctl/volume-show   ANYUSER
+v mute /usr/lib/gutenbach/remctl/volume-mute   ANYUSER 
+v up   /usr/lib/gutenbach/remctl/volume-up     ANYUSER 
+v down /usr/lib/gutenbach/remctl/volume-down   ANYUSER 
+v is-muted /usr/lib/gutenbach/remctl/volume-is-muted   ANYUSER 
+
+v u /usr/lib/gutenbach/remctl/volume-up   ANYUSER
+v d /usr/lib/gutenbach/remctl/volume-down ANYUSER
+
+volume u /usr/lib/gutenbach/remctl/volume-up   ANYUSER
+volume d /usr/lib/gutenbach/remctl/volume-down ANYUSER
+
+volume help /usr/lib/gutenbach/remctl/volume-help ANYUSER
+v      help /usr/lib/gutenbach/remctl/volume-help ANYUSER
+help   ALL  /usr/lib/gutenbach/remctl/volume-help ANYUSER
Index: gutenbach-remctl/volume-down
===================================================================
--- gutenbach-remctl/volume-down	(revision 6bb3ffb249dc254896b2f89be72367ae76fad5e9)
+++ gutenbach-remctl/volume-down	(revision 6bb3ffb249dc254896b2f89be72367ae76fad5e9)
@@ -0,0 +1,3 @@
+#!/bin/sh
+PATH="$(dirname $0):$PATH"
+volume-set . $(( $(volume-get .) - 1 ))
Index: gutenbach-remctl/volume-get
===================================================================
--- gutenbach-remctl/volume-get	(revision 53936a5ce93f322effc45c0b2fadff6a4d0478ec)
+++ gutenbach-remctl/volume-get	(revision 53936a5ce93f322effc45c0b2fadff6a4d0478ec)
@@ -0,0 +1,8 @@
+#!/bin/sh
+PATH="$(dirname $0):$PATH"
+
+mixer=$(/usr/lib/gutenbach/gutenbach-get-config mixer)
+channel=$(/usr/lib/gutenbach/gutenbach-get-config channel)
+
+amixer get $mixer | grep "$channel" \
+ | perl -lne 'print $1 if (/: Playback ([0-9]+)/)'
Index: gutenbach-remctl/volume-help
===================================================================
--- gutenbach-remctl/volume-help	(revision 6bb3ffb249dc254896b2f89be72367ae76fad5e9)
+++ gutenbach-remctl/volume-help	(revision 6bb3ffb249dc254896b2f89be72367ae76fad5e9)
@@ -0,0 +1,15 @@
+#!/bin/bash
+PATH="$(dirname $0):$PATH"
+cat <<EOF
+Usage: remctl zsr.mit.edu <command> <subcommand> [..args..]
+Commands:
+  volume up        - increment volume
+  volume down      - decrement volume
+  volume get       - get volume
+  volume set [vol] - set volume, in range 0..31
+  volume mute      - zero volume
+  volume help,
+   help <anything> - print this help
+
+'v', 'u', 'd' abbreviate 'volume', 'up', 'down' respectively.
+EOF
Index: gutenbach-remctl/volume-is-muted
===================================================================
--- gutenbach-remctl/volume-is-muted	(revision 53936a5ce93f322effc45c0b2fadff6a4d0478ec)
+++ gutenbach-remctl/volume-is-muted	(revision 53936a5ce93f322effc45c0b2fadff6a4d0478ec)
@@ -0,0 +1,17 @@
+#!/bin/sh
+PATH="$(dirname $0):$PATH"
+
+mixer=$(/usr/lib/gutenbach/gutenbach-get-config mixer)
+channel=$(/usr/lib/gutenbach/gutenbach-get-config channel)
+
+volstat=$(amixer get $mixer | grep "$channel" \
+ | perl -lne 'print $1 if (/: Playback .*\[(on|off)\]$/)'
+)
+
+case "$volstat" in 
+    on)  result=unmuted;;
+    off) result=muted;;
+    *)   result=unknown;;
+esac
+
+echo $result
Index: gutenbach-remctl/volume-mute
===================================================================
--- gutenbach-remctl/volume-mute	(revision 53936a5ce93f322effc45c0b2fadff6a4d0478ec)
+++ gutenbach-remctl/volume-mute	(revision 53936a5ce93f322effc45c0b2fadff6a4d0478ec)
@@ -0,0 +1,10 @@
+#!/bin/sh
+PATH="$(dirname $0):$PATH"
+
+mixer=$(/usr/lib/gutenbach/gutenbach-get-config mixer)
+channel=$(/usr/lib/gutenbach/gutenbach-get-config channel)
+
+amixer set $mixer toggle > /dev/null
+volume-is-muted
+
+volume-zephyr
Index: gutenbach-remctl/volume-set
===================================================================
--- gutenbach-remctl/volume-set	(revision 53936a5ce93f322effc45c0b2fadff6a4d0478ec)
+++ gutenbach-remctl/volume-set	(revision 53936a5ce93f322effc45c0b2fadff6a4d0478ec)
@@ -0,0 +1,10 @@
+#!/bin/sh
+PATH="$(dirname $0):$PATH"
+
+mixer=$(/usr/lib/gutenbach/gutenbach-get-config mixer)
+channel=$(/usr/lib/gutenbach/gutenbach-get-config channel)
+
+amixer set $mixer "$2" | grep "$channel" \
+ | perl -lne 'print $1 if (/: Playback ([0-9]+)/)'
+
+volume-zephyr
Index: gutenbach-remctl/volume-show
===================================================================
--- gutenbach-remctl/volume-show	(revision 53936a5ce93f322effc45c0b2fadff6a4d0478ec)
+++ gutenbach-remctl/volume-show	(revision 53936a5ce93f322effc45c0b2fadff6a4d0478ec)
@@ -0,0 +1,7 @@
+#!/bin/sh
+PATH="$(dirname $0):$PATH"
+
+mixer=$(/usr/lib/gutenbach/gutenbach-get-config mixer)
+channel=$(/usr/lib/gutenbach/gutenbach-get-config channel)
+
+amixer get $mixer
Index: gutenbach-remctl/volume-up
===================================================================
--- gutenbach-remctl/volume-up	(revision 6bb3ffb249dc254896b2f89be72367ae76fad5e9)
+++ gutenbach-remctl/volume-up	(revision 6bb3ffb249dc254896b2f89be72367ae76fad5e9)
@@ -0,0 +1,3 @@
+#!/bin/sh
+PATH="$(dirname $0):$PATH"
+volume-set . $(( $(volume-get .) + 1 ))
Index: gutenbach-remctl/volume-zephyr
===================================================================
--- gutenbach-remctl/volume-zephyr	(revision 4c91fc6e62ec5d8ebeb5fdf1c2ac40118489f184)
+++ gutenbach-remctl/volume-zephyr	(revision 4c91fc6e62ec5d8ebeb5fdf1c2ac40118489f184)
@@ -0,0 +1,28 @@
+#!/bin/sh
+PATH="$(dirname $0):$PATH"
+class=$(/usr/lib/gutenbach/gutenbach-get-config zephyr-class)
+host=$(/usr/lib/gutenbach/gutenbach-get-config host)
+queue=$(/usr/lib/gutenbach/gutenbach-get-config queue)
+instance="$queue-volume@$host"
+
+mixer=$(/usr/lib/gutenbach/gutenbach-get-config mixer)
+channel=$(/usr/lib/gutenbach/gutenbach-get-config channel)
+
+echo "Class: $class" >> /tmp/gutenbach-remctl.log
+echo "Host: $host" >> /tmp/gutenbach-remctl.log
+echo "Queue: $queue" >> /tmp/gutenbach-remctl.log
+echo "Instance: $instance" >> /tmp/gutenbach-remctl.log
+echo "Mixer: $mixer" >> /tmp/gutenbach-remctl.log
+echo "Channel: $channel" >> /tmp/gutenbach-remctl.log
+
+muted=$(volume-is-muted)
+mute_str=" [$muted]"
+if [ "$muted" = "unmuted" ]; then
+    mute_str=""
+fi
+
+start-stop-daemon --stop --oknodo --pidfile /usr/lib/gutenbach/gutenbach-zephyr >/dev/null 2>&1
+start-stop-daemon --start --pidfile /usr/lib/gutenbach/gutenbach-zephyr --make-pidfile --background --exec /bin/sh -- -c "sleep 10 && zwrite -c $class -i $instance -d -n -m 'volume changed to $(volume-get)$mute_str' > /dev/null" >/dev/null 2>&1
+
+echo "sleep 10 && zwrite -c $class -i $instance -d -n -m 'volume changed to $(volume-get)$mute_str' > /dev/null" >> /tmp/gutenbach-remctl.log
+echo "" >> /tmp/gutenbach-remctl.log
Index: gutenbach-rhythmbox-plugin/README
===================================================================
--- gutenbach-rhythmbox-plugin/README	(revision 5224c0758df7bd0ad87826cab8999d99c420d5af)
+++ gutenbach-rhythmbox-plugin/README	(revision 5224c0758df7bd0ad87826cab8999d99c420d5af)
@@ -0,0 +1,23 @@
+This is a plugin for the Rhythmbox music player, which enables
+Gutenbach users to easily queue music.
+
+Plugin written by Nimrod Gileadi, copyright 2010.
+
+Questions or comments should be directed at gutenbach@mit.edu
+
+INSTALLATION:
+
+1) Move the folder 'pikamp3' and its contents to
+~/.gnome2/rhythmbox/plugins/.  You will have to edit __init.py__,
+replacing "printername" and "hostname" with the desired values (e.g.,
+"sipbmp3" and "zsr.mit.edu").
+
+2) Open rhythmbox, and navigate the 'Edit' menu.  Select 'Plugins'.
+
+3) Check the box next to 'gutenbach'.
+
+4) To queue a song/songs, highlight them, and right click and select
+'Send to gutenbach'.
+
+TODO:
+- turn this into a debian package to auto generate the config file
Index: gutenbach-rhythmbox-plugin/__init__.py
===================================================================
--- gutenbach-rhythmbox-plugin/__init__.py	(revision 61c50434af4f740357ebd00742384ea7fddd18d3)
+++ gutenbach-rhythmbox-plugin/__init__.py	(revision 61c50434af4f740357ebd00742384ea7fddd18d3)
@@ -0,0 +1,69 @@
+"""
+This module implements a Rhythmbox plugin that sends selected track to a
+printer queue. It's meant to be used with gutenbach, a music spooling printer
+server.
+
+The plugin uses lpr to send the files to gutenbach.
+"""
+import gtk
+import rb
+import subprocess
+import urllib
+import urlparse
+
+# UI Change is an extra item added to right-click menu when clicking on tracks
+popup_ui = """
+<ui> 
+  <popup name="BrowserSourceViewPopup"> 
+    <menuitem name="Gutenbach" action="SendToGutenbach"/>
+  </popup>
+</ui>
+"""
+class GutenbachPlugin(rb.Plugin):
+    def __init__(self):
+        rb.Plugin.__init__(self)
+
+    def activate(self, shell):
+        """Adds a new item to the right-click menu which allows
+        sending music files to the gutenbach server.
+        """
+        self.shell = shell
+        # Create action for sending a track to gutenbach
+        action = gtk.Action('SendToGutenbach', _('Send to gutenbach'),
+                _("Queue selected tracks to the gutenbach server."),
+                "")
+        action.connect('activate', self.gutenbach_action, shell)
+        action_group = gtk.ActionGroup('GutenbachActionGroup')
+        action_group.add_action(action)
+        manager = shell.get_ui_manager()
+        manager.insert_action_group(action_group)
+        manager.add_ui_from_string(popup_ui)
+
+        # Default configuration options
+        self.printer = "printername"
+        self.printer_host = "hostname"
+
+    def deactivate(self, shell):
+        del self.shell
+
+    def gutenbach_action(self, action, shell):
+        """An action called when the user clicks the right-click menu item
+        to send a track to gutenbach.
+        This function calls an instance of lpr for each file to be added.
+        """
+        source = shell.get_property("selected-source")
+        # For each track currently selected in the song browser
+        for entry in source.get_entry_view().get_selected_entries():
+            # Only play files that are stored on the user's computer
+            uri = entry.get_playback_uri()
+            p = urlparse.urlparse(urllib.unquote(uri))
+            if p.scheme == "file":
+                path = p.path
+                if self.printer_host:
+                    printer = '@'.join([self.printer, self.printer_host])
+                else:
+                    printer = self.printer
+                command = 'lpr -P %s "%s"' % (printer, path)
+                print "About to run command '%s'" % command
+                subprocess.Popen(command, shell=True)
+
Index: gutenbach-rhythmbox-plugin/gutenbach-prefs.ui
===================================================================
--- gutenbach-rhythmbox-plugin/gutenbach-prefs.ui	(revision 0159c0a25905932d89659336d73d160f46a6b9f1)
+++ gutenbach-rhythmbox-plugin/gutenbach-prefs.ui	(revision 0159c0a25905932d89659336d73d160f46a6b9f1)
@@ -0,0 +1,115 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy project-wide -->
+  <object class="GtkDialog" id="gutenbach-prefs">
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">gutenbach Configuration</property>
+    <property name="type_hint">dialog</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child>
+          <object class="GtkVBox" id="vbox1">
+            <property name="visible">True</property>
+            <property name="orientation">vertical</property>
+            <child>
+              <object class="GtkVBox" id="vbox2">
+                <property name="visible">True</property>
+                <property name="orientation">vertical</property>
+                <child>
+                  <object class="GtkLabel" id="printer_label">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">Printer name:</property>
+                  </object>
+                  <packing>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkEntry" id="printer_entry">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="invisible_char">&#x25CF;</property>
+                    <property name="text" translatable="yes">pikamp3</property>
+                  </object>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkVBox" id="vbox3">
+                <property name="visible">True</property>
+                <property name="orientation">vertical</property>
+                <child>
+                  <object class="GtkLabel" id="host_label">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">Printer host:</property>
+                  </object>
+                  <packing>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkEntry" id="host_entry">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="invisible_char">&#x25CF;</property>
+                  </object>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="OK">
+                <property name="label" translatable="yes">OK</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="0">OK</action-widget>
+    </action-widgets>
+  </object>
+</interface>
Index: gutenbach-rhythmbox-plugin/gutenbach.rb-plugin
===================================================================
--- gutenbach-rhythmbox-plugin/gutenbach.rb-plugin	(revision 0159c0a25905932d89659336d73d160f46a6b9f1)
+++ gutenbach-rhythmbox-plugin/gutenbach.rb-plugin	(revision 0159c0a25905932d89659336d73d160f46a6b9f1)
@@ -0,0 +1,7 @@
+[RB Plugin]
+Loader=python
+Module=gutenbach
+IAge=1
+Name=gutenbach
+Description="Print" tunes to the gutenbach server
+Authors=Nimrod Gileadi <nimrodg@mit.edu>
Index: gutenbach/README
===================================================================
--- gutenbach/README	(revision 593b5e1aa146f73b19a54598ff02d89816701a57)
+++ gutenbach/README	(revision 593b5e1aa146f73b19a54598ff02d89816701a57)
@@ -0,0 +1,70 @@
+So, you want to develop gutenbach, eh?  Good!
+
+Gutenbach is a distributed music player built on top of CUPs.  It
+essentially enables anybody with access to it to play music from their
+own computer -- all they have to do is "print" to the Gutenbach
+instance as they would any other document!
+
+The current repositories for various Gutenbach features are:
+    - gutenbach
+    - gutenbach-queue
+    - gutenbach-remctl
+    - gutenbach-rhythmbox-plugin
+    - gutenbach-itunes-plugin
+    - gutenbach-web
+
+All of these are located on GitHub:
+http://github.com/search?langOverride=&q=gutenbach&repo=&start_value=1&type=Repositories
+
+Additionally, see README.old for how Gutenbach /used/ to be installed.
+This can sometimes offer insight into how to fix things that are
+broken.
+
+Questions or comments should be directed at gutenbach@mit.edu
+
+NOTES:
+
+- If you keep getting zephyrs with the following errors:
+
+      Playback completed with the following errors:
+      bt_audio_service_open: connect() failed: Connection refused (111)
+      bt_audio_service_open: connect() failed: Connection refused (111)
+      bt_audio_service_open: connect() failed: Connection refused (111)
+
+  This is because you have alsa configured for bluetooth, but bluetooth is not
+  enabled.  You should either enable bluetooth, or uninstall the bluez-alsa
+  package.
+
+- To print to a machine without keytabs, you need to do:
+
+     lpr -Pprintername -Hhostname $file
+
+  The old `lpr -Pprintername@hostname $file` syntax will no longer work.
+
+TODO:
+- include mixer and channel in debconf, or even better, move it to
+  gutenbach-remctl and implement debconf in that package
+
+- the filter should die and send an error message if it can't find the
+  config file, not use defaults
+
+- this should really not conflict with pulse (the biggest problem at the moment is that
+  pulse will spew a bunch of errors like "Home directory /var/spool/cups/tmp not ours." I
+  can't figure out how to get rid of them, but they're really annoying.  As long as pulse
+  is in system mode, things seem to work otherwise.)
+
+- CUPS issues
+    * the CUPS daemon processes do not inherit groups from the lp user (so, for example,
+      even if we add 'lp' to 'audio', the process will not be running in group 'audio').
+      For the time being, I've set the CUPS daemon to always run under group 'audio',
+      but there should really be a better solution.
+    * debathena printer configuration defaults to using ipp, e.g.:
+       jhamrick@lemon-meringue:~$ lpstat -v sipbmp3 
+       device for sipbmp3: ipp://zsr.mit.edu:631/printers/sipbmp3
+     so you can't just do `lpq -Psipbmp3`, you have to use `lpq -Psipbmp3 -hzsr` or
+     something similar.  Same thing goes with lprm.  It is interesting that this is
+     only the case with lpq and lprm, though, and lpr Just Works.  This shouldn't be
+     an issue on non-debathena machines.
+
+- Create wrapper scripts for queuing/dequeuing jobs?  Making it easier to use across
+  multiple platforms, regardless of debathena/normal linux/etc?
Index: gutenbach/README.old
===================================================================
--- gutenbach/README.old	(revision 593b5e1aa146f73b19a54598ff02d89816701a57)
+++ gutenbach/README.old	(revision 593b5e1aa146f73b19a54598ff02d89816701a57)
@@ -0,0 +1,369 @@
+gutenbach
+    The SIPB MP3 Music Spooler
+
+We would love you forever if you took this README/INSTALL document and made
+a Debian package out of it.  That would be uber-awesome.  But otherwise, we're
+assuming that you just want to get gutenbach up and running on your own
+system.  Well, maybe we shouldn't assume that.
+
+
+What does gutenbach do?
+---------------------
+
+gutenbach is a music spooler.  As it turns out, streaming music is a hard
+problem, with lots of proprietary protocols, client and server software.
+All of these jiggety bits are kind of a pain to get working correctly,
+so, we built gutenbach on top of... a printer system.  It's very simple:
+you print an mp3 file to a special "printer", and it gets played on
+whatever speakers you're hooked up to.
+
+
+Prerequisites
+-------------
+
+You'll need a server hooked up to an audio system that you want to use, with
+Debathena installed on top of it.  Ubuntu Server Edition tends to work
+well.
+
+
+Installing gutenbach
+------------------
+
+
+1. Configuring your sound
+
+If you're installing gutenbach on a server environment, it's highly likely
+that you have a bare bones audio setup and everything is muted.  Make sure
+your sound works!  One common problem is that the daemon user (the user which
+will be actually playing the songs, or the user that your lpd, the print server,
+will be running under), isn't in the group audio, and thus can't play
+anything. If you're on Ubuntu Desktop, you'll probably have pulse-audio
+installed, in which case you should add lpd to the pulse-audio group
+as well, and make pulse-audio a single, system-wide instance. See
+this URL for detailed instructions:
+
+    http://www.pulseaudio.org/wiki/SystemWideInstance
+
+
+2. Install some prerequisite software
+
+On a vanilla Ubuntu server install, gutenbach will also need the following
+packages to work properly:
+
+    * mplayer
+    * libimage-exiftool-perl
+
+mpg123 can also be useful for testing, but is not strictly necessary.
+
+
+3. Setup gutenbach
+
+The Git repository for gutenbach is located in:
+
+    /afs/sipb/project/sipbmp3/gutenbach.git
+
+Place this in /root/gutenbach; the remctl scripts will assume that the
+scripts can be found in this location.
+
+
+4. Configure gutenbach
+
+gutenbach will send zephyrs during playback start and end.  Since you don't
+want to be spamming sipb-auto (which is the default zephyr class these
+are sent to), you should create a configuration file:
+
+    /etc/gutenbach-filter-config.pl
+
+That looks like:
+
+    $zephyr_class = "my-auto-class"
+    $host = "hostname"
+    $queue = "printername"
+
+XXX: Auto-detect hostname and invent a sane default zephyr class off of it.
+
+
+5. Configure gutenbach init scripts
+
+gutenbach will attempt to drop some information into /var/run/gutenbach, which
+needs to exist and you can't simply mkdir since /var/run on Ubuntu is
+a tempfs. Thus, add the following lines to a new file, /etc/init.d/gutenbach:
+
+#!/bin/sh
+mkdir /var/run/gutenbach
+touch /var/run/gutenbach/status
+chmod 0777 /var/run/gutenbach/status
+
+You should also run these commands yourself. :-)
+
+XXX: Note from jhamrick: I would recomment actually setting this up as a nice startup script, with a switch case for {start|stop|restart} (where with stop you just remove the directory, and with restart you remove the directory and then recreate it).  Also, gutenbach won't actually run on startup unless there are scripts in the /etc/rc*.d directory, so we need to do:
+
+> ln -s ../init.d/gutenbach /etc/rc2.d/S61gutenbach
+> ln -s ../init.d/gutenbach /etc/rc3.d/S61gutenbach
+> ln -s ../init.d/gutenbach /etc/rc4.d/S61gutenbach
+> ln -s ../init.d/gutenbach /etc/rc5.d/S61gutenbach
+> ln -s ../init.d/gutenbach /etc/rc0.d/K39gutenbach
+> ln -s ../init.d/gutenbach /etc/rc1.d/K39gutenbach
+> ln -s ../init.d/gutenbach /etc/rc6.d/K39gutenbach
+
+XXX: We need better permissions for status. Also, quentin wants to put this
+file in AFS.
+
+
+6. Configure lpd
+
+You'll need to setup a printcap file so that your machine will be actually
+running a printer! The magic lines are:
+
+    :if=|/path/to/gutenbach-filter
+    :lp=/dev/null
+
+Which mean that we pipe the mp3 files through gutenbach-filter (which does
+the actual playing), and then dump the rest of the output into /dev/null,
+since we don't actually care about it.
+
+A standard printcap entry looks like this:
+
+printername
+  :server
+  :cm=Human Readable Printer Name
+  :lp=/dev/null
+  :if=|/path/to/gutenbach-filter
+  :sd=/var/spool/lpd/printername
+  :ml=0:mx=0:sh:sf
+  :create_files
+
+printcap is located in /etc/printcap, but you can also edit the symlink
+in /etc/lprng/printcap.
+
+In /etc/lprng/lpd.conf:
+
+    printcap_path=...
+
+add /etc/lprng/printcap to the beginning of the pathlist, so it looks like:
+
+    printcap_path=/etc/lprng/printcap:|/usr/lib/get_hesiod_pcap
+
+/etc/printcap will also work, assuming lprng doesn't do something funky
+in the future.
+
+WARNING: On a cluster machine, get_hesiod_pcap will clobber gutenbach
+because it sets all:all=someotherprinter, making lpr not see gutenbach.
+There are two ways of fixing this:
+
+1. Patch /usr/lib/get_hesiod_pcap to return a full pcap line instead
+of all when it gets "all" from stdin.
+
+2. Remove get_hesiod_pcap from the list.
+
+To check your modifications, and create the necessary files and folders,
+you should run:
+
+    checkpc -V -f
+
+(As root, of course). You might get a failure on a directory
+/var/spool/lpd/%P doesn't exist; simply mkdir it and run checkpc -V -f
+
+With recent versions of lprng, you will also need to make lpd less paranoid
+about accepting connections.  This usually means the following two changes:
+
+In /etc/lprng/lpd.perms:
+
+    REJECT NOT SERVER
+
+should be commented out, as:
+
+    #REJECT NOT SERVER
+
+You will also need to add this line in lpd.conf:
+
+    lpd_listen_port=515
+
+By default, printers don't allow other users to remove other people's print
+jobs.  For an MP3 spooler, however, this may be a desirable trait, especially
+if someone trys to rickroll you.  You can let everyone lprm jobs by
+commenting out the line:
+
+    REJECT SERVICE=M
+
+XXX: On scourge, ACCEPT SERVICE=M SAMEHOST SAMEUSER doesn't seem to work
+properly, so removing the REJECT line is a must!
+
+XXXXXX: gutenbach accepts no responsibility for social faux pas that may
+be committed with this system.  It is consider good etiquette, however,
+to clear the status file if you're on zsr.
+
+XXXXXXXX: Another note from jhamrick (09/2009): debathena-lprng does not start up with the system by default.  debathena developers are currently deciding whether to change this, but in the meantine you will want to do:
+
+> ln -s ../etc/init.d/debathena-lprng /etc/rc2.d/S60debathena-lprng
+> ^rc2^rc3
+> ^rc3^rc4
+> ^rc4^rc5
+> ln -s ../etc/init.d/debathena-lprng /etc/rc0.d/K40debathena-lprng
+> ^rc0^rc1
+> ^rc1^rc6
+
+7. Test, round one
+
+The first test you should do to make sure gutenbach is configured properly is
+to attempt to play an mp3 file locally, via lpr.  The command you should use
+is:
+
+    mit-lpr -Pprintername@localhost filename.mp3
+
+Note the "mit-" prefix; Debathena defaults to CUPS, which we have not set
+up yet.
+
+See below for troubleshooting tips.
+
+
+8. Test, round two
+
+The second test you should do is try playing an MP3 remotely. The appropriate
+command is:
+
+    mit-lpr -Pprintername@hostname filename.mp3
+
+(Once again, with "mit-").  See below for troubleshooting tips.
+
+
+9. Troubleshooting
+
+So, it didn't work.  How did it fail?
+
+----
+sending job 'ezyang@vivace+800' to asdfasdf@localhost
+ connecting to 'localhost', attempt 1
+ cannot open connection to localhost - No such file or directory
+----
+
+This means that lpd is not accepting connections properly.  Check to see
+if you configured lpd.perms and lpd.conf correctly.  Try rebooting lpd
+by pkill lpd && lpd.  Use nmap to check of port 515 is open, both on the
+local machine and on a remote machine.  Check if networking is working
+on the server.  Use netstat to see what programs are listening to port
+515, and from which hosts.  Check iptables.
+
+----
+lpr: The printer or class was not found.
+----
+
+You're using lpr, not mit-lpr.
+
+----
+(no output, but no sound)
+----
+
+It looks like you managed to send the file over.  To diagnose the problems
+further:
+
+    * Check the zephyr logs of the class gutenbach was configured to
+      send messages to:
+
+        - If you see a reasonably full and formatted message, that means
+          that either: 1. your volume is turned off, or 2. mplayer is
+          horribly broken (XXX: it probably isn't, but I don't know what
+          error message it gives in that case)
+
+          By the way, be sure to check both the *hardware* and the
+          *software* volume.
+
+        - If you see a blank zephyr, that means that gutenbach-filter died
+          trying to get a handle to /var/run/gutenbach/status and failing.
+          Check if you created the file correctly, and that daemon has
+          permissions to write to it. If you rebooted recently, check if
+          you have the appropriate init.d script setup.
+
+    * Otherwise, check /var/spool/lpd/printername/status.pr (most of all the
+      other files are useless, especially including log):
+
+        - If you see a Perl error, fix it. The most common cause is because
+          exiftools is not installed.
+
+    * Otherwise, double check the userland code in gutenbach-filter. XXX: There
+      are some edge-cases that don't give nice error messages, for example
+      the failed write to /var/run/gutenbach/status
+
+
+10. Deploying CUPS
+------------------
+
+The final step is to give your newfangled printer a cups.mit.edu record.
+In order to do this, you will need to ask IS&T for a Moira pcap entry
+request.  Send mail to hesreq@mit.edu, specifying that you are setting
+up a gutenbach clone, that you want a Moira pcap entry, the printer name
+and server name of your queue, and that you want hwtype=LOCAL,ka=1. It wouldn't
+hurt to also tell them where your print queue is, and a contact list.
+
+Once you get the pcap entry, ping sipb-cups@mit.edu to add your machine
+to the public list.
+
+Troubleshooting:
+
+----
+Send_auth_transfer: on client client_krb5_auth failed - krb5_sendauth failed -
+Bad application version was sent (via sendauth)
+----
+
+This means that the ka field in your Hesiod pcap entry is incorrectly set to
+0.  Send mail to hesreq@mit.edu requesting ka be set to 1.
+
+
+11. Setting up keytabs on the machine
+-------------------------------------
+
+Email accounts@mit.edu and ask them for two keytabs: one for your machine,
+and one for "daemon" at your machine.  When you get the keytab, reset their
+passwords by running:
+
+    k5srvutil change -f your.keytab
+    k5srvutil delold -f your.keytab
+
+Now, install the machine-wide keytab in /etc/krb5.keytab, and install the
+daemon keytab as /etc/daemon.keytab.  (The first filename is required; the
+second can be changed.)  Make sure you chown and chgrp it to daemon.
+
+Finally, edit /etc/printcap and give it information about the Kerberos:
+
+gutenbach: server
+    :cm=SIPB MP3 Spooler
+    ...
+    :auth_forward=kerberos5
+    :use_auth=kerberos5
+    :kerberos_id=daemon/your-machine-name.mit.edu@ATHENA.MIT.EDU
+    :kerberos_keytab=/etc/daemon.keytab
+
+Troubleshooting
+
+-----
+Printer 'pikamp3@LESBIAN-BABY-SEAGULL-GODDESS.MIT.EDU' - 
+on client client_krb5_auth failed - krb5_sendauth failed - Bad response (during sendauth exchange)
+-----
+
+Your daemon.keytab is not readable by daemon.
+
+12. Setting up remctl commands
+-----------------------------
+
+It's useful to be able to control the volume. Remctl is the way to do
+this without asking people to ssh in, and then alsamix(er).
+
+You will probably need to apt-get install remctl-server. Then, replace
+the /etc/remctl/conf.d directory with a Git checkout of
+/afs/sipb/project/sipbmp3/gutenbach-remctl.git.
+
+Please note that remctl will NOT work without a keytab setup.
+
+
+X. Deploying gutenbachweb
+------------------------
+
+gutenbach web provides a nice and user-friendly interface for some common
+tasks. XXX: It is currently not portable beyond zsr. Stay tuned!
+
+X. Troubleshooting
+------------------
+
+If things are broken on a reboot, make sure you're running:
+
+    /etc/init.d/{gutenbach,zhm,debatehna-lprng}
Index: gutenbach/inst/create-filter-config
===================================================================
--- gutenbach/inst/create-filter-config	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ gutenbach/inst/create-filter-config	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,39 @@
+#!/bin/sh -e
+
+echo "Creating /usr/lib/gutenbach/config/gutenbach-filter-config.pl..." >&2
+if [ -e "/usr/lib/gutenbach/config/gutenbach-filter-config.pl" ]; then
+    rm /usr/lib/gutenbach/config/gutenbach-filter-config.pl
+fi
+
+failed=
+if [ -e /usr/lib/gutenbach/config/printername ]; then
+    printername=$(cat /usr/lib/gutenbach/config/printername)
+else
+    failed="yes"
+fi
+if [ -e /usr/lib/gutenbach/config/hostname ]; then
+    hostname=$(cat /usr/lib/gutenbach/config/hostname)
+else
+    failed="yes"
+fi
+if [ -e /usr/lib/gutenbach/config/zephyrclass ]; then
+    zephyrclass=$(cat /usr/lib/gutenbach/config/zephyrclass)
+else
+    failed="yes"
+fi
+
+mixer="PCM"
+channel="Front Left"
+config_file="/usr/lib/gutenbach/config/gutenbach-filter-config.pl"
+
+if [ -z "$failed" ]; then
+    echo "\$zephyr_class = \""$zephyrclass"\";" >> "$config_file"
+    echo "\$host = \""$hostname"\";" >> "$config_file"
+    echo "\$queue = \""$printername"\";" >> "$config_file"
+    echo "\$mixer = \""$mixer"\";" >> "$config_file"
+    echo "\$channel = \""$channel"\";" >> "$config_file"
+    echo "1;" >> "$config_file"
+else
+    echo "Error: One of /usr/lib/gutenbach/config/{printername,hostname,zephyrclass} does not exist!" >&2
+    exit 1
+fi
Index: gutenbach/inst/cups-add-printer
===================================================================
--- gutenbach/inst/cups-add-printer	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ gutenbach/inst/cups-add-printer	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+if [ -e /usr/lib/gutenbach/config/printername ]; then
+    printername="$(cat /usr/lib/gutenbach/config/printername)"
+    echo "Adding new printer $printername..."
+
+    lpadmin -p "$printername" -E -v gutenbach:/dev/null -D "Gutenbach Music Spooler"
+
+else
+    echo "Error: /usr/lib/gutenbach/config/printername does not exist"
+    exit 1
+fi
Index: gutenbach/inst/cups-set-perms
===================================================================
--- gutenbach/inst/cups-set-perms	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ gutenbach/inst/cups-set-perms	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,55 @@
+#!/bin/sh
+
+# Set the CUPS permissions such that anyone can add/remove jobs
+# from the queue for gutenbach.
+
+if [ -e /usr/lib/gutenbach/config/printername ]; then
+    printername="$(cat /usr/lib/gutenbach/config/printername)"
+
+    conffile="/etc/cups/cupsd.conf"
+    mv "$conffile" "$conffile.bak"
+    touch "$conffile"
+
+    while read line; do
+	listen_localhost=$(echo "$line" | grep '^Listen localhost' || true)
+	if [ -n "$listen_localhost" ]; then
+	    echo "#GUTENBACH$line" >> "$conffile"
+       	else
+	    root_location=$(echo "$line" | grep '^<Location />$' || true)
+	    if [ -n "$root_location" ]; then
+		echo "<Location />" >> "$conffile"
+		echo "Allow from All # added by Gutenbach" >> "$conffile"
+	    else
+		echo "$line" >> "$conffile"
+	    fi
+	fi
+
+    done < "$conffile.bak"
+    rm "$conffile.bak"
+
+    cat >> "$conffile" <<EOF
+# Begin configurations for gutenbach
+
+Group audio
+Listen *
+ServerAlias *
+
+<Location /printers/$printername>
+    <Limit Cancel-Job Purge-Jobs CUPS-Authenticate-Job>
+        Order deny,allow
+        Allow from All
+    </Limit>
+
+    Order Deny, Allow
+    Allow from All
+</Location>
+
+# End configurations for gutenbach
+EOF
+
+    /etc/init.d/cups reload
+
+else
+    echo "Error: /usr/lib/gutenbach/config/printername does not exist"
+    exit 1
+fi
Index: gutenbach/inst/edit-lpd.conf
===================================================================
--- gutenbach/inst/edit-lpd.conf	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ gutenbach/inst/edit-lpd.conf	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,34 @@
+#!/bin/sh -e
+
+echo "Editing /etc/lprng/lpd.conf..." >&2
+# add the printcap path to lpd.conf
+if [ -e /etc/lprng/lpd.conf ]; then
+    mv /etc/lprng/lpd.conf /etc/lprng/lpd.conf.bak
+    touch /etc/lprng/lpd.conf	
+
+    while read line; do
+	printcap=$(echo "$line" | grep ^printcap_path= || true)
+	if [ -n "$printcap" ]; then
+	    lprngprintcap=$(echo "$line" | grep /etc/lprng/printcap || true)
+	    printcap=$(echo "$line" | grep /etc/printcap || true)
+	    if [ ! -n "$lprngprintcap" ] && [ ! -n "$printcap" ]; then
+		echo "#$line" >> /etc/lprng/lpd.conf
+		echo "$line" | sed 's,printcap_path=,printcap_path=/etc/lprng/printcap:\|,' >> /etc/lprng/lpd.conf
+	    else
+		echo "$line" >> /etc/lprng/lpd.conf
+	    fi
+	else
+	    echo "$line" >> /etc/lprng/lpd.conf
+	fi
+    done < /etc/lprng/lpd.conf.bak
+    rm /etc/lprng/lpd.conf.bak
+else
+    touch /etc/lprng/lpd.conf
+    echo "printcap_path=/etc/lprng/printcap" >> /etc/lprng/lpd.conf
+fi
+
+# add lpd_listen_port to lpd.conf
+lpd_listen_port=$(cat /etc/lprng/lpd.conf | grep ^lpd_listen_port=515 || true)
+if [ ! -n "$lpd_listen_port" ]; then
+    echo "lpd_listen_port=515" >> /etc/lprng/lpd.conf
+fi
Index: gutenbach/inst/edit-lpd.perms
===================================================================
--- gutenbach/inst/edit-lpd.perms	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ gutenbach/inst/edit-lpd.perms	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+# make lpd less paranoid about accepting connections
+# (comment out REJECT NOT SERVER)
+# allow other users to dequeue music
+# (comment out REJECT SERVICE=M)
+# make it only accept A jobs
+# (add 
+#    ACCEPT SERVICE=R,P SERVER
+#    ACCEPT C=CA* SERVICE=R,P
+#    REJECT SERVICE=R,P)
+
+echo "Editing /etc/lprng/lpd.perms..." >&2
+if [ -e /etc/lprng/lpd.perms ]; then
+    mv /etc/lprng/lpd.perms /etc/lprng/lpd.perms.bak
+    touch /etc/lprng/lpd.perms	
+
+    while read line; do
+	reject_not_server=$(echo "$line" | grep '^REJECT NOT SERVER' || true)
+	if [ -n "$reject_not_server" ]; then
+	    echo "#$line" >> /etc/lprng/lpd.perms
+	    
+	    echo "## BEGIN gutenbach configuration" >> /etc/lprng/lpd.perms
+	    echo "ACCEPT SERVICE=R,P SERVER" >> /etc/lprng/lpd.perms
+	    echo "ACCEPT C=CA* SERVICE=R,P" >> /etc/lprng/lpd.perms
+	    echo "REJECT SERVICE=R,P" >> /etc/lprng/lpd.perms
+	    echo "## END gutenbach configuration" >> /etc/lprng/lpd.perms
+      	else
+	    reject_service=$(echo "$line" | grep '^REJECT SERVICE=M' || true)
+	    if [ -n "$reject_service" ]; then
+		echo "#line" >> /etc/lprng/lpd.perms
+	    else
+		echo "$line" >> /etc/lprng/lpd.perms
+	    fi
+	fi
+    done < /etc/lprng/lpd.perms.bak
+    rm /etc/lprng/lpd.perms.bak
+fi
Index: gutenbach/inst/edit-printcap
===================================================================
--- gutenbach/inst/edit-printcap	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ gutenbach/inst/edit-printcap	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,35 @@
+#!/bin/sh -e
+
+echo "Editing /etc/printcap..." >&2
+if [ ! -e /etc/printcap ]; then
+    touch /etc/printcap
+fi
+
+if [ ! -e /etc/lprng/printcap ]; then
+    ln -s /etc/printcap /etc/lprng/printcap
+fi
+
+if [ -e /usr/lib/gutenbach/config/printername ]; then
+    printername=$(cat /usr/lib/gutenbach/config/printername)
+
+    printcap=$(cat /etc/printcap | grep ^`echo $printername` || true)
+    if [ ! -n "$printcap" ]; then
+    # add the appropriate entry into /etc/printcap, /etc/lprng/printcap
+	echo "$printername" >> /etc/printcap
+	echo "  :server" >> /etc/printcap
+	echo "  :cm=Gutenbach Music Spooler" >> /etc/printcap
+	echo "  :lp=/dev/null" >> /etc/printcap
+	echo "  :if=|/usr/lib/gutenbach/gutenbach-filter" >> /etc/printcap
+	echo "  :lf=/var/spool/lpd/$printername/log" >> /etc/printcap
+	echo "  :sd=/var/spool/lpd/$printername" >> /etc/printcap
+	echo "  :ml=0:mx=0:sh" >> /etc/printcap
+	echo "  :create_files" >> /etc/printcap
+	echo "  :auth_forward=kerberos5" >> /etc/printcap
+	echo "  :use_auth=kerberos5" >> /etc/printcap
+	echo "  :kerberos_id=daemon/"`hostname`".mit.edu@ATHENA.MIT.EDU" >> /etc/printcap
+	echo "  :kerberos_keytab=/etc/daemon.keytab" >> /etc/printcap
+    fi
+else
+    echo "Error: /usr/lib/gutenbach/config/printername does not exist!" >&2
+    exit 1
+fi
Index: gutenbach/inst/run-checkpc
===================================================================
--- gutenbach/inst/run-checkpc	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ gutenbach/inst/run-checkpc	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,22 @@
+#!/bin/sh -e
+
+# make sure directories exist for checkpc
+echo "Running checkpc..." >&2
+if [ ! -d /var/spool/lpd ]; then
+    mkdir /var/spool/lpd
+    mkdir /var/spool/lpd/%P
+else
+    if [ ! -d /var/spool/lpd/%P ]; then
+	mkdir /var/spool/lpd/%P
+    fi
+fi
+chmod og=rwx /var/spool/lpd
+chmod og=rwx /var/spool/lpd/%P
+
+if [ -e /usr/lib/gutenbach/config/printername ]; then
+    printername=$(cat /usr/lib/gutenbach/config/printername)
+    /usr/sbin/checkpc -P"$printername" -f
+else
+    echo "Error: /usr/lib/gutenbach/config/printername does not exist!" >&2
+    exit 1
+fi
Index: gutenbach/lib/README
===================================================================
--- gutenbach/lib/README	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ gutenbach/lib/README	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,20 @@
+If you want to help make changes to gutenbach, do NOT make changes
+locally!  They will most likely get overwritten by the next package
+install.  Instead, you should check out the source and edit the
+package itself:
+
+/afs/sipb/project/sipbmp3/gutenbach.git
+
+It may be useful to just edit things locally to make sure they work,
+and then add the change into the package.
+
+zsr (in SIPB) is set up to build packages, and already has a git clone
+in /root/gutenbach.  You can edit the source there, build the package,
+and then reinstall the package.
+
+A good guide to get started with debian packaging is here:
+http://debathena.mit.edu/packaging/
+
+jhamrick (Jessica Hamrick) is currently the active maintainer for
+gutenbach, so if you're interested in contributing but don't know
+quite where to start, you should talk to her.
Index: gutenbach/lib/TODO
===================================================================
--- gutenbach/lib/TODO	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ gutenbach/lib/TODO	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,2 @@
+- gutenbach-get-config should fail and error out if it can't find a
+   config file -- we can't use defaults since what would the defaults be?
Index: gutenbach/lib/gutenbach
===================================================================
--- gutenbach/lib/gutenbach	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ gutenbach/lib/gutenbach	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,333 @@
+#!/usr/bin/perl
+# Play the data on STDIN as an audio file
+#
+# $Id: gutenbach-filter,v 1.26 2009/02/20 00:27:17 geofft Exp root $
+# $Source: /usr/local/bin/RCS/gutenbach-filter,v $
+#
+# TODO
+# ----
+# Make this structured code. It's a mess.
+# Repeat what we just played for EXT files too
+# Support HTTP Auth on ogg streams
+# License, cleanup and package
+#
+# Jered Floyd <jered@mit.edu> takes very little credit for this code
+# apparently neither does Quentin Smith <quentin@mit.edu>
+
+use strict;
+use warnings;
+use Image::ExifTool qw(ImageInfo);
+use File::Spec::Functions;
+use File::Temp qw{tempfile tempdir};
+use File::Basename qw(basename);
+use LWP::UserAgent;
+use Data::Dumper;
+use IPC::Open2;
+use English;
+
+use vars qw/$zephyr_class $host $queue $mixer $channel/;
+
+require "/usr/lib/gutenbach/config/gutenbach-filter-config.pl" or die "Unable to load configuration";
+
+my $ua = new LWP::UserAgent;
+
+# This variable contains the pid of the child process (which runs
+# mplayer) once it has been forked, so that we can kill it on SIGTERM
+my $pid;
+
+# Replace STDERR with a log file in /tmp.
+open(CUPS, ">&STDERR") or die "Unable to copy CUPS filehandle";
+close(STDERR);
+open(STDERR, ">>", "/tmp/gutenbach.log") or warn "Couldn't open log: $!";
+
+# Set the TERM environment (for the benefit of mplayer?)
+# I don't know why we do this --quentin
+$ENV{"TERM"}="vt100";
+
+print STDERR "STDERR FROM SPOOL FILTER\n";
+
+# CUPS provides us with these arguments:
+#
+# argv[1]
+# The job ID
+# argv[2]
+# The user printing the job
+# argv[3]
+# The job name/title
+# argv[4]
+# The number of copies to print
+# argv[5]
+# The options that were provided when the job was submitted
+# argv[6]
+# The file to print (first program only)
+#
+# The scheduler runs one or more of these programs to print any given
+# job. The first filter reads from the print file and writes to the
+# standard output, while the remaining filters read from the standard
+# input and write to the standard output. The backend is the last
+# filter in the chain and writes to the device.
+
+printf(STDERR "Got \@ARGV: %s\n", Dumper(\@ARGV));
+
+my %arguments = (
+		 "job-id" => $ARGV[0],
+		 user => $ARGV[1],
+		 "job-title" => $ARGV[2],
+		 copies => $ARGV[3],
+		 options => {split(/[= ]/, $ARGV[4])},
+		 file => $ARGV[5],
+		);
+
+# If we weren't given a filename, we need to read from stdin. Since
+# mplayer really wants a file, let's write out to a temporary file
+# first.
+if (!$arguments{"file"}) {
+  my ($fh, $file) = tempfile("gutenbachXXXXX", UNLINK => 1); # Ask File::Temp for a safe temporary file
+  my $buf;
+  while (read(STDIN, $buf, 1024*1024)) { # Read 1M at a time and put it in the temporary file
+    print $fh $buf;
+  }
+  close($fh);
+  $arguments{"file"} = $file;
+}
+
+printf(STDERR "Got \%arguments: %s\n", Dumper(\%arguments));
+
+# Open up a zwrite command to announce the current track.
+my @zwrite_command = (qw(/usr/bin/zwrite -d -n -c), $zephyr_class, "-i", $queue.'@'.$host, "-s", "Gutenbach Music Spooler");
+
+print STDERR "Invoking @zwrite_command\n";
+open(ZEPHYR, "|-", @zwrite_command) or die "Couldn't launch zwrite: $!";
+
+my $status;
+if (exists($arguments{"options"}{"job-originating-host-name"})) {
+    print(ZEPHYR $arguments{"user"},"\@",$arguments{"options"}{"job-originating-host-name"}," is playing:\n");
+    $status = "User: ".$arguments{"user"}."\@".$arguments{"options"}{"job-originating-host-name"};
+} else {
+    print(ZEPHYR $arguments{"user"}," is playing:\n");
+    $status = "User: ".$arguments{"user"};
+}
+
+# SIGHUP handler, in case we were aborted
+sub clear_status {
+  kill 15, $pid if $pid;
+  my @zwrite_command = (qw(/usr/bin/zwrite -d -n -c), $zephyr_class, "-i", $queue.'@'.$host, "-s", "Gutenbach Music Spooler");
+  open(ZEPH, "|-", @zwrite_command);
+  print(ZEPH "Playback aborted.\n");
+  close(ZEPH);
+  die;
+}
+
+$SIG{HUP} = \&clear_status;
+$SIG{TERM} = \&clear_status;
+
+# Read the metadata information from the file.
+my ($filepath) = $arguments{"file"};
+my ($fileinfo) = ImageInfo($filepath);
+my ($magic) = $fileinfo->{FileType};
+my ($tempdir);
+my ($newpath);
+
+if ($magic) {
+  # $magic means that Image::ExifTool was able to identify the type of file
+  printf(ZEPHYR "%s file %s\n", $magic, $arguments{"job-title"});
+  $status .= sprintf(" Filetype: %s.", $magic);
+  $status .= sprintf(" Filename: %s.", $arguments{"job-title"});
+
+  if (exists $fileinfo->{'Title'}) {
+    printf(ZEPHYR "\@b{%s}\n", $fileinfo->{'Title'}) if exists $fileinfo->{'Title'};
+    $status .= sprintf(" Title: %s.", $fileinfo->{'Title'});
+  }
+  foreach my $key (qw/Artist Album AlbumArtist/) {
+    if (exists $fileinfo->{$key}) {
+      printf(ZEPHYR "%s\n", $fileinfo->{$key}) if exists $fileinfo->{$key};
+      $status .= sprintf(" %s: %s\n", $key, $fileinfo->{$key});
+    }
+  }
+
+  $tempdir = tempdir();
+  #awful hack -- geofft
+  #== -- quentin
+  # This code appears to create a new temporary directory and symlink
+  # the job file into the temporary directory under the original
+  # filename. I think this is because mplayer sometimes uses the file
+  # extension to identify a filetype.
+  $newpath = $tempdir . '/' . basename($arguments{"job-title"});
+  symlink($filepath, $newpath);
+  $filepath = $newpath;
+}
+elsif ($arguments{copies} == 42) {
+  # This is a flag that is set by jobs queued by split_playlist(); it tells us to not try to split the playlist again.
+  # Call resolve_external_reference to apply some heuristics to determine the filetype.
+  $filepath = resolve_external_reference($filepath, \%arguments);
+  if ($filepath =~ m|http://www\.youtube\.com/watch\?v=|) {
+    # YouTube URLs are resolved by the youtube-dl command.
+    # Launch youtube-dl
+    open(YTDL, "-|", "youtube-dl", "-g", $filepath) or die "Unable to invoke youtube-dl";
+    # Read the title (currently not doing so because youtube-dl doesn't know how to get the title.
+    my $title = ""; # <YTDL>
+    # Print the title to zephyr and the status string.
+    print ZEPHYR "YouTube video $filepath\n$title";
+    $status .= " YouTube video $filepath. $title.";
+    # youtube-dl prints the URL of the flash video, which we pass to mplayer as a filename.
+    $filepath = <YTDL>;
+    chomp $filepath;
+  } else { # Doesn't appear to be a YouTube URL.
+    print STDERR "Resolved external reference to $filepath\n";
+    printf(ZEPHYR "%s\n", $filepath);
+    $status .= sprintf(" External: %s\n", $filepath);
+  }
+}
+elsif (-T $filepath) { # If the file appears to be a text file, treat it as a playlist.
+  split_playlist($filepath, \%arguments);
+  close(ZEPHYR);
+  # See http://www.cups.org/documentation.php/api-filter.html#MESSAGES
+  print CUPS "NOTICE: $status\n";
+  exit 0;
+}
+
+close(ZEPHYR);
+print CUPS "NOTICE: $status\n";
+play_mplayer_audio($filepath, \%arguments);
+
+# Remove the symlink we made earlier for the filetype.
+if ($magic) {
+  unlink($newpath);
+  rmdir($tempdir);
+}
+
+# Play an external stream reference
+sub resolve_external_reference {
+  # Retrieve those command line opts.
+  my ($filepath, $arguments) = @_;
+
+  my ($format, $uri, $userpass);
+
+  open(FILE, "<", $filepath) or die "Couldn't open spool file";
+  if (<FILE> =~ /^(\S+)/) {
+    # Take the leading non-whitespace as a URL
+    $uri=$1;
+
+    if ($uri =~ m|http://www\.youtube\.com/watch\?v=|) {
+      return $uri;
+    }
+
+    # Fetch the URL with a HEAD request to get the content type
+    my $response = $ua->head($uri);
+
+    my $contenttype=($response->content_type() or "unknown");
+
+    if ($contenttype eq "audio/mpeg") { $format="MP3" }
+    elsif ($contenttype eq "application/x-ogg") { $format="OGG" }
+    elsif ($contenttype eq "application/ogg") { $format="OGG" }
+    elsif ($contenttype eq "audio/x-scpls") { $format="SHOUTCAST" }
+    else {
+      print ZEPHYR
+	"Unknown Content-Type $contenttype for URI $uri\n";
+    }
+  } else { # Unable to match the URL regex
+    print ZEPHYR "Couldn't read URI for external reference\n";
+    # Return the existing path, in the hopes that mplayer knows what to do with it.
+    return $filepath;
+  }
+
+  if ($format eq "SHOUTCAST") {
+    print ZEPHYR "Shoutcast playlist...\n";
+    return get_shoutcast($uri);
+  } elsif ($format eq "MP3") {
+  } elsif ($format eq "OGG") {
+  } else {
+    print ZEPHYR "Unrecognized stream format: $format\n";
+  }
+  return $uri;
+}
+
+sub split_playlist {
+  my ($file, $arguments) = @_;
+
+  my $i = 0;
+
+  open(FILE, "<", $filepath) or die "Couldn't open spool file";
+  while (<FILE>) {
+    chomp;
+    if (/^([^#]\S+)/) {
+      printf (STDERR "Found playlist line: %s\n", $_);
+      open(LPR, "|-", 'lpr', '-P'.$queue.'@localhost', '-#', '42', '-J', $arguments->{"job-title"}, '-o', 'job-priority=100');
+      print LPR $1;
+      close(LPR);
+      $i++;
+    }
+  }
+  printf(ZEPHYR "Playlist containing %d valid entries, split into separate jobs.\n", $i);
+}
+
+# Process a Shoutcast playlist
+# get_shoutcast(URI)
+sub get_shoutcast {
+  my $uri = shift(@_);
+
+  my $response = $ua->get($uri);
+  my (@titles, @uris);
+
+  foreach (split("\n", $response->content())) {
+      if (/^File\d+=(\S+)/) {
+	  push(@uris, $1);
+      }
+      if (/^Title\d+=(.+)$/) {
+	  push(@titles, $1);
+      }
+  }
+
+  # choose a random server
+  my $server = int(rand scalar(@uris));
+  # print the name of the stream if available
+  print ZEPHYR "$titles[$server]\n";
+  return $uris[$server];
+}
+
+sub play_mplayer_audio {
+  my ($filepath, $opts) = @_;
+
+  # Open up a zwrite command to show the mplayer output
+  my @zwrite_command = (qw(/usr/bin/zwrite -d -n -c), $zephyr_class, "-i", $queue.'@'.$host, "-s", "Gutenbach Music Spooler");
+
+  print STDERR "Invoking (from play_mplayer_audio): @zwrite_command\n";
+
+  # fork for mplayer
+  $pid = open(MP3STATUS, "-|");
+  unless (defined $pid) {
+    open(ZEPHYR, "|-", @zwrite_command) or die "Couldn't launch zwrite: $!";
+    print ZEPHYR "Couldn't fork: $!\n";
+    close(ZEPHYR);
+    return;
+  }
+
+  if ($pid) { #parent
+    # Check if there were any errors
+    if ($_ = <MP3STATUS>) {
+      open(ZEPHYR, "|-", @zwrite_command) or die "Couldn't launch zwrite: $!";
+      print ZEPHYR "Playback completed with the following errors:\n";
+      while (<MP3STATUS>) {
+	print ZEPHYR $_;
+      }
+      close(ZEPHYR);
+    } else {
+      open(ZEPHYR, "|-", @zwrite_command) or die "Couldn't launch zwrite: $!";
+      print ZEPHYR "Playback completed successfully.\n";
+      close(ZEPHYR);
+    }
+    close(MP3STATUS) || print ZEPHYR "mplayer exited $?\n";
+  }
+  else { # child
+    # redirect STDERR to STDOUT
+    open STDERR, '>&STDOUT';
+    # make sure that mplayer doesn't try to intepret the file as keyboard input
+    close(STDIN);
+    open(STDIN, "/dev/null");
+
+    my @args = (qw|/usr/bin/mplayer -vo fbdev2 -zoom -x 1024 -y 768 -framedrop -nolirc -cache 512 -ao alsa -really-quiet |, $filepath);
+    #print STDERR "About to exec: ", Dumper([@args]);
+    exec(@args) ||
+      die "Couldn't exec";
+  }
+}
Index: gutenbach/lib/gutenbach-get-config
===================================================================
--- gutenbach/lib/gutenbach-get-config	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ gutenbach/lib/gutenbach-get-config	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,35 @@
+#!/usr/bin/perl
+use strict;
+# Get configuration of gutenbach
+
+my $zephyr_class = `hostname`;
+chomp($zephyr_class);
+my $host = `hostname`;
+chomp($zephyr_class);
+my $queue = "gutenbach";
+my $mixer = "PCM";
+my $channel = "Front Left";
+
+# Configuration
+my $config_file = "/usr/lib/gutenbach/config/gutenbach-filter-config.pl";
+if (-r $config_file) {
+    # Inline the configuration file
+    local $/;
+    my $fh;
+    open $fh, $config_file;
+    eval <$fh>;
+}
+
+my %config = (
+    'zephyr-class' => $zephyr_class,
+    'host' => $host,
+    'queue' => $queue,
+    'mixer' => $mixer,
+    'channel' => $channel,
+);
+
+foreach my $argv (@ARGV)
+{
+    #print $argv . "\n";
+    print $config{$argv};
+}
Index: gutenbach/rm/cups-remove-printer
===================================================================
--- gutenbach/rm/cups-remove-printer	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ gutenbach/rm/cups-remove-printer	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+echo "Removing gutenbach printer..." >&2
+
+if [ -e /usr/lib/gutenbach/config/printername ]; then
+    printername="$(cat /usr/lib/gutenbach/config/printername)"
+
+    lpadmin -x "$printername"
+
+else
+    echo "Error: /usr/lib/gutenbach/config/printername does not exist"
+fi
Index: gutenbach/rm/cups-revert-perms
===================================================================
--- gutenbach/rm/cups-revert-perms	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ gutenbach/rm/cups-revert-perms	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,25 @@
+#!/bin/sh 
+
+echo "Reverting changes to /etc/cups/cupsd.conf..." >&2
+conffile="/etc/cups/cupsd.conf"
+
+mv "$conffile" "$conffile.bak"
+touch "$conffile"
+sed '/# Begin configurations for gutenbach/,/# End configurations for gutenbach/ d' < "$conffile.bak" > "$conffile"
+
+mv "$conffile" "$conffile.bak"
+touch "$conffile"
+while read line; do
+    listen_localhost=$(echo "$line" | grep '^#GUTENBACH' || true)
+    if [ -n "$listen_localhost" ]; then
+	echo "$(echo $line | sed s/#GUTENBACH//)" >> "$conffile"
+    else
+	root_location=$(echo "$line" | grep '^Allow from All # added by Gutenbach$' || true)
+	if [ -z "$root_location" ]; then
+	    echo "$line" >> "$conffile"
+	fi
+    fi
+
+done < "$conffile.bak"
+
+rm "$conffile.bak"
Index: gutenbach/rm/revert_lpd.conf
===================================================================
--- gutenbach/rm/revert_lpd.conf	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ gutenbach/rm/revert_lpd.conf	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,11 @@
+#!/bin/sh -e
+
+echo "Reverting changes to /etc/lprng/lpd.conf..." >&2
+mv /etc/lprng/lpd.conf /etc/lprng/lpd.conf.bak
+touch /etc/lprng/lpd.conf
+while read line; do
+    lpd_listen_port=$(echo "$line" | grep ^lpd_listen_port=515$ || true)
+    if [ -z "$lpd_listen_port" ]; then
+	echo "$line" >> /etc/lprng/lpd.conf
+    fi
+done < /etc/lprng/lpd.conf.bak
Index: gutenbach/rm/revert_lpd.perms
===================================================================
--- gutenbach/rm/revert_lpd.perms	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ gutenbach/rm/revert_lpd.perms	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,19 @@
+#!/bin/sh -e
+
+echo "Reverting changes to /etc/lprng/lpd.perms..." >&2
+mv /etc/lprng/lpd.perms /etc/lprng/lpd.perms.bak
+touch /etc/lprng/lpd.perms
+while read line; do
+    reject_not_server=$(echo "$line" | grep '^#REJECT NOT SERVER$' || true)
+    if [ ! -z "$reject_not_server" ]; then
+	echo "REJECT NOT SERVER" >> /etc/lprng/lpd.perms
+    else
+	reject_service=$(echo "$line" | grep '^#REJECT SERVICE=M$' || true)
+	if [ ! -z "$reject_service" ]; then
+	    echo "REJECT SERVICE=M" >> /etc/lprng/lpd.perms
+	else
+            echo "$line" >> /etc/lprng/lpd.perms
+	fi
+    fi
+done < /etc/lprng/lpd.perms.bak
+rm /etc/lprng/lpd.perms.bak
Index: gutenbach/rm/revert_printcap
===================================================================
--- gutenbach/rm/revert_printcap	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
+++ gutenbach/rm/revert_printcap	(revision 04f7e0593d10b7f59bee40314f6e3e81da8c34ed)
@@ -0,0 +1,30 @@
+#!/bin/sh -e
+
+echo "Reverting changes to /etc/printcap..." >&2
+
+if [ -e /usr/lib/gutenbach/config/printername ]; then
+    printername=$(cat /usr/lib/gutenbach/config/printername)
+
+    mv /etc/printcap /etc/printcap.bak
+    touch /etc/printcap
+    foundprinter="false"
+    while read line; do
+	printername=$(echo "$line" | grep ^`echo $printername`$ || true)
+	if [ -n "$printername" ]; then
+            foundprinter="true"
+	else
+            if [ "$foundprinter"="true" ]; then
+		configline=$(echo "$line" | grep ^[[:space:]]*: || true)
+		if [ -z "$configline" ]; then
+                    foundprinter="false"
+                    echo "$line" >> /etc/printcap
+		fi
+            else
+		echo "$line" >> /etc/printcap
+            fi
+	fi
+    done < /etc/printcap.bak
+    rm /etc/printcap.bak
+else
+    echo "Error: /usr/lib/gutenbach/config/printername does not exist!" >&2
+fi
