[Pkg-cups-devel] r442 - in cupsys/branches/cups-1.2-ubuntu/debian: . patches

Martin Pitt mpitt at alioth.debian.org
Thu Mar 15 01:36:11 CET 2007


Author: mpitt
Date: Thu Mar 15 00:36:09 2007
New Revision: 442

Modified:
   cupsys/branches/cups-1.2-ubuntu/debian/changelog
   cupsys/branches/cups-1.2-ubuntu/debian/cupsys.postinst
   cupsys/branches/cups-1.2-ubuntu/debian/patches/96_more-bug-fixes-between-cups-1.2.8-1.2.9.dpatch
Log:
* debian/cupsys.postinst: Sync /usr/lib/cups/backend always with the
  debconf settingsm, as otherwise sooner or later the backend directory
  will be empty (closes: LP#92042).
* 96_more-bug-fixes-between-cups-1.2.8-1.2.9.dpatch: Generated some garbage
  files. Fixed.

Modified: cupsys/branches/cups-1.2-ubuntu/debian/changelog
==============================================================================
--- cupsys/branches/cups-1.2-ubuntu/debian/changelog	(original)
+++ cupsys/branches/cups-1.2-ubuntu/debian/changelog	Thu Mar 15 00:36:09 2007
@@ -1,10 +1,20 @@
+cupsys (1.2.8-0ubuntu7) feisty; urgency=low
+
+  * debian/cupsys.postinst: Sync /usr/lib/cups/backend always with the
+    debconf settingsm, as otherwise sooner or later the backend directory
+    will be empty (closes: LP#92042).
+  * 96_more-bug-fixes-between-cups-1.2.8-1.2.9.dpatch: Generated some garbage
+    files. Fixed.
+
+ -- Till Kamppeter <till.kamppeter at gmail.com>  Tue, 14 Mar 2007 16:22:06 +0000
+
 cupsys (1.2.8-0ubuntu6) feisty; urgency=low
 
   * 98_search_mime_files_in_usr_share.dpatch: CUPS failed reading the
     *.types and *.convs files in /etc/cups when /usr/share/cups/mime
     did not exist. Fixed (closes: LP#92205).
 	
- -- Till Kamppeter <till.kamppeter at gmail.com>  Tue, 13 Mar 2007 12:22:06 +0000
+ -- Till Kamppeter <till.kamppeter at gmail.com>  Tue, 14 Mar 2007 12:22:06 +0000
 
 cupsys (1.2.8-0ubuntu5) feisty; urgency=low
 

Modified: cupsys/branches/cups-1.2-ubuntu/debian/cupsys.postinst
==============================================================================
--- cupsys/branches/cups-1.2-ubuntu/debian/cupsys.postinst	(original)
+++ cupsys/branches/cups-1.2-ubuntu/debian/cupsys.postinst	Thu Mar 15 00:36:09 2007
@@ -122,24 +122,23 @@
 	    rm -f /etc/cups/raw.convs-convert
 	    db_fset cupsys/raw-print changed false
 	fi
-	# Set up backends (if configuration was changed or if we do an
-	# initial installation of cupsys, not an update)
-	db_fget cupsys/backend changed
-	if [ "$RET" = "true" ] || [ -z "$2" ]; then
-	    db_get cupsys/backend && SELECTED=$RET
-	    list=`echo $SELECTED | sed -e 's/, /,/g'`
-	    save_IFS=$IFS
-	    IFS=,
-	    (cd /usr/lib/cups/backend && rm -f http ipp lpd parallel scsi serial socket usb snmp)
-	    for module in $list; do
-		ln /usr/lib/cups/backend-available/$module /usr/lib/cups/backend/$module
-		if [ "$module" = "ipp" ]; then
-		    ln /usr/lib/cups/backend/ipp /usr/lib/cups/backend/http
-		fi
-	    done
-	    IFS=$save_IFS
-	    db_fset cupsys/backend changed false
-	fi
+	# Set up backends
+	#db_fget cupsys/backend changed
+	#if [ "$RET" = "true" ] || [ -z "$2" ]; then
+	db_get cupsys/backend && SELECTED=$RET
+	list=`echo $SELECTED | sed -e 's/, /,/g'`
+	save_IFS=$IFS
+	IFS=,
+	(cd /usr/lib/cups/backend && rm -f http ipp lpd parallel scsi serial socket usb snmp)
+	for module in $list; do
+	    ln /usr/lib/cups/backend-available/$module /usr/lib/cups/backend/$module
+	    if [ "$module" = "ipp" ]; then
+		ln /usr/lib/cups/backend/ipp /usr/lib/cups/backend/http
+	    fi
+	done
+	IFS=$save_IFS
+	db_fset cupsys/backend changed false
+	#fi
 
 	# Assure that the special permissions of the lpd backend are also set
 	# for the link in /usr/lib/cups/backend/
@@ -158,8 +157,8 @@
 	    done
 	fi
 	# Resync Debconf database with real state
-	#list=`( cd /usr/lib/cups/backend && for f in ipp lpd parallel scsi serial socket usb snmp; do [ -e $f ] && echo -en "$f, "; done ) | sed -e 's/, $//'`
-	#db_set cupsys/backend $list;
+	list=`( cd /usr/lib/cups/backend && for f in ipp lpd parallel scsi serial socket usb snmp; do [ -e $f ] && echo -n "$f, "; done ) | sed -e 's/, $//'`
+	db_set cupsys/backend $list;
 
 	# Create password file for Digest authentication
         # (removed: Debian CUPS uses PAM and basic authentication)

Modified: cupsys/branches/cups-1.2-ubuntu/debian/patches/96_more-bug-fixes-between-cups-1.2.8-1.2.9.dpatch
==============================================================================
--- cupsys/branches/cups-1.2-ubuntu/debian/patches/96_more-bug-fixes-between-cups-1.2.8-1.2.9.dpatch	(original)
+++ cupsys/branches/cups-1.2-ubuntu/debian/patches/96_more-bug-fixes-between-cups-1.2.8-1.2.9.dpatch	Thu Mar 15 00:36:09 2007
@@ -7,7 +7,7 @@
 @DPATCH@
 diff -urNad cupsys-1.2.8~/config-scripts/cups-largefile.m4 cupsys-1.2.8/config-scripts/cups-largefile.m4
 --- cupsys-1.2.8~/config-scripts/cups-largefile.m4	2005-10-01 00:23:25.000000000 +0100
-+++ cupsys-1.2.8/config-scripts/cups-largefile.m4	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/config-scripts/cups-largefile.m4	2007-03-14 15:53:31.000000000 +0000
 @@ -30,11 +30,11 @@
  if test x$enable_largefile != xno; then
  	LARGEFILE="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE"
@@ -24,7 +24,7 @@
  fi
 diff -urNad cupsys-1.2.8~/cups/file.c cupsys-1.2.8/cups/file.c
 --- cupsys-1.2.8~/cups/file.c	2007-01-10 19:27:04.000000000 +0000
-+++ cupsys-1.2.8/cups/file.c	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/cups/file.c	2007-03-14 15:53:31.000000000 +0000
 @@ -508,7 +508,7 @@
    */
  
@@ -67,7 +67,7 @@
     /*
 diff -urNad cupsys-1.2.8~/cups/options.c cupsys-1.2.8/cups/options.c
 --- cupsys-1.2.8~/cups/options.c	2006-02-22 22:43:17.000000000 +0000
-+++ cupsys-1.2.8/cups/options.c	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/cups/options.c	2007-03-14 15:53:31.000000000 +0000
 @@ -3,7 +3,7 @@
   *
   *   Option routines for the Common UNIX Printing System (CUPS).
@@ -97,7 +97,7 @@
   /*
 diff -urNad cupsys-1.2.8~/filter/pstops.c cupsys-1.2.8/filter/pstops.c
 --- cupsys-1.2.8~/filter/pstops.c	2007-02-07 20:54:37.000000000 +0000
-+++ cupsys-1.2.8/filter/pstops.c	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/filter/pstops.c	2007-03-14 15:53:31.000000000 +0000
 @@ -937,14 +937,21 @@
          ppdEmitJCL(ppd, stdout, doc->job_id, doc->user, doc->title);
  
@@ -125,7 +125,7 @@
  
 diff -urNad cupsys-1.2.8~/locale/cups_fr.po cupsys-1.2.8/locale/cups_fr.po
 --- cupsys-1.2.8~/locale/cups_fr.po	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/locale/cups_fr.po	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/locale/cups_fr.po	2007-03-14 15:53:31.000000000 +0000
 @@ -2843,2848 +2843,3 @@
  #
  # End of "$Id$".
@@ -2977,7 +2977,7 @@
 -#
 diff -urNad cupsys-1.2.8~/pdftops/pdftops.cxx cupsys-1.2.8/pdftops/pdftops.cxx
 --- cupsys-1.2.8~/pdftops/pdftops.cxx	2006-01-10 20:53:28.000000000 +0000
-+++ cupsys-1.2.8/pdftops/pdftops.cxx	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/pdftops/pdftops.cxx	2007-03-14 15:53:31.000000000 +0000
 @@ -279,9 +279,16 @@
  
    globalParams = new GlobalParams(buffer);
@@ -2999,8 +2999,8 @@
    globalParams->setPSExpandSmaller(fit);
    globalParams->setPSShrinkLarger(fit);
 diff -urNad cupsys-1.2.8~/scheduler/classes.c cupsys-1.2.8/scheduler/classes.c
---- cupsys-1.2.8~/scheduler/classes.c	2007-03-13 15:02:07.000000000 +0000
-+++ cupsys-1.2.8/scheduler/classes.c	2007-03-13 15:02:07.000000000 +0000
+--- cupsys-1.2.8~/scheduler/classes.c	2007-03-14 15:53:31.000000000 +0000
++++ cupsys-1.2.8/scheduler/classes.c	2007-03-14 15:53:31.000000000 +0000
 @@ -3,7 +3,7 @@
   *
   *   Printer class routines for the Common UNIX Printing System (CUPS).
@@ -3086,7 +3086,7 @@
      {
 diff -urNad cupsys-1.2.8~/scheduler/client.c cupsys-1.2.8/scheduler/client.c
 --- cupsys-1.2.8~/scheduler/client.c	2007-02-07 20:54:37.000000000 +0000
-+++ cupsys-1.2.8/scheduler/client.c	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/scheduler/client.c	2007-03-14 15:53:31.000000000 +0000
 @@ -3472,7 +3472,7 @@
    int		pid,			/* Process ID of command */
  		status;			/* Status of command */
@@ -3098,7 +3098,7 @@
  		infofile[1024],		/* Type-in information for cert */
 diff -urNad cupsys-1.2.8~/scheduler/cups-lpd.c cupsys-1.2.8/scheduler/cups-lpd.c
 --- cupsys-1.2.8~/scheduler/cups-lpd.c	2006-10-10 20:47:03.000000000 +0100
-+++ cupsys-1.2.8/scheduler/cups-lpd.c	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/scheduler/cups-lpd.c	2007-03-14 15:53:31.000000000 +0000
 @@ -96,7 +96,8 @@
  		            int destsize, cups_option_t **options,
  			    int *accepting, int *shared, ipp_pstate_t *state);
@@ -3139,7 +3139,7 @@
  		else
 diff -urNad cupsys-1.2.8~/scheduler/ipp.c cupsys-1.2.8/scheduler/ipp.c
 --- cupsys-1.2.8~/scheduler/ipp.c	2006-12-06 20:10:16.000000000 +0000
-+++ cupsys-1.2.8/scheduler/ipp.c	2007-03-13 15:02:37.000000000 +0000
++++ cupsys-1.2.8/scheduler/ipp.c	2007-03-14 15:53:31.000000000 +0000
 @@ -5466,9 +5466,6 @@
      if ((job->dtype & dmask) != dtype &&
          (!job->printer || (job->printer->type & dmask) != dtype))
@@ -3160,9178 +3160,9 @@
      if (count > 0)
        ippAddSeparator(con->response);
  
-diff -urNad cupsys-1.2.8~/scheduler/ipp.c.orig cupsys-1.2.8/scheduler/ipp.c.orig
---- cupsys-1.2.8~/scheduler/ipp.c.orig	1970-01-01 01:00:00.000000000 +0100
-+++ cupsys-1.2.8/scheduler/ipp.c.orig	2006-12-06 20:10:16.000000000 +0000
-@@ -0,0 +1,9165 @@
-+/*
-+ * "$Id: ipp.c 6145 2006-12-06 20:10:16Z mike $"
-+ *
-+ *   IPP routines for the Common UNIX Printing System (CUPS) scheduler.
-+ *
-+ *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
-+ *
-+ *   These coded instructions, statements, and computer programs are the
-+ *   property of Easy Software Products and are protected by Federal
-+ *   copyright law.  Distribution and use rights are outlined in the file
-+ *   "LICENSE.txt" which should have been included with this file.  If this
-+ *   file is missing or damaged please contact Easy Software Products
-+ *   at:
-+ *
-+ *       Attn: CUPS Licensing Information
-+ *       Easy Software Products
-+ *       44141 Airport View Drive, Suite 204
-+ *       Hollywood, Maryland 20636 USA
-+ *
-+ *       Voice: (301) 373-9600
-+ *       EMail: cups-info at cups.org
-+ *         WWW: http://www.cups.org
-+ *
-+ * Contents:
-+ *
-+ *   cupsdProcessIPPRequest()    - Process an incoming IPP request...
-+ *   accept_jobs()               - Accept print jobs to a printer.
-+ *   add_class()                 - Add a class to the system.
-+ *   add_file()                  - Add a file to a job.
-+ *   add_job()                   - Add a job to a print queue.
-+ *   add_job_state_reasons()     - Add the "job-state-reasons" attribute based
-+ *                                 upon the job and printer state...
-+ *   add_job_subscriptions()     - Add any subcriptions for a job.
-+ *   add_job_uuid()              - Add job-uuid attribute to a job.
-+ *   add_printer()               - Add a printer to the system.
-+ *   add_printer_state_reasons() - Add the "printer-state-reasons" attribute
-+ *                                 based upon the printer state...
-+ *   add_queued_job_count()      - Add the "queued-job-count" attribute for
-+ *   apply_printer_defaults()    - Apply printer default options to a job.
-+ *   authenticate_job()          - Set job authentication info.
-+ *   cancel_all_jobs()           - Cancel all print jobs.
-+ *   cancel_job()                - Cancel a print job.
-+ *   cancel_subscription()       - Cancel a subscription.
-+ *   check_quotas()              - Check quotas for a printer and user.
-+ *   copy_attribute()            - Copy a single attribute.
-+ *   copy_attrs()                - Copy attributes from one request to another.
-+ *   copy_banner()               - Copy a banner file to the requests directory
-+ *                                 for the specified job.
-+ *   copy_file()                 - Copy a PPD file or interface script...
-+ *   copy_model()                - Copy a PPD model file, substituting default
-+ *                                 values as needed...
-+ *   copy_job_attrs()            - Copy job attributes.
-+ *   copy_printer_attrs()        - Copy printer attributes.
-+ *   copy_subscription_attrs()   - Copy subscription attributes.
-+ *   create_job()                - Print a file to a printer or class.
-+ *   create_requested_array()    - Create an array for the requested-attributes.
-+ *   create_subscription()       - Create a notification subscription.
-+ *   delete_printer()            - Remove a printer or class from the system.
-+ *   get_default()               - Get the default destination.
-+ *   get_devices()               - Get the list of available devices on the
-+ *                                 local system.
-+ *   get_job_attrs()             - Get job attributes.
-+ *   get_jobs()                  - Get a list of jobs for the specified printer.
-+ *   get_notifications()         - Get events for a subscription.
-+ *   get_ppds()                  - Get the list of PPD files on the local
-+ *                                 system.
-+ *   get_printer_attrs()         - Get printer attributes.
-+ *   get_printers()              - Get a list of printers.
-+ *   get_subscription_attrs()    - Get subscription attributes.
-+ *   get_subscriptions()         - Get subscriptions.
-+ *   get_username()              - Get the username associated with a request.
-+ *   hold_job()                  - Hold a print job.
-+ *   move_job()                  - Move a job to a new destination.
-+ *   ppd_parse_line()            - Parse a PPD default line.
-+ *   print_job()                 - Print a file to a printer or class.
-+ *   read_ps_line()              - Read a line from a PS file...
-+ *   read_ps_job_ticket()        - Reads a job ticket embedded in a PS file.
-+ *   reject_jobs()               - Reject print jobs to a printer.
-+ *   release_job()               - Release a held print job.
-+ *   restart_job()               - Restart an old print job.
-+ *   save_auth_info()            - Save authentication information for a job.
-+ *   send_document()             - Send a file to a printer or class.
-+ *   send_http_error()           - Send a HTTP error back to the IPP client.
-+ *   send_ipp_status()           - Send a status back to the IPP client.
-+ *   set_default()               - Set the default destination...
-+ *   set_job_attrs()             - Set job attributes.
-+ *   set_printer_defaults()      - Set printer default options from a request.
-+ *   start_printer()             - Start a printer.
-+ *   stop_printer()              - Stop a printer.
-+ *   url_encode_attr()           - URL-encode a string attribute.
-+ *   user_allowed()              - See if a user is allowed to print to a queue.
-+ *   validate_job()              - Validate printer options and destination.
-+ *   validate_name()             - Make sure the printer name only contains
-+ *                                 valid chars.
-+ *   validate_user()             - Validate the user for the request.
-+ */
-+
-+/*
-+ * Include necessary headers...
-+ */
-+
-+#include "cupsd.h"
-+
-+#ifdef HAVE_LIBPAPER
-+#  include <paper.h>
-+#endif /* HAVE_LIBPAPER */
-+
-+
-+/*
-+ * Local functions...
-+ */
-+
-+static void	accept_jobs(cupsd_client_t *con, ipp_attribute_t *uri);
-+static void	add_class(cupsd_client_t *con, ipp_attribute_t *uri);
-+static int	add_file(cupsd_client_t *con, cupsd_job_t *job,
-+		         mime_type_t *filetype, int compression);
-+static cupsd_job_t *add_job(cupsd_client_t *con, ipp_attribute_t *uri,
-+		            cupsd_printer_t **dprinter,
-+			    mime_type_t *filetype);
-+static void	add_job_state_reasons(cupsd_client_t *con, cupsd_job_t *job);
-+static void	add_job_subscriptions(cupsd_client_t *con, cupsd_job_t *job);
-+static void	add_job_uuid(cupsd_client_t *con, cupsd_job_t *job);
-+static void	add_printer(cupsd_client_t *con, ipp_attribute_t *uri);
-+static void	add_printer_state_reasons(cupsd_client_t *con,
-+		                          cupsd_printer_t *p);
-+static void	add_queued_job_count(cupsd_client_t *con, cupsd_printer_t *p);
-+static void	apply_printer_defaults(cupsd_printer_t *printer,
-+				       cupsd_job_t *job);
-+static void	authenticate_job(cupsd_client_t *con, ipp_attribute_t *uri);
-+static void	cancel_all_jobs(cupsd_client_t *con, ipp_attribute_t *uri);
-+static void	cancel_job(cupsd_client_t *con, ipp_attribute_t *uri);
-+static void	cancel_subscription(cupsd_client_t *con, int id);
-+static int	check_quotas(cupsd_client_t *con, cupsd_printer_t *p);
-+static ipp_attribute_t	*copy_attribute(ipp_t *to, ipp_attribute_t *attr,
-+		                        int quickcopy);
-+static void	copy_attrs(ipp_t *to, ipp_t *from, cups_array_t *ra,
-+		           ipp_tag_t group, int quickcopy);
-+static int	copy_banner(cupsd_client_t *con, cupsd_job_t *job,
-+		            const char *name);
-+static int	copy_file(const char *from, const char *to);
-+static int	copy_model(cupsd_client_t *con, const char *from,
-+		           const char *to);
-+static void	copy_job_attrs(cupsd_client_t *con,
-+		               cupsd_job_t *job,
-+			       cups_array_t *ra);
-+static void	copy_printer_attrs(cupsd_client_t *con,
-+		                   cupsd_printer_t *printer,
-+				   cups_array_t *ra);
-+static void	copy_subscription_attrs(cupsd_client_t *con,
-+		                        cupsd_subscription_t *sub,
-+					cups_array_t *ra);
-+static void	create_job(cupsd_client_t *con, ipp_attribute_t *uri);
-+static cups_array_t *create_requested_array(ipp_t *request);
-+static void	create_subscription(cupsd_client_t *con, ipp_attribute_t *uri);
-+static void	delete_printer(cupsd_client_t *con, ipp_attribute_t *uri);
-+static void	get_default(cupsd_client_t *con);
-+static void	get_devices(cupsd_client_t *con);
-+static void	get_jobs(cupsd_client_t *con, ipp_attribute_t *uri);
-+static void	get_job_attrs(cupsd_client_t *con, ipp_attribute_t *uri);
-+static void	get_notifications(cupsd_client_t *con);
-+static void	get_ppds(cupsd_client_t *con);
-+static void	get_printers(cupsd_client_t *con, int type);
-+static void	get_printer_attrs(cupsd_client_t *con, ipp_attribute_t *uri);
-+static void	get_subscription_attrs(cupsd_client_t *con, int sub_id);
-+static void	get_subscriptions(cupsd_client_t *con, ipp_attribute_t *uri);
-+static const char *get_username(cupsd_client_t *con);
-+static void	hold_job(cupsd_client_t *con, ipp_attribute_t *uri);
-+static void	move_job(cupsd_client_t *con, ipp_attribute_t *uri);
-+static int	ppd_parse_line(const char *line, char *option, int olen,
-+		               char *choice, int clen);
-+static void	print_job(cupsd_client_t *con, ipp_attribute_t *uri);
-+static void	read_ps_job_ticket(cupsd_client_t *con);
-+static void	reject_jobs(cupsd_client_t *con, ipp_attribute_t *uri);
-+static void	release_job(cupsd_client_t *con, ipp_attribute_t *uri);
-+static void	renew_subscription(cupsd_client_t *con, int sub_id);
-+static void	restart_job(cupsd_client_t *con, ipp_attribute_t *uri);
-+static void	save_auth_info(cupsd_client_t *con, cupsd_job_t *job);
-+static void	send_document(cupsd_client_t *con, ipp_attribute_t *uri);
-+static void	send_http_error(cupsd_client_t *con, http_status_t status);
-+static void	send_ipp_status(cupsd_client_t *con, ipp_status_t status,
-+		                const char *message, ...)
-+#    ifdef __GNUC__
-+__attribute__ ((__format__ (__printf__, 3, 4)))
-+#    endif /* __GNUC__ */
-+;
-+static void	set_default(cupsd_client_t *con, ipp_attribute_t *uri);
-+static void	set_job_attrs(cupsd_client_t *con, ipp_attribute_t *uri);
-+static void	set_printer_defaults(cupsd_client_t *con,
-+		                     cupsd_printer_t *printer);
-+static void	start_printer(cupsd_client_t *con, ipp_attribute_t *uri);
-+static void	stop_printer(cupsd_client_t *con, ipp_attribute_t *uri);
-+static void	url_encode_attr(ipp_attribute_t *attr, char *buffer,
-+		                int bufsize);
-+static int	user_allowed(cupsd_printer_t *p, const char *username);
-+static void	validate_job(cupsd_client_t *con, ipp_attribute_t *uri);
-+static int	validate_name(const char *name);
-+static int	validate_user(cupsd_job_t *job, cupsd_client_t *con,
-+		              const char *owner, char *username,
-+		              int userlen);
-+
-+
-+/*
-+ * 'cupsdProcessIPPRequest()' - Process an incoming IPP request...
-+ */
-+
-+int					/* O - 1 on success, 0 on failure */
-+cupsdProcessIPPRequest(
-+    cupsd_client_t *con)		/* I - Client connection */
-+{
-+  ipp_tag_t		group;		/* Current group tag */
-+  ipp_attribute_t	*attr;		/* Current attribute */
-+  ipp_attribute_t	*charset;	/* Character set attribute */
-+  ipp_attribute_t	*language;	/* Language attribute */
-+  ipp_attribute_t	*uri;		/* Printer URI attribute */
-+  ipp_attribute_t	*username;	/* requesting-user-name attr */
-+  int			sub_id;		/* Subscription ID */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-+                  "cupsdProcessIPPRequest(%p[%d]): operation_id = %04x",
-+                  con, con->http.fd, con->request->request.op.operation_id);
-+
-+ /*
-+  * First build an empty response message for this request...
-+  */
-+
-+  con->response = ippNew();
-+
-+  con->response->request.status.version[0] = con->request->request.op.version[0];
-+  con->response->request.status.version[1] = con->request->request.op.version[1];
-+  con->response->request.status.request_id = con->request->request.op.request_id;
-+
-+ /*
-+  * Then validate the request header and required attributes...
-+  */
-+  
-+  if (con->request->request.any.version[0] != 1)
-+  {
-+   /*
-+    * Return an error, since we only support IPP 1.x.
-+    */
-+
-+    cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL,
-+                  "%04X %s Bad request version number %d.%d",
-+		  IPP_VERSION_NOT_SUPPORTED, con->http.hostname,
-+                  con->request->request.any.version[0],
-+	          con->request->request.any.version[1]);
-+
-+    send_ipp_status(con, IPP_VERSION_NOT_SUPPORTED,
-+                    _("Bad request version number %d.%d!"),
-+		    con->request->request.any.version[0],
-+	            con->request->request.any.version[1]);
-+  }  
-+  else if (!con->request->attrs)
-+  {
-+    cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL,
-+                  "%04X %s No attributes in request",
-+		  IPP_BAD_REQUEST, con->http.hostname);
-+
-+    send_ipp_status(con, IPP_BAD_REQUEST, _("No attributes in request!"));
-+  }
-+  else
-+  {
-+   /*
-+    * Make sure that the attributes are provided in the correct order and
-+    * don't repeat groups...
-+    */
-+
-+    for (attr = con->request->attrs, group = attr->group_tag;
-+	 attr;
-+	 attr = attr->next)
-+      if (attr->group_tag < group && attr->group_tag != IPP_TAG_ZERO)
-+      {
-+       /*
-+	* Out of order; return an error...
-+	*/
-+
-+	cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL,
-+                      "%04X %s Attribute groups are out of order",
-+		      IPP_BAD_REQUEST, con->http.hostname);
-+
-+	send_ipp_status(con, IPP_BAD_REQUEST,
-+	                _("Attribute groups are out of order (%x < %x)!"),
-+			attr->group_tag, group);
-+	break;
-+      }
-+      else
-+	group = attr->group_tag;
-+
-+    if (!attr)
-+    {
-+     /*
-+      * Then make sure that the first three attributes are:
-+      *
-+      *     attributes-charset
-+      *     attributes-natural-language
-+      *     printer-uri/job-uri
-+      */
-+
-+      attr = con->request->attrs;
-+      if (attr && !strcmp(attr->name, "attributes-charset") &&
-+	  (attr->value_tag & IPP_TAG_MASK) == IPP_TAG_CHARSET)
-+	charset = attr;
-+      else
-+	charset = NULL;
-+
-+      if (attr)
-+        attr = attr->next;
-+
-+      if (attr && !strcmp(attr->name, "attributes-natural-language") &&
-+	  (attr->value_tag & IPP_TAG_MASK) == IPP_TAG_LANGUAGE)
-+	language = attr;
-+      else
-+	language = NULL;
-+
-+      if ((attr = ippFindAttribute(con->request, "printer-uri",
-+                                   IPP_TAG_URI)) != NULL)
-+	uri = attr;
-+      else if ((attr = ippFindAttribute(con->request, "job-uri",
-+                                        IPP_TAG_URI)) != NULL)
-+	uri = attr;
-+      else
-+	uri = NULL;
-+
-+      if (charset)
-+	ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
-+        	     "attributes-charset", NULL, charset->values[0].string.text);
-+      else
-+	ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
-+        	     "attributes-charset", NULL, DefaultCharset);
-+
-+      if (language)
-+	ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
-+                     "attributes-natural-language", NULL,
-+		     language->values[0].string.text);
-+      else
-+	ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
-+                     "attributes-natural-language", NULL, DefaultLanguage);
-+
-+      if (!charset || !language ||
-+	  (!uri &&
-+	   con->request->request.op.operation_id != CUPS_GET_DEFAULT &&
-+	   con->request->request.op.operation_id != CUPS_GET_PRINTERS &&
-+	   con->request->request.op.operation_id != CUPS_GET_CLASSES &&
-+	   con->request->request.op.operation_id != CUPS_GET_DEVICES &&
-+	   con->request->request.op.operation_id != CUPS_GET_PPDS))
-+      {
-+       /*
-+	* Return an error, since attributes-charset,
-+	* attributes-natural-language, and printer-uri/job-uri are required
-+	* for all operations.
-+	*/
-+
-+        if (!charset)
-+	{
-+	  cupsdLogMessage(CUPSD_LOG_ERROR,
-+	                  "Missing attributes-charset attribute!");
-+
-+	  cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL,
-+                	"%04X %s Missing attributes-charset attribute",
-+			IPP_BAD_REQUEST, con->http.hostname);
-+        }
-+
-+        if (!language)
-+	{
-+	  cupsdLogMessage(CUPSD_LOG_ERROR,
-+	                  "Missing attributes-natural-language attribute!");
-+
-+	  cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL,
-+                	"%04X %s Missing attributes-natural-language attribute",
-+			IPP_BAD_REQUEST, con->http.hostname);
-+        }
-+
-+        if (!uri)
-+	{
-+	  cupsdLogMessage(CUPSD_LOG_ERROR,
-+	                  "Missing printer-uri or job-uri attribute!");
-+
-+	  cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL,
-+                	"%04X %s Missing printer-uri or job-uri attribute",
-+			IPP_BAD_REQUEST, con->http.hostname);
-+        }
-+
-+	cupsdLogMessage(CUPSD_LOG_DEBUG, "Request attributes follow...");
-+
-+	for (attr = con->request->attrs; attr; attr = attr->next)
-+	  cupsdLogMessage(CUPSD_LOG_DEBUG, 
-+	        	  "attr \"%s\": group_tag = %x, value_tag = %x",
-+	        	  attr->name ? attr->name : "(null)", attr->group_tag,
-+			  attr->value_tag);
-+
-+	cupsdLogMessage(CUPSD_LOG_DEBUG, "End of attributes...");
-+
-+	send_ipp_status(con, IPP_BAD_REQUEST,
-+	                _("Missing required attributes!"));
-+      }
-+      else
-+      {
-+       /*
-+	* OK, all the checks pass so far; make sure requesting-user-name is
-+	* not "root" from a remote host...
-+	*/
-+
-+        if ((username = ippFindAttribute(con->request, "requesting-user-name",
-+	                                 IPP_TAG_NAME)) != NULL)
-+	{
-+	 /*
-+	  * Check for root user...
-+	  */
-+
-+	  if (!strcmp(username->values[0].string.text, "root") &&
-+	      strcasecmp(con->http.hostname, "localhost") &&
-+	      strcmp(con->username, "root"))
-+	  {
-+	   /*
-+	    * Remote unauthenticated user masquerading as local root...
-+	    */
-+
-+	    _cupsStrFree(username->values[0].string.text);
-+	    username->values[0].string.text = _cupsStrAlloc(RemoteRoot);
-+	  }
-+	}
-+
-+        if ((attr = ippFindAttribute(con->request, "notify-subscription-id",
-+	                             IPP_TAG_INTEGER)) != NULL)
-+	  sub_id = attr->values[0].integer;
-+	else
-+	  sub_id = 0;
-+
-+       /*
-+        * Then try processing the operation...
-+	*/
-+
-+        if (uri)
-+	  cupsdLogMessage(CUPSD_LOG_DEBUG, "%s %s",
-+                	  ippOpString(con->request->request.op.operation_id),
-+			  uri->values[0].string.text);
-+        else
-+	  cupsdLogMessage(CUPSD_LOG_DEBUG, "%s",
-+                	  ippOpString(con->request->request.op.operation_id));
-+
-+	switch (con->request->request.op.operation_id)
-+	{
-+	  case IPP_PRINT_JOB :
-+              print_job(con, uri);
-+              break;
-+
-+	  case IPP_VALIDATE_JOB :
-+              validate_job(con, uri);
-+              break;
-+
-+	  case IPP_CREATE_JOB :
-+              create_job(con, uri);
-+              break;
-+
-+	  case IPP_SEND_DOCUMENT :
-+              send_document(con, uri);
-+              break;
-+
-+	  case IPP_CANCEL_JOB :
-+              cancel_job(con, uri);
-+              break;
-+
-+	  case IPP_GET_JOB_ATTRIBUTES :
-+              get_job_attrs(con, uri);
-+              break;
-+
-+	  case IPP_GET_JOBS :
-+              get_jobs(con, uri);
-+              break;
-+
-+	  case IPP_GET_PRINTER_ATTRIBUTES :
-+              get_printer_attrs(con, uri);
-+              break;
-+
-+	  case IPP_HOLD_JOB :
-+              hold_job(con, uri);
-+              break;
-+
-+	  case IPP_RELEASE_JOB :
-+              release_job(con, uri);
-+              break;
-+
-+	  case IPP_RESTART_JOB :
-+              restart_job(con, uri);
-+              break;
-+
-+	  case IPP_PAUSE_PRINTER :
-+              stop_printer(con, uri);
-+	      break;
-+
-+	  case IPP_RESUME_PRINTER :
-+              start_printer(con, uri);
-+	      break;
-+
-+	  case IPP_PURGE_JOBS :
-+              cancel_all_jobs(con, uri);
-+              break;
-+
-+	  case IPP_SET_JOB_ATTRIBUTES :
-+              set_job_attrs(con, uri);
-+              break;
-+
-+	  case CUPS_GET_DEFAULT :
-+              get_default(con);
-+              break;
-+
-+	  case CUPS_GET_PRINTERS :
-+              get_printers(con, 0);
-+              break;
-+
-+	  case CUPS_GET_CLASSES :
-+              get_printers(con, CUPS_PRINTER_CLASS);
-+              break;
-+
-+	  case CUPS_ADD_PRINTER :
-+              add_printer(con, uri);
-+              break;
-+
-+	  case CUPS_DELETE_PRINTER :
-+              delete_printer(con, uri);
-+              break;
-+
-+	  case CUPS_ADD_CLASS :
-+              add_class(con, uri);
-+              break;
-+
-+	  case CUPS_DELETE_CLASS :
-+              delete_printer(con, uri);
-+              break;
-+
-+	  case CUPS_ACCEPT_JOBS :
-+	  case IPP_ENABLE_PRINTER :
-+              accept_jobs(con, uri);
-+              break;
-+
-+	  case CUPS_REJECT_JOBS :
-+	  case IPP_DISABLE_PRINTER :
-+              reject_jobs(con, uri);
-+              break;
-+
-+	  case CUPS_SET_DEFAULT :
-+              set_default(con, uri);
-+              break;
-+
-+	  case CUPS_GET_DEVICES :
-+              get_devices(con);
-+              break;
-+
-+	  case CUPS_GET_PPDS :
-+              get_ppds(con);
-+              break;
-+
-+	  case CUPS_MOVE_JOB :
-+              move_job(con, uri);
-+              break;
-+
-+	  case CUPS_AUTHENTICATE_JOB :
-+              authenticate_job(con, uri);
-+              break;
-+
-+          case IPP_CREATE_PRINTER_SUBSCRIPTION :
-+	  case IPP_CREATE_JOB_SUBSCRIPTION :
-+	      create_subscription(con, uri);
-+	      break;
-+
-+          case IPP_GET_SUBSCRIPTION_ATTRIBUTES :
-+	      get_subscription_attrs(con, sub_id);
-+	      break;
-+
-+	  case IPP_GET_SUBSCRIPTIONS :
-+	      get_subscriptions(con, uri);
-+	      break;
-+
-+	  case IPP_RENEW_SUBSCRIPTION :
-+	      renew_subscription(con, sub_id);
-+	      break;
-+
-+	  case IPP_CANCEL_SUBSCRIPTION :
-+	      cancel_subscription(con, sub_id);
-+	      break;
-+
-+          case IPP_GET_NOTIFICATIONS :
-+	      get_notifications(con);
-+	      break;
-+
-+	  default :
-+	      cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL,
-+                	    "%04X %s Operation %04X (%s) not supported",
-+			    IPP_OPERATION_NOT_SUPPORTED, con->http.hostname,
-+			    con->request->request.op.operation_id,
-+			    ippOpString(con->request->request.op.operation_id));
-+
-+              send_ipp_status(con, IPP_OPERATION_NOT_SUPPORTED,
-+	                      _("%s not supported!"),
-+			      ippOpString(con->request->request.op.operation_id));
-+	      break;
-+	}
-+      }
-+    }
-+  }
-+
-+  if (con->response)
-+  {
-+   /*
-+    * Sending data from the scheduler...
-+    */
-+
-+    cupsdLogMessage(CUPSD_LOG_DEBUG,
-+                    "cupsdProcessIPPRequest: %d status_code=%x (%s)",
-+                    con->http.fd, con->response->request.status.status_code,
-+	            ippErrorString(con->response->request.status.status_code));
-+
-+    if (cupsdSendHeader(con, HTTP_OK, "application/ipp"))
-+    {
-+#ifdef CUPSD_USE_CHUNKING
-+     /*
-+      * Because older versions of CUPS (1.1.17 and older) and some IPP
-+      * clients do not implement chunking properly, we cannot use
-+      * chunking by default.  This may become the default in future
-+      * CUPS releases, or we might add a configuration directive for
-+      * it.
-+      */
-+
-+      if (con->http.version == HTTP_1_1)
-+      {
-+	if (httpPrintf(HTTP(con), "Transfer-Encoding: chunked\r\n\r\n") < 0)
-+	  return (0);
-+
-+	if (cupsdFlushHeader(con) < 0)
-+	  return (0);
-+
-+	con->http.data_encoding = HTTP_ENCODE_CHUNKED;
-+      }
-+      else
-+#endif /* CUPSD_USE_CHUNKING */
-+      {
-+        size_t	length;			/* Length of response */
-+
-+
-+	length = ippLength(con->response);
-+
-+	if (httpPrintf(HTTP(con), "Content-Length: " CUPS_LLFMT "\r\n\r\n",
-+        	       CUPS_LLCAST length) < 0)
-+	  return (0);
-+
-+	if (cupsdFlushHeader(con) < 0)
-+	  return (0);
-+
-+	con->http.data_encoding  = HTTP_ENCODE_LENGTH;
-+	con->http.data_remaining = length;
-+      }
-+
-+      cupsdLogMessage(CUPSD_LOG_DEBUG2,
-+                      "cupsdProcessIPPRequest: Adding fd %d to OutputSet...",
-+        	      con->http.fd);
-+
-+      FD_SET(con->http.fd, OutputSet);
-+
-+     /*
-+      * Tell the caller the response header was sent successfully...
-+      */
-+
-+      return (1);
-+    }
-+    else
-+    {
-+     /*
-+      * Tell the caller the response header could not be sent...
-+      */
-+
-+      return (0);
-+    }
-+  }
-+  else
-+  {
-+   /*
-+    * Sending data from a subprocess like cups-deviced; tell the caller
-+    * everything is A-OK so far...
-+    */
-+
-+    return (1);
-+  }
-+}
-+
-+
-+/*
-+ * 'accept_jobs()' - Accept print jobs to a printer.
-+ */
-+
-+static void
-+accept_jobs(cupsd_client_t  *con,	/* I - Client connection */
-+            ipp_attribute_t *uri)	/* I - Printer or class URI */
-+{
-+  http_status_t	status;			/* Policy status */
-+  cups_ptype_t	dtype;			/* Destination type (printer or class) */
-+  char		method[HTTP_MAX_URI],	/* Method portion of URI */
-+		username[HTTP_MAX_URI],	/* Username portion of URI */
-+		host[HTTP_MAX_URI],	/* Host portion of URI */
-+		resource[HTTP_MAX_URI];	/* Resource portion of URI */
-+  int		port;			/* Port portion of URI */
-+  const char	*name;			/* Printer name */
-+  cupsd_printer_t *printer;		/* Printer data */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "accept_jobs(%p[%d], %s)", con,
-+                  con->http.fd, uri->values[0].string.text);
-+
-+ /*
-+  * Is the destination valid?
-+  */
-+
-+  httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
-+                  sizeof(method), username, sizeof(username), host,
-+		  sizeof(host), &port, resource, sizeof(resource));
-+
-+  if ((name = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL)
-+  {
-+   /*
-+    * Bad URI...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_FOUND,
-+                    _("The printer or class was not found."));
-+    return;
-+  }
-+
-+ /*
-+  * Check policy...
-+  */
-+
-+  if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
-+  {
-+    send_http_error(con, status);
-+    return;
-+  }
-+
-+ /*
-+  * Accept jobs sent to the printer...
-+  */
-+
-+  printer->accepting        = 1;
-+  printer->state_message[0] = '\0';
-+
-+  cupsdAddPrinterHistory(printer);
-+
-+  if (dtype & CUPS_PRINTER_CLASS)
-+    cupsdSaveAllClasses();
-+  else
-+    cupsdSaveAllPrinters();
-+
-+  cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" now accepting jobs (\"%s\").", name,
-+                  get_username(con));
-+
-+ /*
-+  * Everything was ok, so return OK status...
-+  */
-+
-+  con->response->request.status.status_code = IPP_OK;
-+}
-+
-+
-+/*
-+ * 'add_class()' - Add a class to the system.
-+ */
-+
-+static void
-+add_class(cupsd_client_t  *con,		/* I - Client connection */
-+          ipp_attribute_t *uri)		/* I - URI of class */
-+{
-+  http_status_t	status;			/* Policy status */
-+  int		i;			/* Looping var */
-+  char		method[HTTP_MAX_URI],	/* Method portion of URI */
-+		username[HTTP_MAX_URI],	/* Username portion of URI */
-+		host[HTTP_MAX_URI],	/* Host portion of URI */
-+		resource[HTTP_MAX_URI];	/* Resource portion of URI */
-+  int		port;			/* Port portion of URI */
-+  cupsd_printer_t *pclass,		/* Class */
-+		*member;		/* Member printer/class */
-+  cups_ptype_t	dtype;			/* Destination type */
-+  ipp_attribute_t *attr;		/* Printer attribute */
-+  int		modify;			/* Non-zero if we just modified */
-+  char		newname[IPP_MAX_NAME];	/* New class name */
-+  int		need_restart_job;	/* Need to restart job? */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_class(%p[%d], %s)", con,
-+                  con->http.fd, uri->values[0].string.text);
-+
-+ /*
-+  * Do we have a valid URI?
-+  */
-+
-+  httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
-+                  sizeof(method), username, sizeof(username), host,
-+		  sizeof(host), &port, resource, sizeof(resource));
-+
-+
-+  if (strncmp(resource, "/classes/", 9) || strlen(resource) == 9)
-+  {
-+   /*
-+    * No, return an error...
-+    */
-+
-+    send_ipp_status(con, IPP_BAD_REQUEST,
-+                    _("The printer-uri must be of the form "
-+		      "\"ipp://HOSTNAME/classes/CLASSNAME\"."));
-+    return;
-+  }
-+
-+ /*
-+  * Do we have a valid printer name?
-+  */
-+
-+  if (!validate_name(resource + 9))
-+  {
-+   /*
-+    * No, return an error...
-+    */
-+
-+    send_ipp_status(con, IPP_BAD_REQUEST,
-+                    _("The printer-uri \"%s\" contains invalid characters."),
-+		    uri->values[0].string.text);
-+    return;
-+  }
-+
-+ /*
-+  * Check policy...
-+  */
-+
-+  if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
-+  {
-+    send_http_error(con, status);
-+    return;
-+  }
-+
-+ /*
-+  * See if the class already exists; if not, create a new class...
-+  */
-+
-+  if ((pclass = cupsdFindClass(resource + 9)) == NULL)
-+  {
-+   /*
-+    * Class doesn't exist; see if we have a printer of the same name...
-+    */
-+
-+    if ((pclass = cupsdFindPrinter(resource + 9)) != NULL &&
-+        !(pclass->type & CUPS_PRINTER_REMOTE))
-+    {
-+     /*
-+      * Yes, return an error...
-+      */
-+
-+      send_ipp_status(con, IPP_NOT_POSSIBLE,
-+                      _("A printer named \"%s\" already exists!"),
-+		      resource + 9);
-+      return;
-+    }
-+
-+   /*
-+    * No, add the pclass...
-+    */
-+
-+    pclass = cupsdAddClass(resource + 9);
-+    modify = 0;
-+  }
-+  else if (pclass->type & CUPS_PRINTER_IMPLICIT)
-+  {
-+   /*
-+    * Rename the implicit class to "AnyClass" or remove it...
-+    */
-+
-+    if (ImplicitAnyClasses)
-+    {
-+      snprintf(newname, sizeof(newname), "Any%s", resource + 9);
-+      cupsdRenamePrinter(pclass, newname);
-+    }
-+    else
-+      cupsdDeletePrinter(pclass, 1);
-+
-+   /*
-+    * Add the class as a new local class...
-+    */
-+
-+    pclass = cupsdAddClass(resource + 9);
-+    modify = 0;
-+  }
-+  else if (pclass->type & CUPS_PRINTER_REMOTE)
-+  {
-+   /*
-+    * Rename the remote class to "Class"...
-+    */
-+
-+    snprintf(newname, sizeof(newname), "%s@%s", resource + 9, pclass->hostname);
-+    cupsdRenamePrinter(pclass, newname);
-+
-+   /*
-+    * Add the class as a new local class...
-+    */
-+
-+    pclass = cupsdAddClass(resource + 9);
-+    modify = 0;
-+  }
-+  else
-+    modify = 1;
-+
-+ /*
-+  * Look for attributes and copy them over as needed...
-+  */
-+
-+  need_restart_job = 0;
-+
-+  if ((attr = ippFindAttribute(con->request, "printer-location",
-+                               IPP_TAG_TEXT)) != NULL)
-+    cupsdSetString(&pclass->location, attr->values[0].string.text);
-+
-+  if ((attr = ippFindAttribute(con->request, "printer-info",
-+                               IPP_TAG_TEXT)) != NULL)
-+    cupsdSetString(&pclass->info, attr->values[0].string.text);
-+
-+  if ((attr = ippFindAttribute(con->request, "printer-is-accepting-jobs",
-+                               IPP_TAG_BOOLEAN)) != NULL)
-+  {
-+    cupsdLogMessage(CUPSD_LOG_INFO, "Setting %s printer-is-accepting-jobs to %d (was %d.)",
-+               pclass->name, attr->values[0].boolean, pclass->accepting);
-+
-+    pclass->accepting = attr->values[0].boolean;
-+    cupsdAddPrinterHistory(pclass);
-+  }
-+
-+  if ((attr = ippFindAttribute(con->request, "printer-is-shared",
-+                               IPP_TAG_BOOLEAN)) != NULL)
-+  {
-+    if (pclass->shared && !attr->values[0].boolean)
-+      cupsdSendBrowseDelete(pclass);
-+
-+    cupsdLogMessage(CUPSD_LOG_INFO,
-+                    "Setting %s printer-is-shared to %d (was %d.)",
-+                    pclass->name, attr->values[0].boolean, pclass->shared);
-+
-+    pclass->shared = attr->values[0].boolean;
-+  }
-+
-+  if ((attr = ippFindAttribute(con->request, "printer-state",
-+                               IPP_TAG_ENUM)) != NULL)
-+  {
-+    if (attr->values[0].integer != IPP_PRINTER_IDLE &&
-+        attr->values[0].integer != IPP_PRINTER_STOPPED)
-+    {
-+      send_ipp_status(con, IPP_BAD_REQUEST,
-+                      _("Attempt to set %s printer-state to bad value %d!"),
-+                      pclass->name, attr->values[0].integer);
-+      return;
-+    }
-+
-+    cupsdLogMessage(CUPSD_LOG_INFO, "Setting %s printer-state to %d (was %d.)", pclass->name,
-+                    attr->values[0].integer, pclass->state);
-+
-+    if (attr->values[0].integer == IPP_PRINTER_STOPPED)
-+      cupsdStopPrinter(pclass, 0);
-+    else
-+    {
-+      cupsdSetPrinterState(pclass, (ipp_pstate_t)(attr->values[0].integer), 0);
-+      need_restart_job = 1;
-+    }
-+  }
-+  if ((attr = ippFindAttribute(con->request, "printer-state-message",
-+                               IPP_TAG_TEXT)) != NULL)
-+  {
-+    strlcpy(pclass->state_message, attr->values[0].string.text,
-+            sizeof(pclass->state_message));
-+    cupsdAddPrinterHistory(pclass);
-+  }
-+  if ((attr = ippFindAttribute(con->request, "member-uris",
-+                               IPP_TAG_URI)) != NULL)
-+  {
-+   /*
-+    * Clear the printer array as needed...
-+    */
-+
-+    need_restart_job = 1;
-+
-+    if (pclass->num_printers > 0)
-+    {
-+      free(pclass->printers);
-+      pclass->num_printers = 0;
-+    }
-+
-+   /*
-+    * Add each printer or class that is listed...
-+    */
-+
-+    for (i = 0; i < attr->num_values; i ++)
-+    {
-+     /*
-+      * Search for the printer or class URI...
-+      */
-+
-+      httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[i].string.text, method,
-+                      sizeof(method), username, sizeof(username), host,
-+		      sizeof(host), &port, resource, sizeof(resource));
-+
-+      if (!cupsdValidateDest(host, resource, &dtype, &member))
-+      {
-+       /*
-+	* Bad URI...
-+	*/
-+
-+	send_ipp_status(con, IPP_NOT_FOUND,
-+                	_("The printer or class was not found."));
-+	return;
-+      }
-+
-+     /*
-+      * Add it to the class...
-+      */
-+
-+      cupsdAddPrinterToClass(pclass, member);
-+    }
-+  }
-+
-+  set_printer_defaults(con, pclass);
-+
-+ /*
-+  * Update the printer class attributes and return...
-+  */
-+
-+  cupsdSetPrinterAttrs(pclass);
-+  cupsdSaveAllClasses();
-+
-+  if (need_restart_job && pclass->job)
-+  {
-+    cupsd_job_t *job;
-+
-+   /*
-+    * Stop the current job and then restart it below...
-+    */
-+
-+    job = (cupsd_job_t *)pclass->job;
-+
-+    cupsdStopJob(job, 1);
-+
-+    job->state->values[0].integer = IPP_JOB_PENDING;
-+    job->state_value              = IPP_JOB_PENDING;
-+  }
-+
-+  if (need_restart_job)
-+    cupsdCheckJobs();
-+
-+  cupsdWritePrintcap();
-+
-+  if (modify)
-+  {
-+    cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED, pclass, NULL,
-+                  "Class \"%s\" modified by \"%s\".", pclass->name,
-+        	  get_username(con));
-+
-+    cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" modified by \"%s\".",
-+                    pclass->name, get_username(con));
-+  }
-+  else
-+  {
-+    cupsdAddPrinterHistory(pclass);
-+
-+    cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, pclass, NULL,
-+                  "New class \"%s\" added by \"%s\".", pclass->name,
-+        	  get_username(con));
-+
-+    cupsdLogMessage(CUPSD_LOG_INFO, "New class \"%s\" added by \"%s\".",
-+                    pclass->name, get_username(con));
-+  }
-+
-+  con->response->request.status.status_code = IPP_OK;
-+}
-+
-+
-+/*
-+ * 'add_file()' - Add a file to a job.
-+ */
-+
-+static int				/* O - 0 on success, -1 on error */
-+add_file(cupsd_client_t *con,		/* I - Connection to client */
-+         cupsd_job_t    *job,		/* I - Job to add to */
-+         mime_type_t    *filetype,	/* I - Type of file */
-+	 int            compression)	/* I - Compression */
-+{
-+  mime_type_t	**filetypes;		/* New filetypes array... */
-+  int		*compressions;		/* New compressions array... */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-+        	  "add_file(con=%p[%d], job=%d, filetype=%s/%s, compression=%d)",
-+        	  con, con->http.fd, job->id, filetype->super, filetype->type,
-+		  compression);
-+
-+ /*
-+  * Add the file to the job...
-+  */
-+
-+  if (job->num_files == 0)
-+  {
-+    compressions = (int *)malloc(sizeof(int));
-+    filetypes    = (mime_type_t **)malloc(sizeof(mime_type_t *));
-+  }
-+  else
-+  {
-+    compressions = (int *)realloc(job->compressions,
-+                                  (job->num_files + 1) * sizeof(int));
-+    filetypes    = (mime_type_t **)realloc(job->filetypes,
-+                                           (job->num_files + 1) *
-+					   sizeof(mime_type_t *));
-+  }
-+
-+  if (!compressions || !filetypes)
-+  {
-+    cupsdCancelJob(job, 1, IPP_JOB_ABORTED);
-+
-+    send_ipp_status(con, IPP_INTERNAL_ERROR,
-+                    _("Unable to allocate memory for file types!"));
-+    return (-1);
-+  }
-+
-+  job->compressions                 = compressions;
-+  job->compressions[job->num_files] = compression;
-+  job->filetypes                    = filetypes;
-+  job->filetypes[job->num_files]    = filetype;
-+
-+  job->num_files ++;
-+
-+  return (0);
-+}
-+
-+
-+/*
-+ * 'add_job()' - Add a job to a print queue.
-+ */
-+
-+static cupsd_job_t *			/* O - Job object */
-+add_job(cupsd_client_t  *con,		/* I - Client connection */
-+        ipp_attribute_t *uri,		/* I - printer-uri */
-+	cupsd_printer_t **dprinter,	/* I - Destination printer */
-+	mime_type_t     *filetype)	/* I - First print file type, if any */
-+{
-+  http_status_t	status;			/* Policy status */
-+  ipp_attribute_t *attr;		/* Current attribute */
-+  const char	*dest;			/* Destination */
-+  cups_ptype_t	dtype;			/* Destination type (printer or class) */
-+  const char	*val;			/* Default option value */
-+  int		priority;		/* Job priority */
-+  char		*title;			/* Job name/title */
-+  cupsd_job_t	*job;			/* Current job */
-+  char		job_uri[HTTP_MAX_URI],	/* Job URI */
-+		method[HTTP_MAX_URI],	/* Method portion of URI */
-+		username[HTTP_MAX_URI],	/* Username portion of URI */
-+		host[HTTP_MAX_URI],	/* Host portion of URI */
-+		resource[HTTP_MAX_URI];	/* Resource portion of URI */
-+  int		port;			/* Port portion of URI */
-+  cupsd_printer_t *printer;		/* Printer data */
-+  int		kbytes;			/* Size of print file */
-+  int		i;			/* Looping var */
-+  int		lowerpagerange;		/* Page range bound */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_job(%p[%d], %s)", con,
-+                  con->http.fd, uri->values[0].string.text);
-+
-+ /*
-+  * Is the destination valid?
-+  */
-+
-+  httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
-+                  sizeof(method), username, sizeof(username), host,
-+		  sizeof(host), &port, resource, sizeof(resource));
-+
-+  if ((dest = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL)
-+  {
-+   /*
-+    * Bad URI...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_FOUND,
-+                    _("The printer or class was not found."));
-+    return (NULL);
-+  }
-+
-+  if (dprinter)
-+    *dprinter = printer;
-+
-+ /*
-+  * Check remote printing to non-shared printer...
-+  */
-+
-+  if (!printer->shared &&
-+      strcasecmp(con->http.hostname, "localhost") &&
-+      strcasecmp(con->http.hostname, ServerName))
-+  {
-+    send_ipp_status(con, IPP_NOT_AUTHORIZED,
-+                    _("The printer or class is not shared!"));
-+    return (NULL);
-+  }
-+
-+ /*
-+  * Check policy...
-+  */
-+
-+  if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
-+  {
-+    send_http_error(con, status);
-+    return (NULL);
-+  }
-+  else if ((printer->type & CUPS_PRINTER_AUTHENTICATED) && !con->username[0])
-+  {
-+    send_http_error(con, HTTP_UNAUTHORIZED);
-+    return (NULL);
-+  }
-+
-+ /*
-+  * See if the printer is accepting jobs...
-+  */
-+
-+  if (!printer->accepting)
-+  {
-+    send_ipp_status(con, IPP_NOT_ACCEPTING,
-+                    _("Destination \"%s\" is not accepting jobs."),
-+                    dest);
-+    return (NULL);
-+  }
-+
-+ /*
-+  * Validate job template attributes; for now just document-format,
-+  * copies, and page-ranges...
-+  */
-+
-+  if (filetype && printer->filetypes &&
-+      !cupsArrayFind(printer->filetypes, filetype))
-+  {
-+    char	mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2];
-+					/* MIME media type string */
-+
-+
-+    snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super,
-+             filetype->type);
-+
-+    send_ipp_status(con, IPP_DOCUMENT_FORMAT,
-+                    _("Unsupported format \'%s\'!"), mimetype);
-+
-+    ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE,
-+                 "document-format", NULL, mimetype);
-+
-+    return (NULL);
-+  }
-+
-+  if ((attr = ippFindAttribute(con->request, "copies",
-+                               IPP_TAG_INTEGER)) != NULL)
-+  {
-+    if (attr->values[0].integer < 1 || attr->values[0].integer > MaxCopies)
-+    {
-+      send_ipp_status(con, IPP_ATTRIBUTES, _("Bad copies value %d."),
-+                      attr->values[0].integer);
-+      ippAddInteger(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_INTEGER,
-+	            "copies", attr->values[0].integer);
-+      return (NULL);
-+    }
-+  }
-+
-+  if ((attr = ippFindAttribute(con->request, "page-ranges",
-+                               IPP_TAG_RANGE)) != NULL)
-+  {
-+    for (i = 0, lowerpagerange = 1; i < attr->num_values; i ++)
-+    {
-+      if (attr->values[i].range.lower < lowerpagerange || 
-+	  attr->values[i].range.lower > attr->values[i].range.upper)
-+      {
-+	send_ipp_status(con, IPP_BAD_REQUEST,
-+	                _("Bad page-ranges values %d-%d."),
-+	                attr->values[i].range.lower,
-+			attr->values[i].range.upper);
-+	return (NULL);
-+      }
-+
-+      lowerpagerange = attr->values[i].range.upper + 1;
-+    }
-+  }
-+
-+ /*
-+  * Make sure we aren't over our limit...
-+  */
-+
-+  if (MaxJobs && cupsArrayCount(Jobs) >= MaxJobs)
-+    cupsdCleanJobs();
-+
-+  if (cupsArrayCount(Jobs) >= MaxJobs && MaxJobs)
-+  {
-+    send_ipp_status(con, IPP_NOT_POSSIBLE,
-+                    _("Too many active jobs."));
-+    return (NULL);
-+  }
-+
-+  if (!check_quotas(con, printer))
-+  {
-+    send_ipp_status(con, IPP_NOT_POSSIBLE, _("Quota limit reached."));
-+    return (NULL);
-+  }
-+
-+ /*
-+  * Create the job and set things up...
-+  */
-+
-+  if ((attr = ippFindAttribute(con->request, "job-priority",
-+                               IPP_TAG_INTEGER)) != NULL)
-+    priority = attr->values[0].integer;
-+  else
-+  {
-+    if ((val = cupsGetOption("job-priority", printer->num_options,
-+                             printer->options)) != NULL)
-+      priority = atoi(val);
-+    else
-+      priority = 50;
-+
-+    ippAddInteger(con->request, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-priority",
-+                  priority);
-+  }
-+
-+  if ((attr = ippFindAttribute(con->request, "job-name",
-+                               IPP_TAG_NAME)) != NULL)
-+    title = attr->values[0].string.text;
-+  else
-+    ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL,
-+                 title = "Untitled");
-+
-+  if ((job = cupsdAddJob(priority, printer->name)) == NULL)
-+  {
-+    send_ipp_status(con, IPP_INTERNAL_ERROR,
-+                    _("Unable to add job for destination \"%s\"!"), dest);
-+    return (NULL);
-+  }
-+
-+  job->dtype   = dtype;
-+  job->attrs   = con->request;
-+  con->request = ippNewRequest(job->attrs->request.op.operation_id);
-+
-+  add_job_uuid(con, job);
-+  apply_printer_defaults(printer, job);
-+
-+  attr = ippFindAttribute(job->attrs, "requesting-user-name", IPP_TAG_NAME);
-+
-+  if (con->username[0])
-+  {
-+    cupsdSetString(&job->username, con->username);
-+
-+    if (attr)
-+      cupsdSetString(&attr->values[0].string.text, con->username);
-+
-+    save_auth_info(con, job);
-+  }
-+  else if (attr)
-+  {
-+    cupsdLogMessage(CUPSD_LOG_DEBUG,
-+                    "add_job: requesting-user-name=\"%s\"",
-+                    attr->values[0].string.text);
-+
-+    cupsdSetString(&job->username, attr->values[0].string.text);
-+  }
-+  else
-+    cupsdSetString(&job->username, "anonymous");
-+
-+  if (!attr)
-+    ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME,
-+                 "job-originating-user-name", NULL, job->username);
-+  else
-+  {
-+    attr->group_tag = IPP_TAG_JOB;
-+    _cupsStrFree(attr->name);
-+    attr->name = _cupsStrAlloc("job-originating-user-name");
-+  }
-+
-+  if ((attr = ippFindAttribute(job->attrs, "job-originating-host-name",
-+                               IPP_TAG_ZERO)) != NULL)
-+  {
-+   /*
-+    * Request contains a job-originating-host-name attribute; validate it...
-+    */
-+
-+    if (attr->value_tag != IPP_TAG_NAME ||
-+        attr->num_values != 1 ||
-+        strcmp(con->http.hostname, "localhost"))
-+    {
-+     /*
-+      * Can't override the value if we aren't connected via localhost.
-+      * Also, we can only have 1 value and it must be a name value.
-+      */
-+
-+      switch (attr->value_tag)
-+      {
-+        case IPP_TAG_STRING :
-+	case IPP_TAG_TEXTLANG :
-+	case IPP_TAG_NAMELANG :
-+	case IPP_TAG_TEXT :
-+	case IPP_TAG_NAME :
-+	case IPP_TAG_KEYWORD :
-+	case IPP_TAG_URI :
-+	case IPP_TAG_URISCHEME :
-+	case IPP_TAG_CHARSET :
-+	case IPP_TAG_LANGUAGE :
-+	case IPP_TAG_MIMETYPE :
-+	   /*
-+	    * Free old strings...
-+	    */
-+
-+	    for (i = 0; i < attr->num_values; i ++)
-+	    {
-+	      _cupsStrFree(attr->values[i].string.text);
-+	      attr->values[i].string.text = NULL;
-+	      if (attr->values[i].string.charset)
-+	      {
-+		_cupsStrFree(attr->values[i].string.charset);
-+		attr->values[i].string.charset = NULL;
-+	      }
-+            }
-+
-+	default :
-+            break;
-+      }
-+
-+     /*
-+      * Use the default connection hostname instead...
-+      */
-+
-+      attr->value_tag             = IPP_TAG_NAME;
-+      attr->num_values            = 1;
-+      attr->values[0].string.text = _cupsStrAlloc(con->http.hostname);
-+    }
-+
-+    attr->group_tag = IPP_TAG_JOB;
-+  }
-+  else
-+  {
-+   /*
-+    * No job-originating-host-name attribute, so use the hostname from
-+    * the connection...
-+    */
-+
-+    ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, 
-+        	 "job-originating-host-name", NULL, con->http.hostname);
-+  }
-+
-+  ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "time-at-creation",
-+                time(NULL));
-+  attr = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER,
-+                       "time-at-processing", 0);
-+  attr->value_tag = IPP_TAG_NOVALUE;
-+  attr = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER,
-+                       "time-at-completed", 0);
-+  attr->value_tag = IPP_TAG_NOVALUE;
-+
-+ /*
-+  * Add remaining job attributes...
-+  */
-+
-+  ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id);
-+  job->state = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_ENUM,
-+                             "job-state", IPP_JOB_STOPPED);
-+  job->state_value = (ipp_jstate_t)job->state->values[0].integer;
-+  job->sheets = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER,
-+                              "job-media-sheets-completed", 0);
-+  ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri", NULL,
-+               printer->uri);
-+  ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL,
-+               title);
-+
-+  if ((attr = ippFindAttribute(job->attrs, "job-k-octets",
-+                               IPP_TAG_INTEGER)) != NULL)
-+    attr->values[0].integer = 0;
-+  else
-+    attr = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER,
-+                         "job-k-octets", 0);
-+
-+  if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
-+                               IPP_TAG_KEYWORD)) == NULL)
-+    attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
-+  if (!attr)
-+  {
-+    if ((val = cupsGetOption("job-hold-until", printer->num_options,
-+                             printer->options)) == NULL)
-+      val = "no-hold";
-+
-+    attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD,
-+                        "job-hold-until", NULL, val);
-+  }
-+  if (attr && strcmp(attr->values[0].string.text, "no-hold") &&
-+      !(printer->type & CUPS_PRINTER_REMOTE))
-+  {
-+   /*
-+    * Hold job until specified time...
-+    */
-+
-+    cupsdSetJobHoldUntil(job, attr->values[0].string.text);
-+
-+    job->state->values[0].integer = IPP_JOB_HELD;
-+    job->state_value              = IPP_JOB_HELD;
-+  }
-+  else if (job->attrs->request.op.operation_id == IPP_CREATE_JOB)
-+  {
-+    job->hold_until               = time(NULL) + 60;
-+    job->state->values[0].integer = IPP_JOB_HELD;
-+    job->state_value              = IPP_JOB_HELD;
-+  }
-+  else
-+  {
-+    job->state->values[0].integer = IPP_JOB_PENDING;
-+    job->state_value              = IPP_JOB_PENDING;
-+  }
-+
-+  if (!(printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) ||
-+      Classification)
-+  {
-+   /*
-+    * Add job sheets options...
-+    */
-+
-+    if ((attr = ippFindAttribute(job->attrs, "job-sheets",
-+                                 IPP_TAG_ZERO)) == NULL)
-+    {
-+      cupsdLogMessage(CUPSD_LOG_DEBUG,
-+                      "Adding default job-sheets values \"%s,%s\"...",
-+                      printer->job_sheets[0], printer->job_sheets[1]);
-+
-+      attr = ippAddStrings(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-sheets",
-+                           2, NULL, NULL);
-+      attr->values[0].string.text = _cupsStrAlloc(printer->job_sheets[0]);
-+      attr->values[1].string.text = _cupsStrAlloc(printer->job_sheets[1]);
-+    }
-+
-+    job->job_sheets = attr;
-+
-+   /*
-+    * Enforce classification level if set...
-+    */
-+
-+    if (Classification)
-+    {
-+      cupsdLogMessage(CUPSD_LOG_INFO,
-+                      "Classification=\"%s\", ClassifyOverride=%d",
-+                      Classification ? Classification : "(null)",
-+		      ClassifyOverride);
-+
-+      if (ClassifyOverride)
-+      {
-+        if (!strcmp(attr->values[0].string.text, "none") &&
-+	    (attr->num_values == 1 ||
-+	     !strcmp(attr->values[1].string.text, "none")))
-+        {
-+	 /*
-+          * Force the leading banner to have the classification on it...
-+	  */
-+
-+          cupsdSetString(&attr->values[0].string.text, Classification);
-+
-+	  cupsdLogMessage(CUPSD_LOG_NOTICE, "[Job %d] CLASSIFICATION FORCED "
-+	                		    "job-sheets=\"%s,none\", "
-+					    "job-originating-user-name=\"%s\"",
-+	        	 job->id, Classification, job->username);
-+	}
-+	else if (attr->num_values == 2 &&
-+	         strcmp(attr->values[0].string.text,
-+		        attr->values[1].string.text) &&
-+		 strcmp(attr->values[0].string.text, "none") &&
-+		 strcmp(attr->values[1].string.text, "none"))
-+        {
-+	 /*
-+	  * Can't put two different security markings on the same document!
-+	  */
-+
-+          cupsdSetString(&attr->values[1].string.text, attr->values[0].string.text);
-+
-+	  cupsdLogMessage(CUPSD_LOG_NOTICE, "[Job %d] CLASSIFICATION FORCED "
-+	                		    "job-sheets=\"%s,%s\", "
-+					    "job-originating-user-name=\"%s\"",
-+	        	 job->id, attr->values[0].string.text,
-+			 attr->values[1].string.text, job->username);
-+	}
-+	else if (strcmp(attr->values[0].string.text, Classification) &&
-+	         strcmp(attr->values[0].string.text, "none") &&
-+		 (attr->num_values == 1 ||
-+	          (strcmp(attr->values[1].string.text, Classification) &&
-+	           strcmp(attr->values[1].string.text, "none"))))
-+        {
-+	  if (attr->num_values == 1)
-+            cupsdLogMessage(CUPSD_LOG_NOTICE,
-+	                    "[Job %d] CLASSIFICATION OVERRIDDEN "
-+	                    "job-sheets=\"%s\", "
-+			    "job-originating-user-name=\"%s\"",
-+	               job->id, attr->values[0].string.text, job->username);
-+          else
-+            cupsdLogMessage(CUPSD_LOG_NOTICE,
-+	                    "[Job %d] CLASSIFICATION OVERRIDDEN "
-+	                    "job-sheets=\"%s,%s\",fffff "
-+			    "job-originating-user-name=\"%s\"",
-+	        	    job->id, attr->values[0].string.text,
-+			    attr->values[1].string.text, job->username);
-+        }
-+      }
-+      else if (strcmp(attr->values[0].string.text, Classification) &&
-+               (attr->num_values == 1 ||
-+	       strcmp(attr->values[1].string.text, Classification)))
-+      {
-+       /*
-+        * Force the banner to have the classification on it...
-+	*/
-+
-+        if (attr->num_values > 1 &&
-+	    !strcmp(attr->values[0].string.text, attr->values[1].string.text))
-+	{
-+          cupsdSetString(&(attr->values[0].string.text), Classification);
-+          cupsdSetString(&(attr->values[1].string.text), Classification);
-+	}
-+        else
-+	{
-+          if (attr->num_values == 1 ||
-+	      strcmp(attr->values[0].string.text, "none"))
-+            cupsdSetString(&(attr->values[0].string.text), Classification);
-+
-+          if (attr->num_values > 1 &&
-+	      strcmp(attr->values[1].string.text, "none"))
-+            cupsdSetString(&(attr->values[1].string.text), Classification);
-+        }
-+
-+        if (attr->num_values > 1)
-+	  cupsdLogMessage(CUPSD_LOG_NOTICE,
-+	                  "[Job %d] CLASSIFICATION FORCED "
-+	                  "job-sheets=\"%s,%s\", "
-+			  "job-originating-user-name=\"%s\"",
-+	        	  job->id, attr->values[0].string.text,
-+			  attr->values[1].string.text, job->username);
-+        else
-+	  cupsdLogMessage(CUPSD_LOG_NOTICE,
-+	                  "[Job %d] CLASSIFICATION FORCED "
-+	                  "job-sheets=\"%s\", "
-+			  "job-originating-user-name=\"%s\"",
-+	        	 job->id, Classification, job->username);
-+      }
-+    }
-+
-+   /*
-+    * See if we need to add the starting sheet...
-+    */
-+
-+    if (!(printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
-+    {
-+      cupsdLogMessage(CUPSD_LOG_INFO,
-+                      "Adding start banner page \"%s\" to job %d.",
-+                      attr->values[0].string.text, job->id);
-+
-+      kbytes = copy_banner(con, job, attr->values[0].string.text);
-+
-+      cupsdUpdateQuota(printer, job->username, 0, kbytes);
-+    }
-+  }
-+  else if ((attr = ippFindAttribute(job->attrs, "job-sheets",
-+                                    IPP_TAG_ZERO)) != NULL)
-+    job->sheets = attr;
-+
-+ /*
-+  * Fill in the response info...
-+  */
-+
-+  snprintf(job_uri, sizeof(job_uri), "http://%s:%d/jobs/%d", ServerName,
-+	   LocalPort, job->id);
-+
-+  ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL,
-+               job_uri);
-+
-+  ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id);
-+
-+  ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state",
-+                job->state_value);
-+  add_job_state_reasons(con, job);
-+
-+  con->response->request.status.status_code = IPP_OK;
-+
-+ /*
-+  * Add any job subscriptions...
-+  */
-+
-+  add_job_subscriptions(con, job);
-+
-+ /*
-+  * Set all but the first two attributes to the job attributes group...
-+  */
-+
-+  for (attr = job->attrs->attrs->next->next; attr; attr = attr->next)
-+    attr->group_tag = IPP_TAG_JOB;
-+
-+ /*
-+  * Fire the "job created" event...
-+  */
-+
-+  cupsdAddEvent(CUPSD_EVENT_JOB_CREATED, printer, job, "Job created.");
-+
-+ /*
-+  * Return the new job...
-+  */
-+
-+  return (job);
-+}
-+
-+
-+/*
-+ * 'add_job_state_reasons()' - Add the "job-state-reasons" attribute based
-+ *                             upon the job and printer state...
-+ */
-+
-+static void
-+add_job_state_reasons(
-+    cupsd_client_t *con,		/* I - Client connection */
-+    cupsd_job_t    *job)		/* I - Job info */
-+{
-+  cupsd_printer_t	*dest;		/* Destination printer */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_job_state_reasons(%p[%d], %d)",
-+                  con, con->http.fd, job ? job->id : 0);
-+
-+  switch (job ? job->state_value : IPP_JOB_CANCELED)
-+  {
-+    case IPP_JOB_PENDING :
-+	dest = cupsdFindDest(job->dest);
-+
-+        if (dest && dest->state == IPP_PRINTER_STOPPED)
-+          ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD,
-+	               "job-state-reasons", NULL, "printer-stopped");
-+        else
-+          ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD,
-+	               "job-state-reasons", NULL, "none");
-+        break;
-+
-+    case IPP_JOB_HELD :
-+        if (ippFindAttribute(job->attrs, "job-hold-until",
-+	                     IPP_TAG_KEYWORD) != NULL ||
-+	    ippFindAttribute(job->attrs, "job-hold-until",
-+	                     IPP_TAG_NAME) != NULL)
-+          ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD,
-+	               "job-state-reasons", NULL, "job-hold-until-specified");
-+        else
-+          ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD,
-+	               "job-state-reasons", NULL, "job-incoming");
-+        break;
-+
-+    case IPP_JOB_PROCESSING :
-+        ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD,
-+	             "job-state-reasons", NULL, "job-printing");
-+        break;
-+
-+    case IPP_JOB_STOPPED :
-+        ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD,
-+	             "job-state-reasons", NULL, "job-stopped");
-+        break;
-+
-+    case IPP_JOB_CANCELED :
-+        ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD,
-+	             "job-state-reasons", NULL, "job-canceled-by-user");
-+        break;
-+
-+    case IPP_JOB_ABORTED :
-+        ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD,
-+	             "job-state-reasons", NULL, "aborted-by-system");
-+        break;
-+
-+    case IPP_JOB_COMPLETED :
-+        ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD,
-+	             "job-state-reasons", NULL, "job-completed-successfully");
-+        break;
-+  }
-+}
-+
-+
-+/*
-+ * 'add_job_subscriptions()' - Add any subcriptions for a job.
-+ */
-+
-+static void
-+add_job_subscriptions(
-+    cupsd_client_t *con,		/* I - Client connection */
-+    cupsd_job_t    *job)		/* I - Newly created job */
-+{
-+  int			i;		/* Looping var */
-+  ipp_attribute_t	*prev,		/* Previous attribute */
-+			*next,		/* Next attribute */
-+			*attr;		/* Current attribute */
-+  cupsd_subscription_t	*sub;		/* Subscription object */
-+  const char		*recipient,	/* notify-recipient-uri */
-+			*pullmethod;	/* notify-pull-method */
-+  ipp_attribute_t	*user_data;	/* notify-user-data */
-+  int			interval;	/* notify-time-interval */
-+  unsigned		mask;		/* notify-events */
-+
-+
-+ /*
-+  * Find the first subscription group attribute; return if we have
-+  * none...
-+  */
-+
-+  for (attr = job->attrs->attrs, prev = NULL;
-+       attr;
-+       prev = attr, attr = attr->next)
-+    if (attr->group_tag == IPP_TAG_SUBSCRIPTION)
-+      break;
-+
-+  if (!attr)
-+    return;
-+
-+ /*
-+  * Process the subscription attributes in the request...
-+  */
-+
-+  while (attr)
-+  {
-+    recipient = NULL;
-+    pullmethod = NULL;
-+    user_data  = NULL;
-+    interval   = 0;
-+    mask       = CUPSD_EVENT_NONE;
-+
-+    while (attr && attr->group_tag != IPP_TAG_ZERO)
-+    {
-+      if (!strcmp(attr->name, "notify-recipient") &&
-+          attr->value_tag == IPP_TAG_URI)
-+        recipient = attr->values[0].string.text;
-+      else if (!strcmp(attr->name, "notify-pull-method") &&
-+               attr->value_tag == IPP_TAG_KEYWORD)
-+        pullmethod = attr->values[0].string.text;
-+      else if (!strcmp(attr->name, "notify-charset") &&
-+               attr->value_tag == IPP_TAG_CHARSET &&
-+	       strcmp(attr->values[0].string.text, "us-ascii") &&
-+	       strcmp(attr->values[0].string.text, "utf-8"))
-+      {
-+        send_ipp_status(con, IPP_CHARSET,
-+	                _("Character set \"%s\" not supported!"),
-+			attr->values[0].string.text);
-+	return;
-+      }
-+      else if (!strcmp(attr->name, "notify-natural-language") &&
-+               (attr->value_tag != IPP_TAG_LANGUAGE ||
-+	        strcmp(attr->values[0].string.text, DefaultLanguage)))
-+      {
-+        send_ipp_status(con, IPP_CHARSET,
-+	                _("Language \"%s\" not supported!"),
-+			attr->values[0].string.text);
-+	return;
-+      }
-+      else if (!strcmp(attr->name, "notify-user-data") &&
-+               attr->value_tag == IPP_TAG_STRING)
-+      {
-+        if (attr->num_values > 1 || attr->values[0].unknown.length > 63)
-+	{
-+          send_ipp_status(con, IPP_REQUEST_VALUE,
-+	                  _("The notify-user-data value is too large "
-+			    "(%d > 63 octets)!"),
-+			  attr->values[0].unknown.length);
-+	  return;
-+	}
-+
-+        user_data = attr;
-+      }
-+      else if (!strcmp(attr->name, "notify-events") &&
-+               attr->value_tag == IPP_TAG_KEYWORD)
-+      {
-+        for (i = 0; i < attr->num_values; i ++)
-+	  mask |= cupsdEventValue(attr->values[i].string.text);
-+      }
-+      else if (!strcmp(attr->name, "notify-lease-duration"))
-+      {
-+        send_ipp_status(con, IPP_BAD_REQUEST,
-+	                _("The notify-lease-duration attribute cannot be "
-+			  "used with job subscriptions."));
-+	return;
-+      }
-+      else if (!strcmp(attr->name, "notify-time-interval") &&
-+               attr->value_tag == IPP_TAG_INTEGER)
-+        interval = attr->values[0].integer;
-+
-+      attr = attr->next;
-+    }
-+
-+    if (!recipient && !pullmethod)
-+      break;
-+
-+    if (mask == CUPSD_EVENT_NONE)
-+      mask = CUPSD_EVENT_JOB_COMPLETED;
-+
-+    sub = cupsdAddSubscription(mask, cupsdFindDest(job->dest), job, recipient,
-+                               0);
-+
-+    sub->interval = interval;
-+
-+    cupsdSetString(&sub->owner, job->username);
-+
-+    if (user_data)
-+    {
-+      sub->user_data_len = user_data->values[0].unknown.length;
-+      memcpy(sub->user_data, user_data->values[0].unknown.data,
-+             sub->user_data_len);
-+    }
-+
-+    ippAddSeparator(con->response);
-+    ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
-+                  "notify-subscription-id", sub->id);
-+
-+    if (attr)
-+      attr = attr->next;
-+  }
-+
-+  cupsdSaveAllSubscriptions();
-+
-+ /*
-+  * Remove all of the subscription attributes from the job request...
-+  */
-+
-+  for (attr = job->attrs->attrs, prev = NULL; attr; attr = next)
-+  {
-+    next = attr->next;
-+
-+    if (attr->group_tag == IPP_TAG_SUBSCRIPTION ||
-+        attr->group_tag == IPP_TAG_ZERO)
-+    {
-+     /*
-+      * Free and remove this attribute...
-+      */
-+
-+      _ippFreeAttr(attr);
-+
-+      if (prev)
-+        prev->next = next;
-+      else
-+        job->attrs->attrs = next;
-+    }
-+    else
-+      prev = attr;
-+  }
-+
-+  job->attrs->last    = prev;
-+  job->attrs->current = prev;
-+}
-+
-+
-+/*
-+ * 'add_job_uuid()' - Add job-uuid attribute to a job.
-+ *
-+ * See RFC 4122 for the definition of UUIDs and the format.
-+ */
-+
-+static void
-+add_job_uuid(cupsd_client_t *con,	/* I - Client connection */
-+             cupsd_job_t    *job)	/* I - Job */
-+{
-+  char			uuid[1024];	/* job-uuid string */
-+  _cups_md5_state_t	md5state;	/* MD5 state */
-+  unsigned char		md5sum[16];	/* MD5 digest/sum */
-+
-+
-+ /*
-+  * First see if the job already has a job-uuid attribute; if so, return...
-+  */
-+
-+  if (ippFindAttribute(job->attrs, "job-uuid", IPP_TAG_URI))
-+    return;
-+
-+ /*
-+  * No job-uuid attribute, so build a version 3 UUID with the local job
-+  * ID at the end; see RFC 4122 for details.  Start with the MD5 sum of
-+  * the ServerName, server name and port that the client connected to,
-+  * and local job ID...
-+  */
-+
-+  snprintf(uuid, sizeof(uuid), "%s:%s:%d:%d", ServerName, con->servername,
-+	   con->serverport, job->id);
-+
-+  _cupsMD5Init(&md5state);
-+  _cupsMD5Append(&md5state, (unsigned char *)uuid, strlen(uuid));
-+  _cupsMD5Finish(&md5state, md5sum);
-+
-+ /*
-+  * Format the UUID URI using the MD5 sum and job ID.
-+  */
-+
-+  snprintf(uuid, sizeof(uuid),
-+           "urn:uuid:%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-"
-+	   "%02x%02x%02x%02x%02x%02x",
-+	   md5sum[0], md5sum[1], md5sum[2], md5sum[3], md5sum[4], md5sum[5],
-+	   (md5sum[6] & 15) | 0x30, md5sum[7], (md5sum[8] & 0x3f) | 0x40,
-+	   md5sum[9], md5sum[10], md5sum[11], md5sum[12], md5sum[13],
-+	   md5sum[14], md5sum[15]);
-+
-+  ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-uuid", NULL, uuid);
-+}
-+
-+
-+/*
-+ * 'add_printer()' - Add a printer to the system.
-+ */
-+
-+static void
-+add_printer(cupsd_client_t  *con,	/* I - Client connection */
-+            ipp_attribute_t *uri)	/* I - URI of printer */
-+{
-+  http_status_t	status;			/* Policy status */
-+  int		i;			/* Looping var */
-+  char		method[HTTP_MAX_URI],	/* Method portion of URI */
-+		username[HTTP_MAX_URI],	/* Username portion of URI */
-+		host[HTTP_MAX_URI],	/* Host portion of URI */
-+		resource[HTTP_MAX_URI];	/* Resource portion of URI */
-+  int		port;			/* Port portion of URI */
-+  cupsd_printer_t *printer;		/* Printer/class */
-+  ipp_attribute_t *attr;		/* Printer attribute */
-+  cups_file_t	*fp;			/* Script/PPD file */
-+  char		line[1024];		/* Line from file... */
-+  char		srcfile[1024],		/* Source Script/PPD file */
-+		dstfile[1024];		/* Destination Script/PPD file */
-+  int		modify;			/* Non-zero if we are modifying */
-+  char		newname[IPP_MAX_NAME];	/* New printer name */
-+  int		need_restart_job;	/* Need to restart job? */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_printer(%p[%d], %s)", con,
-+                  con->http.fd, uri->values[0].string.text);
-+
-+ /*
-+  * Do we have a valid URI?
-+  */
-+
-+  httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
-+                  sizeof(method), username, sizeof(username), host,
-+		  sizeof(host), &port, resource, sizeof(resource));
-+
-+  if (strncmp(resource, "/printers/", 10) || strlen(resource) == 10)
-+  {
-+   /*
-+    * No, return an error...
-+    */
-+
-+    send_ipp_status(con, IPP_BAD_REQUEST,
-+                    _("The printer-uri must be of the form "
-+		      "\"ipp://HOSTNAME/printers/PRINTERNAME\"."));
-+    return;
-+  }
-+
-+ /*
-+  * Do we have a valid printer name?
-+  */
-+
-+  if (!validate_name(resource + 10))
-+  {
-+   /*
-+    * No, return an error...
-+    */
-+
-+    send_ipp_status(con, IPP_BAD_REQUEST,
-+                    _("The printer-uri \"%s\" contains invalid characters."),
-+		    uri->values[0].string.text);
-+    return;
-+  }
-+
-+ /*
-+  * Check policy...
-+  */
-+
-+  if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
-+  {
-+    send_http_error(con, status);
-+    return;
-+  }
-+
-+ /*
-+  * See if the printer already exists; if not, create a new printer...
-+  */
-+
-+  if ((printer = cupsdFindPrinter(resource + 10)) == NULL)
-+  {
-+   /*
-+    * Printer doesn't exist; see if we have a class of the same name...
-+    */
-+
-+    if ((printer = cupsdFindClass(resource + 10)) != NULL &&
-+        !(printer->type & CUPS_PRINTER_REMOTE))
-+    {
-+     /*
-+      * Yes, return an error...
-+      */
-+
-+      send_ipp_status(con, IPP_NOT_POSSIBLE,
-+                      _("A class named \"%s\" already exists!"),
-+        	      resource + 10);
-+      return;
-+    }
-+
-+   /*
-+    * No, add the printer...
-+    */
-+
-+    printer = cupsdAddPrinter(resource + 10);
-+    modify  = 0;
-+  }
-+  else if (printer->type & CUPS_PRINTER_IMPLICIT)
-+  {
-+   /*
-+    * Rename the implicit printer to "AnyPrinter" or delete it...
-+    */
-+
-+    if (ImplicitAnyClasses)
-+    {
-+      snprintf(newname, sizeof(newname), "Any%s", resource + 10);
-+      cupsdRenamePrinter(printer, newname);
-+    }
-+    else
-+      cupsdDeletePrinter(printer, 1);
-+
-+   /*
-+    * Add the printer as a new local printer...
-+    */
-+
-+    printer = cupsdAddPrinter(resource + 10);
-+    modify  = 0;
-+  }
-+  else if (printer->type & CUPS_PRINTER_REMOTE)
-+  {
-+   /*
-+    * Rename the remote printer to "Printer at server"...
-+    */
-+
-+    snprintf(newname, sizeof(newname), "%s@%s", resource + 10,
-+             printer->hostname);
-+    cupsdRenamePrinter(printer, newname);
-+
-+   /*
-+    * Add the printer as a new local printer...
-+    */
-+
-+    printer = cupsdAddPrinter(resource + 10);
-+    modify  = 0;
-+  }
-+  else
-+    modify = 1;
-+
-+ /*
-+  * Look for attributes and copy them over as needed...
-+  */
-+
-+  need_restart_job = 0;
-+
-+  if ((attr = ippFindAttribute(con->request, "printer-location",
-+                               IPP_TAG_TEXT)) != NULL)
-+    cupsdSetString(&printer->location, attr->values[0].string.text);
-+
-+  if ((attr = ippFindAttribute(con->request, "printer-info",
-+                               IPP_TAG_TEXT)) != NULL)
-+    cupsdSetString(&printer->info, attr->values[0].string.text);
-+
-+  if ((attr = ippFindAttribute(con->request, "device-uri",
-+                               IPP_TAG_URI)) != NULL)
-+  {
-+   /*
-+    * Do we have a valid device URI?
-+    */
-+
-+    need_restart_job = 1;
-+
-+    httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[0].string.text, method,
-+                    sizeof(method), username, sizeof(username), host,
-+		    sizeof(host), &port, resource, sizeof(resource));
-+
-+    if (!strcmp(method, "file"))
-+    {
-+     /*
-+      * See if the administrator has enabled file devices...
-+      */
-+
-+      if (!FileDevice && strcmp(resource, "/dev/null"))
-+      {
-+       /*
-+        * File devices are disabled and the URL is not file:/dev/null...
-+	*/
-+
-+	send_ipp_status(con, IPP_NOT_POSSIBLE,
-+	                _("File device URIs have been disabled! "
-+	                  "To enable, see the FileDevice directive in "
-+			  "\"%s/cupsd.conf\"."),
-+			ServerRoot);
-+	return;
-+      }
-+    }
-+    else
-+    {
-+     /*
-+      * See if the backend exists and is executable...
-+      */
-+
-+      snprintf(srcfile, sizeof(srcfile), "%s/backend/%s", ServerBin, method);
-+      if (access(srcfile, X_OK))
-+      {
-+       /*
-+        * Could not find device in list!
-+	*/
-+
-+	send_ipp_status(con, IPP_NOT_POSSIBLE, _("Bad device-uri \"%s\"!"),
-+        	        attr->values[0].string.text);
-+	return;
-+      }
-+    }
-+
-+    cupsdLogMessage(CUPSD_LOG_INFO,
-+                    "Setting %s device-uri to \"%s\" (was \"%s\".)",
-+        	    printer->name,
-+		    cupsdSanitizeURI(attr->values[0].string.text, line,
-+		                     sizeof(line)),
-+		    cupsdSanitizeURI(printer->device_uri, resource,
-+		                     sizeof(resource)));
-+
-+    cupsdSetString(&printer->device_uri, attr->values[0].string.text);
-+  }
-+
-+  if ((attr = ippFindAttribute(con->request, "port-monitor",
-+                               IPP_TAG_KEYWORD)) != NULL)
-+  {
-+    ipp_attribute_t	*supported;	/* port-monitor-supported attribute */
-+
-+
-+    need_restart_job = 1;
-+
-+    supported = ippFindAttribute(printer->attrs, "port-monitor-supported",
-+                                 IPP_TAG_KEYWORD);
-+    for (i = 0; i < supported->num_values; i ++)
-+      if (!strcmp(supported->values[i].string.text,
-+                  attr->values[0].string.text))
-+        break;
-+
-+    if (i >= supported->num_values)
-+    {
-+      send_ipp_status(con, IPP_NOT_POSSIBLE, _("Bad port-monitor \"%s\"!"),
-+        	      attr->values[0].string.text);
-+      return;
-+    }
-+
-+    cupsdLogMessage(CUPSD_LOG_INFO,
-+                    "Setting %s port-monitor to \"%s\" (was \"%s\".)",
-+                    printer->name, attr->values[0].string.text,
-+	            printer->port_monitor);
-+
-+    if (strcmp(attr->values[0].string.text, "none"))
-+      cupsdSetString(&printer->port_monitor, attr->values[0].string.text);
-+    else
-+      cupsdClearString(&printer->port_monitor);
-+  }
-+
-+  if ((attr = ippFindAttribute(con->request, "printer-is-accepting-jobs",
-+                               IPP_TAG_BOOLEAN)) != NULL)
-+  {
-+    cupsdLogMessage(CUPSD_LOG_INFO,
-+                    "Setting %s printer-is-accepting-jobs to %d (was %d.)",
-+                    printer->name, attr->values[0].boolean, printer->accepting);
-+
-+    printer->accepting = attr->values[0].boolean;
-+    cupsdAddPrinterHistory(printer);
-+  }
-+
-+  if ((attr = ippFindAttribute(con->request, "printer-is-shared",
-+                               IPP_TAG_BOOLEAN)) != NULL)
-+  {
-+    if (printer->shared && !attr->values[0].boolean)
-+      cupsdSendBrowseDelete(printer);
-+
-+    cupsdLogMessage(CUPSD_LOG_INFO,
-+                    "Setting %s printer-is-shared to %d (was %d.)",
-+                    printer->name, attr->values[0].boolean, printer->shared);
-+
-+    printer->shared = attr->values[0].boolean;
-+  }
-+
-+  if ((attr = ippFindAttribute(con->request, "printer-state",
-+                               IPP_TAG_ENUM)) != NULL)
-+  {
-+    if (attr->values[0].integer != IPP_PRINTER_IDLE &&
-+        attr->values[0].integer != IPP_PRINTER_STOPPED)
-+    {
-+      send_ipp_status(con, IPP_BAD_REQUEST, _("Bad printer-state value %d!"),
-+                      attr->values[0].integer);
-+      return;
-+    }
-+
-+    cupsdLogMessage(CUPSD_LOG_INFO, "Setting %s printer-state to %d (was %d.)", printer->name,
-+               attr->values[0].integer, printer->state);
-+
-+    if (attr->values[0].integer == IPP_PRINTER_STOPPED)
-+      cupsdStopPrinter(printer, 0);
-+    else
-+    {
-+      need_restart_job = 1;
-+      cupsdSetPrinterState(printer, (ipp_pstate_t)(attr->values[0].integer), 0);
-+    }
-+  }
-+  if ((attr = ippFindAttribute(con->request, "printer-state-message",
-+                               IPP_TAG_TEXT)) != NULL)
-+  {
-+    strlcpy(printer->state_message, attr->values[0].string.text,
-+            sizeof(printer->state_message));
-+    cupsdAddPrinterHistory(printer);
-+  }
-+
-+  set_printer_defaults(con, printer);
-+
-+ /*
-+  * See if we have all required attributes...
-+  */
-+
-+  if (!printer->device_uri)
-+    cupsdSetString(&printer->device_uri, "file:///dev/null");
-+
-+ /*
-+  * See if we have an interface script or PPD file attached to the request...
-+  */
-+
-+  if (con->filename)
-+  {
-+    need_restart_job = 1;
-+
-+    strlcpy(srcfile, con->filename, sizeof(srcfile));
-+
-+    if ((fp = cupsFileOpen(srcfile, "rb")))
-+    {
-+     /*
-+      * Yes; get the first line from it...
-+      */
-+
-+      line[0] = '\0';
-+      cupsFileGets(fp, line, sizeof(line));
-+      cupsFileClose(fp);
-+
-+     /*
-+      * Then see what kind of file it is...
-+      */
-+
-+      snprintf(dstfile, sizeof(dstfile), "%s/interfaces/%s", ServerRoot,
-+               printer->name);
-+
-+      if (!strncmp(line, "*PPD-Adobe", 10))
-+      {
-+       /*
-+	* The new file is a PPD file, so remove any old interface script
-+	* that might be lying around...
-+	*/
-+
-+	unlink(dstfile);
-+      }
-+      else
-+      {
-+       /*
-+	* This must be an interface script, so move the file over to the
-+	* interfaces directory and make it executable...
-+	*/
-+
-+	if (copy_file(srcfile, dstfile))
-+	{
-+          send_ipp_status(con, IPP_INTERNAL_ERROR,
-+	                  _("Unable to copy interface script - %s!"),
-+	                  strerror(errno));
-+	  return;
-+	}
-+	else
-+	{
-+          cupsdLogMessage(CUPSD_LOG_DEBUG,
-+	                  "Copied interface script successfully!");
-+          chmod(dstfile, 0755);
-+	}
-+      }
-+
-+      snprintf(dstfile, sizeof(dstfile), "%s/ppd/%s.ppd", ServerRoot,
-+               printer->name);
-+
-+      if (!strncmp(line, "*PPD-Adobe", 10))
-+      {
-+       /*
-+	* The new file is a PPD file, so move the file over to the
-+	* ppd directory and make it readable by all...
-+	*/
-+
-+	if (copy_file(srcfile, dstfile))
-+	{
-+          send_ipp_status(con, IPP_INTERNAL_ERROR,
-+	                  _("Unable to copy PPD file - %s!"),
-+	                  strerror(errno));
-+	  return;
-+	}
-+	else
-+	{
-+          cupsdLogMessage(CUPSD_LOG_DEBUG,
-+	                  "Copied PPD file successfully!");
-+          chmod(dstfile, 0644);
-+	}
-+      }
-+      else
-+      {
-+       /*
-+	* This must be an interface script, so remove any old PPD file that
-+	* may be lying around...
-+	*/
-+
-+	unlink(dstfile);
-+      }
-+    }
-+  }
-+  else if ((attr = ippFindAttribute(con->request, "ppd-name",
-+                                    IPP_TAG_NAME)) != NULL)
-+  {
-+    need_restart_job = 1;
-+
-+    if (!strcmp(attr->values[0].string.text, "raw"))
-+    {
-+     /*
-+      * Raw driver, remove any existing PPD or interface script files.
-+      */
-+
-+      snprintf(dstfile, sizeof(dstfile), "%s/interfaces/%s", ServerRoot,
-+               printer->name);
-+      unlink(dstfile);
-+
-+      snprintf(dstfile, sizeof(dstfile), "%s/ppd/%s.ppd", ServerRoot,
-+               printer->name);
-+      unlink(dstfile);
-+    }
-+    else
-+    {
-+     /*
-+      * PPD model file...
-+      */
-+
-+      snprintf(dstfile, sizeof(dstfile), "%s/interfaces/%s", ServerRoot,
-+               printer->name);
-+      unlink(dstfile);
-+
-+      snprintf(dstfile, sizeof(dstfile), "%s/ppd/%s.ppd", ServerRoot,
-+               printer->name);
-+
-+      if (copy_model(con, attr->values[0].string.text, dstfile))
-+      {
-+        send_ipp_status(con, IPP_INTERNAL_ERROR, _("Unable to copy PPD file!"));
-+	return;
-+      }
-+      else
-+      {
-+        cupsdLogMessage(CUPSD_LOG_DEBUG,
-+	                "Copied PPD file successfully!");
-+        chmod(dstfile, 0644);
-+      }
-+    }
-+  }
-+
-+ /*
-+  * Update the printer attributes and return...
-+  */
-+
-+  cupsdSetPrinterAttrs(printer);
-+  cupsdSaveAllPrinters();
-+
-+  if (need_restart_job && printer->job)
-+  {
-+    cupsd_job_t *job;
-+
-+   /*
-+    * Stop the current job and then restart it below...
-+    */
-+
-+    job = (cupsd_job_t *)printer->job;
-+
-+    cupsdStopJob(job, 1);
-+
-+    job->state->values[0].integer = IPP_JOB_PENDING;
-+    job->state_value              = IPP_JOB_PENDING;
-+  }
-+
-+  if (need_restart_job)
-+    cupsdCheckJobs();
-+
-+  cupsdWritePrintcap();
-+
-+  if (modify)
-+  {
-+    cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED, printer, NULL,
-+                  "Printer \"%s\" modified by \"%s\".", printer->name,
-+        	  get_username(con));
-+
-+    cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" modified by \"%s\".",
-+                    printer->name, get_username(con));
-+  }
-+  else
-+  {
-+    cupsdAddPrinterHistory(printer);
-+
-+    cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, printer, NULL,
-+                  "New printer \"%s\" added by \"%s\".", printer->name,
-+        	  get_username(con));
-+
-+    cupsdLogMessage(CUPSD_LOG_INFO, "New printer \"%s\" added by \"%s\".",
-+                    printer->name, get_username(con));
-+  }
-+
-+  con->response->request.status.status_code = IPP_OK;
-+}
-+
-+
-+/*
-+ * 'add_printer_state_reasons()' - Add the "printer-state-reasons" attribute
-+ *                                 based upon the printer state...
-+ */
-+
-+static void
-+add_printer_state_reasons(
-+    cupsd_client_t  *con,		/* I - Client connection */
-+    cupsd_printer_t *p)			/* I - Printer info */
-+{
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-+                  "add_printer_state_reasons(%p[%d], %p[%s])",
-+                  con, con->http.fd, p, p->name);
-+
-+  if (p->num_reasons == 0)
-+    ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-+                 "printer-state-reasons", NULL,
-+		 p->state == IPP_PRINTER_STOPPED ? "paused" : "none");
-+  else
-+    ippAddStrings(con->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-+                  "printer-state-reasons", p->num_reasons, NULL,
-+		  (const char * const *)p->reasons);
-+}
-+
-+
-+/*
-+ * 'add_queued_job_count()' - Add the "queued-job-count" attribute for
-+ *                            the specified printer or class.
-+ */
-+
-+static void
-+add_queued_job_count(
-+    cupsd_client_t  *con,		/* I - Client connection */
-+    cupsd_printer_t *p)			/* I - Printer or class */
-+{
-+  int		count;			/* Number of jobs on destination */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_queued_job_count(%p[%d], %p[%s])",
-+                  con, con->http.fd, p, p->name);
-+
-+  count = cupsdGetPrinterJobCount(p->name);
-+
-+  ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
-+                "queued-job-count", count);
-+}
-+
-+
-+/*
-+ * 'apply_printer_defaults()' - Apply printer default options to a job.
-+ */
-+
-+static void
-+apply_printer_defaults(
-+    cupsd_printer_t *printer,		/* I - Printer */
-+    cupsd_job_t     *job)		/* I - Job */
-+{
-+  int		i,			/* Looping var */
-+		num_options;		/* Number of default options */
-+  cups_option_t	*options,		/* Default options */
-+		*option;		/* Current option */	
-+
-+
-+ /*
-+  * Collect all of the default options and add the missing ones to the
-+  * job object...
-+  */
-+
-+  for (i = printer->num_options, num_options = 0, option = printer->options;
-+       i > 0;
-+       i --, option ++)
-+    if (!ippFindAttribute(job->attrs, option->name, IPP_TAG_ZERO))
-+    {
-+      num_options = cupsAddOption(option->name, option->value, num_options,
-+                                  &options);
-+    }
-+
-+ /*
-+  * Encode these options as attributes in the job object...
-+  */
-+
-+  cupsEncodeOptions2(job->attrs, num_options, options, IPP_TAG_JOB);
-+  cupsFreeOptions(num_options, options);
-+}
-+
-+
-+/*
-+ * 'authenticate_job()' - Set job authentication info.
-+ */
-+
-+static void
-+authenticate_job(cupsd_client_t  *con,	/* I - Client connection */
-+	         ipp_attribute_t *uri)	/* I - Job URI */
-+{
-+  ipp_attribute_t	*attr;		/* Job-id attribute */
-+  int			jobid;		/* Job ID */
-+  cupsd_job_t		*job;		/* Current job */
-+  char			method[HTTP_MAX_URI],
-+					/* Method portion of URI */
-+			username[HTTP_MAX_URI],
-+					/* Username portion of URI */
-+			host[HTTP_MAX_URI],
-+					/* Host portion of URI */
-+			resource[HTTP_MAX_URI];
-+					/* Resource portion of URI */
-+  int			port;		/* Port portion of URI */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "authenticate_job(%p[%d], %s)",
-+                  con, con->http.fd, uri->values[0].string.text);
-+
-+ /*
-+  * Start with "everything is OK" status...
-+  */
-+
-+  con->response->request.status.status_code = IPP_OK;
-+
-+ /*
-+  * See if we have a job URI or a printer URI...
-+  */
-+
-+  if (!strcmp(uri->name, "printer-uri"))
-+  {
-+   /*
-+    * Got a printer URI; see if we also have a job-id attribute...
-+    */
-+
-+    if ((attr = ippFindAttribute(con->request, "job-id",
-+                                 IPP_TAG_INTEGER)) == NULL)
-+    {
-+      send_ipp_status(con, IPP_BAD_REQUEST,
-+                      _("Got a printer-uri attribute but no job-id!"));
-+      return;
-+    }
-+
-+    jobid = attr->values[0].integer;
-+  }
-+  else
-+  {
-+   /*
-+    * Got a job URI; parse it to get the job ID...
-+    */
-+
-+    httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
-+                    sizeof(method), username, sizeof(username), host,
-+		    sizeof(host), &port, resource, sizeof(resource));
-+ 
-+    if (strncmp(resource, "/jobs/", 6))
-+    {
-+     /*
-+      * Not a valid URI!
-+      */
-+
-+      send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri attribute \"%s\"!"),
-+                      uri->values[0].string.text);
-+      return;
-+    }
-+
-+    jobid = atoi(resource + 6);
-+  }
-+
-+ /*
-+  * See if the job exists...
-+  */
-+
-+  if ((job = cupsdFindJob(jobid)) == NULL)
-+  {
-+   /*
-+    * Nope - return a "not found" error...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_FOUND,
-+                    _("Job #%d does not exist!"), jobid);
-+    return;
-+  }
-+
-+ /*
-+  * See if the job has been completed...
-+  */
-+
-+  if (job->state_value != IPP_JOB_HELD)
-+  {
-+   /*
-+    * Return a "not-possible" error...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_POSSIBLE,
-+                    _("Job #%d is not held for authentication!"),
-+		    jobid);
-+    return;
-+  }
-+
-+ /*
-+  * See if we have already authenticated...
-+  */
-+
-+  if (!con->username[0])
-+  {
-+    send_ipp_status(con, IPP_NOT_AUTHORIZED,
-+                    _("No authentication information provided!"));
-+    return;
-+  }
-+
-+ /*
-+  * See if the job is owned by the requesting user...
-+  */
-+
-+  if (!validate_user(job, con, job->username, username, sizeof(username)))
-+  {
-+    send_http_error(con, HTTP_UNAUTHORIZED);
-+    return;
-+  }
-+
-+ /*
-+  * Save the authentication information for this job...
-+  */
-+
-+  save_auth_info(con, job);
-+
-+ /*
-+  * Reset the job-hold-until value to "no-hold"...
-+  */
-+
-+  if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
-+                               IPP_TAG_KEYWORD)) == NULL)
-+    attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
-+
-+  if (attr)
-+  {
-+    attr->value_tag = IPP_TAG_KEYWORD;
-+    cupsdSetString(&(attr->values[0].string.text), "no-hold");
-+  }
-+
-+ /*
-+  * Release the job and return...
-+  */
-+
-+  cupsdReleaseJob(job);
-+
-+  cupsdLogMessage(CUPSD_LOG_INFO, "Job %d was authenticated by \"%s\".", jobid,
-+                  con->username);
-+}
-+
-+
-+/*
-+ * 'cancel_all_jobs()' - Cancel all print jobs.
-+ */
-+
-+static void
-+cancel_all_jobs(cupsd_client_t  *con,	/* I - Client connection */
-+	        ipp_attribute_t *uri)	/* I - Job or Printer URI */
-+{
-+  http_status_t	status;			/* Policy status */
-+  const char	*dest;			/* Destination */
-+  cups_ptype_t	dtype;			/* Destination type */
-+  char		method[HTTP_MAX_URI],	/* Method portion of URI */
-+		userpass[HTTP_MAX_URI],	/* Username portion of URI */
-+		host[HTTP_MAX_URI],	/* Host portion of URI */
-+		resource[HTTP_MAX_URI];	/* Resource portion of URI */
-+  int		port;			/* Port portion of URI */
-+  ipp_attribute_t *attr;		/* Attribute in request */
-+  const char	*username;		/* Username */
-+  int		purge;			/* Purge? */
-+  cupsd_printer_t *printer;		/* Printer */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cancel_all_jobs(%p[%d], %s)", con,
-+                  con->http.fd, uri->values[0].string.text);
-+
-+ /*
-+  * See if we have a printer URI...
-+  */
-+
-+  if (strcmp(uri->name, "printer-uri"))
-+  {
-+    send_ipp_status(con, IPP_BAD_REQUEST,
-+                    _("The printer-uri attribute is required!"));
-+    return;
-+  }
-+
-+ /*
-+  * Get the username (if any) for the jobs we want to cancel (only if
-+  * "my-jobs" is specified...
-+  */
-+
-+  if ((attr = ippFindAttribute(con->request, "my-jobs",
-+                               IPP_TAG_BOOLEAN)) != NULL &&
-+      attr->values[0].boolean)
-+  {
-+    if ((attr = ippFindAttribute(con->request, "requesting-user-name",
-+                                 IPP_TAG_NAME)) != NULL)
-+      username = attr->values[0].string.text;
-+    else
-+    {
-+      send_ipp_status(con, IPP_BAD_REQUEST,
-+                      _("Missing requesting-user-name attribute!"));
-+      return;
-+    }
-+  }
-+  else
-+    username = NULL;
-+
-+ /*
-+  * Look for the "purge-jobs" attribute...
-+  */
-+
-+  if ((attr = ippFindAttribute(con->request, "purge-jobs",
-+                               IPP_TAG_BOOLEAN)) != NULL)
-+    purge = attr->values[0].boolean;
-+  else
-+    purge = 1;
-+
-+ /*
-+  * And if the destination is valid...
-+  */
-+
-+  httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
-+                  sizeof(method), userpass, sizeof(userpass), host,
-+		  sizeof(host), &port, resource, sizeof(resource));
-+
-+  if ((dest = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL)
-+  {
-+   /*
-+    * Bad URI?
-+    */
-+
-+    if ((!strncmp(resource, "/printers/", 10) && resource[10]) ||
-+        (!strncmp(resource, "/classes/", 9) && resource[9]))
-+    {
-+      send_ipp_status(con, IPP_NOT_FOUND,
-+                      _("The printer or class was not found."));
-+      return;
-+    }
-+    else if (strcmp(resource, "/printers/"))
-+    {
-+      send_ipp_status(con, IPP_NOT_FOUND,
-+                      _("The printer-uri \"%s\" is not valid."),
-+		      uri->values[0].string.text);
-+      return;
-+    }
-+
-+   /*
-+    * Check policy...
-+    */
-+
-+    if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
-+    {
-+      send_http_error(con, status);
-+      return;
-+    }
-+
-+   /*
-+    * Cancel all jobs on all printers...
-+    */
-+
-+    cupsdCancelJobs(NULL, username, purge);
-+
-+    cupsdLogMessage(CUPSD_LOG_INFO, "All jobs were %s by \"%s\".",
-+                    purge ? "purged" : "canceled", get_username(con));
-+  }
-+  else
-+  {
-+   /*
-+    * Check policy...
-+    */
-+
-+    if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
-+    {
-+      send_http_error(con, status);
-+      return;
-+    }
-+
-+   /*
-+    * Cancel all of the jobs on the named printer...
-+    */
-+
-+    cupsdCancelJobs(dest, username, purge);
-+
-+    cupsdLogMessage(CUPSD_LOG_INFO, "All jobs on \"%s\" were %s by \"%s\".",
-+                    dest, purge ? "purged" : "canceled", get_username(con));
-+  }
-+
-+  con->response->request.status.status_code = IPP_OK;
-+}
-+
-+
-+/*
-+ * 'cancel_job()' - Cancel a print job.
-+ */
-+
-+static void
-+cancel_job(cupsd_client_t  *con,	/* I - Client connection */
-+	   ipp_attribute_t *uri)	/* I - Job or Printer URI */
-+{
-+  ipp_attribute_t *attr;		/* Current attribute */
-+  int		jobid;			/* Job ID */
-+  char		method[HTTP_MAX_URI],	/* Method portion of URI */
-+		username[HTTP_MAX_URI],	/* Username portion of URI */
-+		host[HTTP_MAX_URI],	/* Host portion of URI */
-+		resource[HTTP_MAX_URI];	/* Resource portion of URI */
-+  int		port;			/* Port portion of URI */
-+  cupsd_job_t	*job;			/* Job information */
-+  const char	*dest;			/* Destination */
-+  cups_ptype_t	dtype;			/* Destination type (printer or class) */
-+  cupsd_printer_t *printer;		/* Printer data */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cancel_job(%p[%d], %s)", con,
-+                  con->http.fd, uri->values[0].string.text);
-+
-+ /*
-+  * See if we have a job URI or a printer URI...
-+  */
-+
-+  if (!strcmp(uri->name, "printer-uri"))
-+  {
-+   /*
-+    * Got a printer URI; see if we also have a job-id attribute...
-+    */
-+
-+    if ((attr = ippFindAttribute(con->request, "job-id",
-+                                 IPP_TAG_INTEGER)) == NULL)
-+    {
-+      send_ipp_status(con, IPP_BAD_REQUEST,
-+                      _("Got a printer-uri attribute but no job-id!"));
-+      return;
-+    }
-+
-+    if ((jobid = attr->values[0].integer) == 0)
-+    {
-+     /*
-+      * Find the current job on the specified printer...
-+      */
-+
-+      httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
-+                      sizeof(method), username, sizeof(username), host,
-+		      sizeof(host), &port, resource, sizeof(resource));
-+
-+      if ((dest = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL)
-+      {
-+       /*
-+	* Bad URI...
-+	*/
-+
-+	send_ipp_status(con, IPP_NOT_FOUND,
-+                	_("The printer or class was not found."));
-+	return;
-+      }
-+
-+     /*
-+      * See if the printer is currently printing a job...
-+      */
-+
-+      if (printer->job)
-+        jobid = ((cupsd_job_t *)printer->job)->id;
-+      else
-+      {
-+       /*
-+        * No, see if there are any pending jobs...
-+	*/
-+        
-+        for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
-+	     job;
-+	     job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
-+	  if (job->state_value <= IPP_JOB_PROCESSING &&
-+	      !strcasecmp(job->dest, dest))
-+	    break;
-+
-+	if (job)
-+	  jobid = job->id;
-+	else
-+	{
-+	  send_ipp_status(con, IPP_NOT_POSSIBLE, _("No active jobs on %s!"),
-+	                  dest);
-+	  return;
-+	}
-+      }
-+    }
-+  }
-+  else
-+  {
-+   /*
-+    * Got a job URI; parse it to get the job ID...
-+    */
-+
-+    httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
-+                    sizeof(method), username, sizeof(username), host,
-+		    sizeof(host), &port, resource, sizeof(resource));
-+ 
-+    if (strncmp(resource, "/jobs/", 6))
-+    {
-+     /*
-+      * Not a valid URI!
-+      */
-+
-+      send_ipp_status(con, IPP_BAD_REQUEST,
-+                      _("Bad job-uri attribute \"%s\"!"),
-+                      uri->values[0].string.text);
-+      return;
-+    }
-+
-+    jobid = atoi(resource + 6);
-+  }
-+
-+ /*
-+  * See if the job exists...
-+  */
-+
-+  if ((job = cupsdFindJob(jobid)) == NULL)
-+  {
-+   /*
-+    * Nope - return a "not found" error...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), jobid);
-+    return;
-+  }
-+
-+ /*
-+  * See if the job is owned by the requesting user...
-+  */
-+
-+  if (!validate_user(job, con, job->username, username, sizeof(username)))
-+  {
-+    send_http_error(con, HTTP_UNAUTHORIZED);
-+    return;
-+  }
-+
-+ /*
-+  * See if the job is already completed, canceled, or aborted; if so,
-+  * we can't cancel...
-+  */
-+
-+  if (job->state_value >= IPP_JOB_CANCELED)
-+  {
-+    switch (job->state_value)
-+    {
-+      case IPP_JOB_CANCELED :
-+	  send_ipp_status(con, IPP_NOT_POSSIBLE,
-+                	  _("Job #%d is already canceled - can\'t cancel."),
-+			  jobid);
-+          break;
-+
-+      case IPP_JOB_ABORTED :
-+	  send_ipp_status(con, IPP_NOT_POSSIBLE,
-+                	  _("Job #%d is already aborted - can\'t cancel."),
-+			  jobid);
-+          break;
-+
-+      default :
-+	  send_ipp_status(con, IPP_NOT_POSSIBLE,
-+                	  _("Job #%d is already completed - can\'t cancel."),
-+			  jobid);
-+          break;
-+    }
-+
-+    return;
-+  }
-+
-+ /*
-+  * Cancel the job and return...
-+  */
-+
-+  cupsdCancelJob(job, 0, IPP_JOB_CANCELED);
-+  cupsdCheckJobs();
-+
-+  cupsdLogMessage(CUPSD_LOG_INFO, "Job %d was canceled by \"%s\".", jobid,
-+                  username);
-+
-+  con->response->request.status.status_code = IPP_OK;
-+}
-+
-+
-+/*
-+ * 'cancel_subscription()' - Cancel a subscription.
-+ */
-+
-+static void
-+cancel_subscription(
-+    cupsd_client_t *con,		/* I - Client connection */
-+    int            sub_id)		/* I - Subscription ID */
-+{
-+  http_status_t		status;		/* Policy status */
-+  cupsd_subscription_t	*sub;		/* Subscription */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-+                  "cancel_subscription(con=%p[%d], sub_id=%d)",
-+                  con, con->http.fd, sub_id);
-+
-+ /*
-+  * Is the subscription ID valid?
-+  */
-+
-+  if ((sub = cupsdFindSubscription(sub_id)) == NULL)
-+  {
-+   /*
-+    * Bad subscription ID...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_FOUND,
-+                    _("notify-subscription-id %d no good!"), sub_id);
-+    return;
-+  }
-+
-+ /*
-+  * Check policy...
-+  */
-+
-+  if ((status = cupsdCheckPolicy(sub->dest ? sub->dest->op_policy_ptr :
-+                                             DefaultPolicyPtr,
-+                                 con, sub->owner)) != HTTP_OK)
-+  {
-+    send_http_error(con, status);
-+    return;
-+  }
-+
-+ /*
-+  * Cancel the subscription...
-+  */
-+
-+  cupsdDeleteSubscription(sub, 1);
-+
-+  con->response->request.status.status_code = IPP_OK;
-+}
-+
-+
-+/*
-+ * 'check_quotas()' - Check quotas for a printer and user.
-+ */
-+
-+static int				/* O - 1 if OK, 0 if not */
-+check_quotas(cupsd_client_t  *con,	/* I - Client connection */
-+             cupsd_printer_t *p)	/* I - Printer or class */
-+{
-+  int		i;			/* Looping var */
-+  char		username[33];		/* Username */
-+  cupsd_quota_t	*q;			/* Quota data */
-+  struct passwd	*pw;			/* User password data */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "check_quotas(%p[%d], %p[%s])",
-+                  con, con->http.fd, p, p->name);
-+
-+ /*
-+  * Check input...
-+  */
-+
-+  if (!con || !p)
-+    return (0);
-+
-+ /*
-+  * Figure out who is printing...
-+  */
-+
-+  strlcpy(username, get_username(con), sizeof(username));
-+
-+ /*
-+  * Check global active job limits for printers and users...
-+  */
-+
-+  if (MaxJobsPerPrinter)
-+  {
-+   /*
-+    * Check if there are too many pending jobs on this printer...
-+    */
-+
-+    if (cupsdGetPrinterJobCount(p->name) >= MaxJobsPerPrinter)
-+    {
-+      cupsdLogMessage(CUPSD_LOG_INFO, "Too many jobs for printer \"%s\"...",
-+                      p->name);
-+      return (0);
-+    }
-+  }
-+
-+  if (MaxJobsPerUser)
-+  {
-+   /*
-+    * Check if there are too many pending jobs for this user...
-+    */
-+
-+    if (cupsdGetUserJobCount(username) >= MaxJobsPerUser)
-+    {
-+      cupsdLogMessage(CUPSD_LOG_INFO, "Too many jobs for user \"%s\"...",
-+                      username);
-+      return (0);
-+    }
-+  }
-+
-+ /*
-+  * Check against users...
-+  */
-+
-+  if (p->num_users == 0 && p->k_limit == 0 && p->page_limit == 0)
-+    return (1);
-+
-+  if (p->num_users)
-+  {
-+    pw = getpwnam(username);
-+    endpwent();
-+
-+    for (i = 0; i < p->num_users; i ++)
-+      if (p->users[i][0] == '@')
-+      {
-+       /*
-+        * Check group membership...
-+	*/
-+
-+        if (cupsdCheckGroup(username, pw, p->users[i] + 1))
-+	  break;
-+      }
-+      else if (!strcasecmp(username, p->users[i]))
-+	break;
-+
-+    if ((i < p->num_users) == p->deny_users)
-+    {
-+      cupsdLogMessage(CUPSD_LOG_INFO,
-+                      "Denying user \"%s\" access to printer \"%s\"...",
-+        	      username, p->name);
-+      return (0);
-+    }
-+  }
-+
-+ /*
-+  * Check quotas...
-+  */
-+
-+  if (p->k_limit || p->page_limit)
-+  {
-+    if ((q = cupsdUpdateQuota(p, username, 0, 0)) == NULL)
-+    {
-+      cupsdLogMessage(CUPSD_LOG_ERROR,
-+                      "Unable to allocate quota data for user \"%s\"!",
-+                      username);
-+      return (0);
-+    }
-+
-+    if ((q->k_count >= p->k_limit && p->k_limit) ||
-+        (q->page_count >= p->page_limit && p->page_limit))
-+    {
-+      cupsdLogMessage(CUPSD_LOG_INFO, "User \"%s\" is over the quota limit...",
-+                      username);
-+      return (0);
-+    }
-+  }
-+
-+ /*
-+  * If we have gotten this far, we're done!
-+  */
-+
-+  return (1);
-+}
-+
-+
-+/*
-+ * 'copy_attribute()' - Copy a single attribute.
-+ */
-+
-+static ipp_attribute_t *		/* O - New attribute */
-+copy_attribute(
-+    ipp_t           *to,		/* O - Destination request/response */
-+    ipp_attribute_t *attr,		/* I - Attribute to copy */
-+    int             quickcopy)		/* I - Do a quick copy? */
-+{
-+  int			i;		/* Looping var */
-+  ipp_attribute_t	*toattr;	/* Destination attribute */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-+                  "copy_attribute(%p, %p[%s,%x,%x])", to, attr,
-+        	  attr->name ? attr->name : "(null)", attr->group_tag,
-+		  attr->value_tag);
-+
-+  switch (attr->value_tag & ~IPP_TAG_COPY)
-+  {
-+    case IPP_TAG_ZERO :
-+        toattr = ippAddSeparator(to);
-+	break;
-+
-+    case IPP_TAG_INTEGER :
-+    case IPP_TAG_ENUM :
-+        toattr = ippAddIntegers(to, attr->group_tag, attr->value_tag,
-+	                        attr->name, attr->num_values, NULL);
-+
-+        for (i = 0; i < attr->num_values; i ++)
-+	  toattr->values[i].integer = attr->values[i].integer;
-+        break;
-+
-+    case IPP_TAG_BOOLEAN :
-+        toattr = ippAddBooleans(to, attr->group_tag, attr->name,
-+	                        attr->num_values, NULL);
-+
-+        for (i = 0; i < attr->num_values; i ++)
-+	  toattr->values[i].boolean = attr->values[i].boolean;
-+        break;
-+
-+    case IPP_TAG_STRING :
-+    case IPP_TAG_TEXT :
-+    case IPP_TAG_NAME :
-+    case IPP_TAG_KEYWORD :
-+    case IPP_TAG_URI :
-+    case IPP_TAG_URISCHEME :
-+    case IPP_TAG_CHARSET :
-+    case IPP_TAG_LANGUAGE :
-+    case IPP_TAG_MIMETYPE :
-+        toattr = ippAddStrings(to, attr->group_tag,
-+	                       (ipp_tag_t)(attr->value_tag | quickcopy),
-+	                       attr->name, attr->num_values, NULL, NULL);
-+
-+        if (quickcopy)
-+	{
-+          for (i = 0; i < attr->num_values; i ++)
-+	    toattr->values[i].string.text = attr->values[i].string.text;
-+        }
-+	else
-+	{
-+          for (i = 0; i < attr->num_values; i ++)
-+	    toattr->values[i].string.text = _cupsStrAlloc(attr->values[i].string.text);
-+	}
-+        break;
-+
-+    case IPP_TAG_DATE :
-+        toattr = ippAddDate(to, attr->group_tag, attr->name,
-+	                    attr->values[0].date);
-+        break;
-+
-+    case IPP_TAG_RESOLUTION :
-+        toattr = ippAddResolutions(to, attr->group_tag, attr->name,
-+	                           attr->num_values, IPP_RES_PER_INCH,
-+				   NULL, NULL);
-+
-+        for (i = 0; i < attr->num_values; i ++)
-+	{
-+	  toattr->values[i].resolution.xres  = attr->values[i].resolution.xres;
-+	  toattr->values[i].resolution.yres  = attr->values[i].resolution.yres;
-+	  toattr->values[i].resolution.units = attr->values[i].resolution.units;
-+	}
-+        break;
-+
-+    case IPP_TAG_RANGE :
-+        toattr = ippAddRanges(to, attr->group_tag, attr->name,
-+	                      attr->num_values, NULL, NULL);
-+
-+        for (i = 0; i < attr->num_values; i ++)
-+	{
-+	  toattr->values[i].range.lower = attr->values[i].range.lower;
-+	  toattr->values[i].range.upper = attr->values[i].range.upper;
-+	}
-+        break;
-+
-+    case IPP_TAG_TEXTLANG :
-+    case IPP_TAG_NAMELANG :
-+        toattr = ippAddStrings(to, attr->group_tag,
-+	                       (ipp_tag_t)(attr->value_tag | quickcopy),
-+	                       attr->name, attr->num_values, NULL, NULL);
-+
-+        if (quickcopy)
-+	{
-+          for (i = 0; i < attr->num_values; i ++)
-+	  {
-+            toattr->values[i].string.charset = attr->values[i].string.charset;
-+	    toattr->values[i].string.text    = attr->values[i].string.text;
-+          }
-+        }
-+	else
-+	{
-+          for (i = 0; i < attr->num_values; i ++)
-+	  {
-+	    if (!i)
-+              toattr->values[i].string.charset =
-+	          _cupsStrAlloc(attr->values[i].string.charset);
-+	    else
-+              toattr->values[i].string.charset =
-+	          toattr->values[0].string.charset;
-+
-+	    toattr->values[i].string.text = _cupsStrAlloc(attr->values[i].string.text);
-+          }
-+        }
-+        break;
-+
-+    case IPP_TAG_BEGIN_COLLECTION :
-+        toattr = ippAddCollections(to, attr->group_tag, attr->name,
-+	                           attr->num_values, NULL);
-+
-+        for (i = 0; i < attr->num_values; i ++)
-+	{
-+	  toattr->values[i].collection = ippNew();
-+	  copy_attrs(toattr->values[i].collection, attr->values[i].collection,
-+	             NULL, IPP_TAG_ZERO, 0);
-+	}
-+        break;
-+
-+    default :
-+        toattr = ippAddIntegers(to, attr->group_tag, attr->value_tag,
-+	                        attr->name, attr->num_values, NULL);
-+
-+        for (i = 0; i < attr->num_values; i ++)
-+	{
-+	  toattr->values[i].unknown.length = attr->values[i].unknown.length;
-+
-+	  if (toattr->values[i].unknown.length > 0)
-+	  {
-+	    if ((toattr->values[i].unknown.data =
-+	             malloc(toattr->values[i].unknown.length)) == NULL)
-+	      toattr->values[i].unknown.length = 0;
-+	    else
-+	      memcpy(toattr->values[i].unknown.data,
-+		     attr->values[i].unknown.data,
-+		     toattr->values[i].unknown.length);
-+	  }
-+	}
-+        break; /* anti-compiler-warning-code */
-+  }
-+
-+  return (toattr);
-+}
-+
-+
-+/*
-+ * 'copy_attrs()' - Copy attributes from one request to another.
-+ */
-+
-+static void
-+copy_attrs(ipp_t        *to,		/* I - Destination request */
-+           ipp_t        *from,		/* I - Source request */
-+           cups_array_t *ra,		/* I - Requested attributes */
-+	   ipp_tag_t    group,		/* I - Group to copy */
-+	   int          quickcopy)	/* I - Do a quick copy? */
-+{
-+  ipp_attribute_t	*fromattr;	/* Source attribute */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-+                  "copy_attrs(to=%p, from=%p, ra=%p, group=%x, quickcopy=%d)",
-+		  to, from, ra, group, quickcopy);
-+
-+  if (!to || !from)
-+    return;
-+
-+  for (fromattr = from->attrs; fromattr; fromattr = fromattr->next)
-+  {
-+   /*
-+    * Filter attributes as needed...
-+    */
-+
-+    if ((group != IPP_TAG_ZERO && fromattr->group_tag != group &&
-+         fromattr->group_tag != IPP_TAG_ZERO) || !fromattr->name)
-+      continue;
-+
-+    if (!ra || cupsArrayFind(ra, fromattr->name))
-+      copy_attribute(to, fromattr, quickcopy);
-+  }
-+}
-+
-+
-+/*
-+ * 'copy_banner()' - Copy a banner file to the requests directory for the
-+ *                   specified job.
-+ */
-+
-+static int				/* O - Size of banner file in kbytes */
-+copy_banner(cupsd_client_t *con,	/* I - Client connection */
-+            cupsd_job_t    *job,	/* I - Job information */
-+            const char     *name)	/* I - Name of banner */
-+{
-+  int		i;			/* Looping var */
-+  int		kbytes;			/* Size of banner file in kbytes */
-+  char		filename[1024];		/* Job filename */
-+  cupsd_banner_t *banner;		/* Pointer to banner */
-+  cups_file_t	*in;			/* Input file */
-+  cups_file_t	*out;			/* Output file */
-+  int		ch;			/* Character from file */
-+  char		attrname[255],		/* Name of attribute */
-+		*s;			/* Pointer into name */
-+  ipp_attribute_t *attr;		/* Attribute */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "copy_banner(%p[%d], %p[%d], %s)",
-+                  con, con->http.fd, job, job->id, name ? name : "(null)");
-+
-+ /*
-+  * Find the banner; return if not found or "none"...
-+  */
-+
-+  if (!name || !strcmp(name, "none") ||
-+      (banner = cupsdFindBanner(name)) == NULL)
-+    return (0);
-+
-+ /*
-+  * Open the banner and job files...
-+  */
-+
-+  if (add_file(con, job, banner->filetype, 0))
-+    return (0);
-+
-+  snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, job->id,
-+           job->num_files);
-+  if ((out = cupsFileOpen(filename, "w")) == NULL)
-+  {
-+    cupsdLogMessage(CUPSD_LOG_ERROR,
-+                    "copy_banner: Unable to create banner job file %s - %s",
-+                    filename, strerror(errno));
-+    job->num_files --;
-+    return (0);
-+  }
-+
-+  fchmod(cupsFileNumber(out), 0640);
-+  fchown(cupsFileNumber(out), RunUser, Group);
-+
-+ /*
-+  * Try the localized banner file under the subdirectory...
-+  */
-+
-+  strlcpy(attrname, job->attrs->attrs->next->values[0].string.text,
-+          sizeof(attrname));
-+  if (strlen(attrname) > 2 && attrname[2] == '-')
-+  {
-+   /*
-+    * Convert ll-cc to ll_CC...
-+    */
-+
-+    attrname[2] = '_';
-+    attrname[3] = toupper(attrname[3] & 255);
-+    attrname[4] = toupper(attrname[4] & 255);
-+  }
-+
-+  snprintf(filename, sizeof(filename), "%s/banners/%s/%s", DataDir,
-+           attrname, name);
-+
-+  if (access(filename, 0) && strlen(attrname) > 2)
-+  {
-+   /*
-+    * Wasn't able to find "ll_CC" locale file; try the non-national
-+    * localization banner directory.
-+    */
-+
-+    attrname[2] = '\0';
-+
-+    snprintf(filename, sizeof(filename), "%s/banners/%s/%s", DataDir,
-+             attrname, name);
-+  }
-+
-+  if (access(filename, 0))
-+  {
-+   /*
-+    * Use the non-localized banner file.
-+    */
-+
-+    snprintf(filename, sizeof(filename), "%s/banners/%s", DataDir, name);
-+  }
-+
-+  if ((in = cupsFileOpen(filename, "r")) == NULL)
-+  {
-+    cupsFileClose(out);
-+    unlink(filename);
-+    cupsdLogMessage(CUPSD_LOG_ERROR,
-+                    "copy_banner: Unable to open banner template file %s - %s",
-+                    filename, strerror(errno));
-+    job->num_files --;
-+    return (0);
-+  }
-+
-+ /*
-+  * Parse the file to the end...
-+  */
-+
-+  while ((ch = cupsFileGetChar(in)) != EOF)
-+    if (ch == '{')
-+    {
-+     /*
-+      * Get an attribute name...
-+      */
-+
-+      for (s = attrname; (ch = cupsFileGetChar(in)) != EOF;)
-+        if (!isalpha(ch & 255) && ch != '-' && ch != '?')
-+          break;
-+	else if (s < (attrname + sizeof(attrname) - 1))
-+          *s++ = ch;
-+	else
-+	  break;
-+
-+      *s = '\0';
-+
-+      if (ch != '}')
-+      {
-+       /*
-+        * Ignore { followed by stuff that is not an attribute name...
-+	*/
-+
-+        cupsFilePrintf(out, "{%s%c", attrname, ch);
-+	continue;
-+      }
-+
-+     /*
-+      * See if it is defined...
-+      */
-+
-+      if (attrname[0] == '?')
-+        s = attrname + 1;
-+      else
-+        s = attrname;
-+
-+      if (!strcmp(s, "printer-name"))
-+      {
-+        cupsFilePuts(out, job->dest);
-+	continue;
-+      }
-+      else if ((attr = ippFindAttribute(job->attrs, s, IPP_TAG_ZERO)) == NULL)
-+      {
-+       /*
-+        * See if we have a leading question mark...
-+	*/
-+
-+	if (attrname[0] != '?')
-+	{
-+	 /*
-+          * Nope, write to file as-is; probably a PostScript procedure...
-+	  */
-+
-+	  cupsFilePrintf(out, "{%s}", attrname);
-+        }
-+
-+        continue;
-+      }
-+
-+     /*
-+      * Output value(s)...
-+      */
-+
-+      for (i = 0; i < attr->num_values; i ++)
-+      {
-+	if (i)
-+	  cupsFilePutChar(out, ',');
-+
-+	switch (attr->value_tag)
-+	{
-+	  case IPP_TAG_INTEGER :
-+	  case IPP_TAG_ENUM :
-+	      if (!strncmp(s, "time-at-", 8))
-+	        cupsFilePuts(out, cupsdGetDateTime(attr->values[i].integer));
-+	      else
-+	        cupsFilePrintf(out, "%d", attr->values[i].integer);
-+	      break;
-+
-+	  case IPP_TAG_BOOLEAN :
-+	      cupsFilePrintf(out, "%d", attr->values[i].boolean);
-+	      break;
-+
-+	  case IPP_TAG_NOVALUE :
-+	      cupsFilePuts(out, "novalue");
-+	      break;
-+
-+	  case IPP_TAG_RANGE :
-+	      cupsFilePrintf(out, "%d-%d", attr->values[i].range.lower,
-+		      attr->values[i].range.upper);
-+	      break;
-+
-+	  case IPP_TAG_RESOLUTION :
-+	      cupsFilePrintf(out, "%dx%d%s", attr->values[i].resolution.xres,
-+		      attr->values[i].resolution.yres,
-+		      attr->values[i].resolution.units == IPP_RES_PER_INCH ?
-+			  "dpi" : "dpc");
-+	      break;
-+
-+	  case IPP_TAG_URI :
-+          case IPP_TAG_STRING :
-+	  case IPP_TAG_TEXT :
-+	  case IPP_TAG_NAME :
-+	  case IPP_TAG_KEYWORD :
-+	  case IPP_TAG_CHARSET :
-+	  case IPP_TAG_LANGUAGE :
-+	      if (!strcasecmp(banner->filetype->type, "postscript"))
-+	      {
-+	       /*
-+	        * Need to quote strings for PS banners...
-+		*/
-+
-+	        const char *p;
-+
-+		for (p = attr->values[i].string.text; *p; p ++)
-+		{
-+		  if (*p == '(' || *p == ')' || *p == '\\')
-+		  {
-+		    cupsFilePutChar(out, '\\');
-+		    cupsFilePutChar(out, *p);
-+		  }
-+		  else if (*p < 32 || *p > 126)
-+		    cupsFilePrintf(out, "\\%03o", *p & 255);
-+		  else
-+		    cupsFilePutChar(out, *p);
-+		}
-+	      }
-+	      else
-+		cupsFilePuts(out, attr->values[i].string.text);
-+	      break;
-+
-+          default :
-+	      break; /* anti-compiler-warning-code */
-+	}
-+      }
-+    }
-+    else if (ch == '\\')	/* Quoted char */
-+    {
-+      ch = cupsFileGetChar(in);
-+
-+      if (ch != '{')		/* Only do special handling for \{ */
-+        cupsFilePutChar(out, '\\');
-+
-+      cupsFilePutChar(out, ch);
-+    }
-+    else
-+      cupsFilePutChar(out, ch);
-+
-+  cupsFileClose(in);
-+
-+  kbytes = (cupsFileTell(out) + 1023) / 1024;
-+
-+  if ((attr = ippFindAttribute(job->attrs, "job-k-octets",
-+                               IPP_TAG_INTEGER)) != NULL)
-+    attr->values[0].integer += kbytes;
-+
-+  cupsFileClose(out);
-+
-+  return (kbytes);
-+}
-+
-+
-+/*
-+ * 'copy_file()' - Copy a PPD file or interface script...
-+ */
-+
-+static int				/* O - 0 = success, -1 = error */
-+copy_file(const char *from,		/* I - Source file */
-+          const char *to)		/* I - Destination file */
-+{
-+  cups_file_t	*src,			/* Source file */
-+		*dst;			/* Destination file */
-+  int		bytes;			/* Bytes to read/write */
-+  char		buffer[2048];		/* Copy buffer */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "copy_file(\"%s\", \"%s\")", from, to);
-+
-+ /*
-+  * Open the source and destination file for a copy...
-+  */
-+
-+  if ((src = cupsFileOpen(from, "rb")) == NULL)
-+    return (-1);
-+
-+  if ((dst = cupsFileOpen(to, "wb")) == NULL)
-+  {
-+    cupsFileClose(src);
-+    return (-1);
-+  }
-+
-+ /*
-+  * Copy the source file to the destination...
-+  */
-+
-+  while ((bytes = cupsFileRead(src, buffer, sizeof(buffer))) > 0)
-+    if (cupsFileWrite(dst, buffer, bytes) < bytes)
-+    {
-+      cupsFileClose(src);
-+      cupsFileClose(dst);
-+      return (-1);
-+    }
-+
-+ /*
-+  * Close both files and return...
-+  */
-+
-+  cupsFileClose(src);
-+
-+  return (cupsFileClose(dst));
-+}
-+
-+
-+/*
-+ * 'copy_model()' - Copy a PPD model file, substituting default values
-+ *                  as needed...
-+ */
-+
-+static int				/* O - 0 = success, -1 = error */
-+copy_model(cupsd_client_t *con,		/* I - Client connection */
-+           const char     *from,	/* I - Source file */
-+           const char     *to)		/* I - Destination file */
-+{
-+  fd_set	*input;			/* select() input set */
-+  struct timeval timeout;		/* select() timeout */
-+  int		maxfd;			/* Maximum file descriptor for select() */
-+  char		tempfile[1024];		/* Temporary PPD file */
-+  int		tempfd;			/* Temporary PPD file descriptor */
-+  int		temppid;		/* Process ID of cups-driverd */
-+  int		temppipe[2];		/* Temporary pipes */
-+  char		*argv[4],		/* Command-line arguments */
-+		*envp[MAX_ENV];		/* Environment */
-+  cups_file_t	*src,			/* Source file */
-+		*dst;			/* Destination file */
-+  ppd_file_t	*ppd;			/* PPD file */
-+  int		bytes,			/* Bytes from pipe */
-+		total;			/* Total bytes from pipe */
-+  char		buffer[2048];		/* Copy buffer */
-+  int		i;			/* Looping var */
-+  char		option[PPD_MAX_NAME],	/* Option name */
-+		choice[PPD_MAX_NAME];	/* Choice name */
-+  int		num_defaults;		/* Number of default options */
-+  cups_option_t	*defaults;		/* Default options */
-+  char		cups_protocol[PPD_MAX_LINE];
-+					/* cupsProtocol attribute */
-+  int		have_letter,		/* Have Letter size */
-+		have_a4;		/* Have A4 size */
-+#ifdef HAVE_LIBPAPER
-+  char		*paper_result;		/* Paper size name from libpaper */
-+  char		system_paper[64];	/* Paper size name buffer */
-+#endif /* HAVE_LIBPAPER */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-+        	  "copy_model(con=%p, from=\"%s\", to=\"%s\")",
-+        	  con, from, to);
-+
-+ /*
-+  * Run cups-driverd to get the PPD file...
-+  */
-+
-+  argv[0] = "cups-driverd";
-+  argv[1] = "cat";
-+  argv[2] = (char *)from;
-+  argv[3] = NULL;
-+
-+  cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
-+
-+  snprintf(buffer, sizeof(buffer), "%s/daemon/cups-driverd", ServerBin);
-+  snprintf(tempfile, sizeof(tempfile), "%s/%d.ppd", TempDir, con->http.fd);
-+  tempfd = open(tempfile, O_WRONLY | O_CREAT | O_TRUNC, 0600);
-+  if (tempfd < 0)
-+    return (-1);
-+
-+  cupsdOpenPipe(temppipe);
-+
-+  if ((input = calloc(1, SetSize)) == NULL)
-+  {
-+    close(tempfd);
-+    unlink(tempfile);
-+
-+    cupsdLogMessage(CUPSD_LOG_ERROR,
-+                    "copy_model: Unable to allocate %d bytes for select()...",
-+                    SetSize);
-+    return (-1);
-+  }
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG,
-+                  "copy_model: Running \"cups-driverd cat %s\"...", from);
-+
-+  if (!cupsdStartProcess(buffer, argv, envp, -1, temppipe[1], CGIPipes[1],
-+                         -1, 0, &temppid))
-+  {
-+    free(input);
-+    close(tempfd);
-+    unlink(tempfile);
-+    return (-1);
-+  }
-+
-+  close(temppipe[1]);
-+
-+ /*
-+  * Wait up to 30 seconds for the PPD file to be copied...
-+  */
-+
-+  total = 0;
-+
-+  if (temppipe[0] > CGIPipes[0])
-+    maxfd = temppipe[0] + 1;
-+  else
-+    maxfd = CGIPipes[0] + 1;
-+
-+  for (;;)
-+  {
-+   /*
-+    * See if we have data ready...
-+    */
-+
-+    bytes = 0;
-+
-+    FD_SET(temppipe[0], input);
-+    FD_SET(CGIPipes[0], input);
-+
-+    timeout.tv_sec  = 30;
-+    timeout.tv_usec = 0;
-+
-+    if ((i = select(maxfd, input, NULL, NULL, &timeout)) < 0)
-+    {
-+      if (errno == EINTR)
-+        continue;
-+      else
-+        break;
-+    }
-+    else if (i == 0)
-+    {
-+     /*
-+      * We have timed out...
-+      */
-+
-+      break;
-+    }
-+
-+    if (FD_ISSET(temppipe[0], input))
-+    {
-+     /*
-+      * Read the PPD file from the pipe, and write it to the PPD file.
-+      */
-+
-+      if ((bytes = read(temppipe[0], buffer, sizeof(buffer))) > 0)
-+      {
-+	if (write(tempfd, buffer, bytes) < bytes)
-+          break;
-+
-+	total += bytes;
-+      }
-+      else
-+	break;
-+    }
-+
-+    if (FD_ISSET(CGIPipes[0], input))
-+      cupsdUpdateCGI();
-+  }
-+
-+  close(temppipe[0]);
-+  close(tempfd);
-+
-+  free(input);
-+
-+  if (!total)
-+  {
-+   /*
-+    * No data from cups-deviced...
-+    */
-+
-+    cupsdLogMessage(CUPSD_LOG_ERROR, "copy_model: empty PPD file!");
-+    unlink(tempfile);
-+    return (-1);
-+  }
-+
-+ /*
-+  * Read the source file and see what page sizes are supported...
-+  */
-+
-+  if ((ppd = ppdOpenFile(tempfile)) == NULL)
-+  {
-+    unlink(tempfile);
-+    return (-1);
-+  }
-+
-+  have_letter = ppdPageSize(ppd, "Letter") != NULL;
-+  have_a4     = ppdPageSize(ppd, "A4") != NULL;
-+
-+ /*
-+  * Open the destination (if possible) and set the default options...
-+  */
-+
-+  num_defaults     = 0;
-+  defaults         = NULL;
-+  cups_protocol[0] = '\0';
-+
-+  if ((dst = cupsFileOpen(to, "rb")) != NULL)
-+  {
-+   /*
-+    * Read all of the default lines from the old PPD...
-+    */
-+
-+    while (cupsFileGets(dst, buffer, sizeof(buffer)))
-+      if (!strncmp(buffer, "*Default", 8))
-+      {
-+       /*
-+	* Add the default option...
-+	*/
-+
-+        if (!ppd_parse_line(buffer, option, sizeof(option),
-+	                    choice, sizeof(choice)))
-+        {
-+	  ppd_option_t	*ppdo;		/* PPD option */
-+
-+
-+         /*
-+	  * Only add the default if the default hasn't already been
-+	  * set and the choice exists in the new PPD...
-+	  */
-+
-+	  if (!cupsGetOption(option, num_defaults, defaults) &&
-+	      (ppdo = ppdFindOption(ppd, option)) != NULL &&
-+	      ppdFindChoice(ppdo, choice))
-+            num_defaults = cupsAddOption(option, choice, num_defaults,
-+	                                 &defaults);
-+        }
-+      }
-+      else if (!strncmp(buffer, "*cupsProtocol:", 14))
-+        strlcpy(cups_protocol, buffer, sizeof(cups_protocol));
-+
-+    cupsFileClose(dst);
-+  }
-+#ifdef HAVE_LIBPAPER
-+  else if ((paper_result = systempapername()) != NULL)
-+  {
-+   /*
-+    * Set the default media sizes from the systemwide default...
-+    */
-+
-+    strlcpy(system_paper, paper_result, sizeof(system_paper));
-+    system_paper[0] = toupper(system_paper[0] & 255);
-+
-+    if ((!strcmp(system_paper, "Letter") && have_letter) ||
-+        (!strcmp(system_paper, "A4") && have_a4))
-+    {
-+      num_defaults = cupsAddOption("PageSize", system_paper, 
-+				   num_defaults, &defaults);
-+      num_defaults = cupsAddOption("PageRegion", system_paper, 
-+				   num_defaults, &defaults);
-+      num_defaults = cupsAddOption("PaperDimension", system_paper, 
-+				   num_defaults, &defaults);
-+      num_defaults = cupsAddOption("ImageableArea", system_paper, 
-+				   num_defaults, &defaults);
-+    }
-+  }
-+#endif /* HAVE_LIBPAPER */
-+  else
-+  {
-+   /*
-+    * Add the default media sizes...
-+    *
-+    * Note: These values are generally not valid for large-format devices
-+    *       like plotters, however it is probably safe to say that those
-+    *       users will configure the media size after initially adding
-+    *       the device anyways...
-+    */
-+
-+    if (!DefaultLanguage ||
-+        !strcasecmp(DefaultLanguage, "C") ||
-+        !strcasecmp(DefaultLanguage, "POSIX") ||
-+	!strcasecmp(DefaultLanguage, "en") ||
-+	!strncasecmp(DefaultLanguage, "en.", 3) ||
-+	!strncasecmp(DefaultLanguage, "en_US", 5) ||
-+	!strncasecmp(DefaultLanguage, "en_CA", 5) ||
-+	!strncasecmp(DefaultLanguage, "fr_CA", 5))
-+    {
-+     /*
-+      * These are the only locales that will default to "letter" size...
-+      */
-+
-+      if (have_letter)
-+      {
-+	num_defaults = cupsAddOption("PageSize", "Letter", num_defaults,
-+                                     &defaults);
-+	num_defaults = cupsAddOption("PageRegion", "Letter", num_defaults,
-+                                     &defaults);
-+	num_defaults = cupsAddOption("PaperDimension", "Letter", num_defaults,
-+                                     &defaults);
-+	num_defaults = cupsAddOption("ImageableArea", "Letter", num_defaults,
-+                                     &defaults);
-+      }
-+    }
-+    else if (have_a4)
-+    {
-+     /*
-+      * The rest default to "a4" size...
-+      */
-+
-+      num_defaults = cupsAddOption("PageSize", "A4", num_defaults,
-+                                   &defaults);
-+      num_defaults = cupsAddOption("PageRegion", "A4", num_defaults,
-+                                   &defaults);
-+      num_defaults = cupsAddOption("PaperDimension", "A4", num_defaults,
-+                                   &defaults);
-+      num_defaults = cupsAddOption("ImageableArea", "A4", num_defaults,
-+                                   &defaults);
-+    }
-+  }
-+
-+  ppdClose(ppd);
-+
-+ /*
-+  * Open the source file for a copy...
-+  */
-+
-+  if ((src = cupsFileOpen(tempfile, "rb")) == NULL)
-+  {
-+    cupsFreeOptions(num_defaults, defaults);
-+    unlink(tempfile);
-+    return (-1);
-+  }
-+
-+ /*
-+  * Open the destination file for a copy...
-+  */
-+
-+  if ((dst = cupsFileOpen(to, "wb")) == NULL)
-+  {
-+    cupsFreeOptions(num_defaults, defaults);
-+    cupsFileClose(src);
-+    unlink(tempfile);
-+    return (-1);
-+  }
-+
-+ /*
-+  * Copy the source file to the destination...
-+  */
-+
-+  while (cupsFileGets(src, buffer, sizeof(buffer)))
-+  {
-+    if (!strncmp(buffer, "*Default", 8))
-+    {
-+     /*
-+      * Check for an previous default option choice...
-+      */
-+
-+      if (!ppd_parse_line(buffer, option, sizeof(option),
-+	                  choice, sizeof(choice)))
-+      {
-+        const char	*val;		/* Default option value */
-+
-+
-+        if ((val = cupsGetOption(option, num_defaults, defaults)) != NULL)
-+	{
-+	 /*
-+	  * Substitute the previous choice...
-+	  */
-+
-+	  snprintf(buffer, sizeof(buffer), "*Default%s: %s", option, val);
-+	}
-+      }
-+    }
-+
-+    cupsFilePrintf(dst, "%s\n", buffer);
-+  }
-+
-+  if (cups_protocol[0])
-+    cupsFilePrintf(dst, "%s\n", cups_protocol);
-+
-+  cupsFreeOptions(num_defaults, defaults);
-+
-+ /*
-+  * Close both files and return...
-+  */
-+
-+  cupsFileClose(src);
-+
-+  unlink(tempfile);
-+
-+  return (cupsFileClose(dst));
-+}
-+
-+
-+/*
-+ * 'copy_job_attrs()' - Copy job attributes.
-+ */
-+
-+static void
-+copy_job_attrs(cupsd_client_t *con,	/* I - Client connection */
-+	       cupsd_job_t    *job,	/* I - Job */
-+	       cups_array_t   *ra)	/* I - Requested attributes array */
-+{
-+  char	job_uri[HTTP_MAX_URI];		/* Job URI */
-+
-+
-+ /*
-+  * Send the requested attributes for each job...
-+  */
-+
-+  httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), "ipp", NULL,
-+                   con->servername, con->serverport, "/jobs/%d",
-+        	   job->id);
-+
-+  if (!ra || cupsArrayFind(ra, "job-more-info"))
-+    ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI,
-+        	 "job-more-info", NULL, job_uri);
-+
-+  if (job->state_value > IPP_JOB_PROCESSING &&
-+      (!ra || cupsArrayFind(ra, "job-preserved")))
-+    ippAddBoolean(con->response, IPP_TAG_JOB, "job-preserved",
-+                  job->num_files > 0);
-+
-+  if (!ra || cupsArrayFind(ra, "job-printer-up-time"))
-+    ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER,
-+                  "job-printer-up-time", time(NULL));
-+
-+  if (!ra || cupsArrayFind(ra, "job-state-reasons"))
-+    add_job_state_reasons(con, job);
-+
-+  if (!ra || cupsArrayFind(ra, "job-uri"))
-+    ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI,
-+        	 "job-uri", NULL, job_uri);
-+
-+  copy_attrs(con->response, job->attrs, ra, IPP_TAG_JOB, 0);
-+}
-+
-+
-+/*
-+ * 'copy_printer_attrs()' - Copy printer attributes.
-+ */
-+
-+static void
-+copy_printer_attrs(
-+    cupsd_client_t  *con,		/* I - Client connection */
-+    cupsd_printer_t *printer,		/* I - Printer */
-+    cups_array_t    *ra)		/* I - Requested attributes array */
-+{
-+  char			printer_uri[HTTP_MAX_URI];
-+					/* Printer URI */
-+  time_t		curtime;	/* Current time */
-+  int			i;		/* Looping var */
-+  ipp_attribute_t	*history;	/* History collection */
-+
-+
-+ /*
-+  * Copy the printer attributes to the response using requested-attributes
-+  * and document-format attributes that may be provided by the client.
-+  */
-+
-+  curtime = time(NULL);
-+
-+#ifdef __APPLE__
-+  if ((!ra || cupsArrayFind(ra, "com.apple.print.recoverable-message")) &&
-+      printer->recoverable)
-+    ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_TEXT,
-+                 "com.apple.print.recoverable-message", NULL,
-+		 printer->recoverable);
-+#endif /* __APPLE__ */
-+
-+  if (!ra || cupsArrayFind(ra, "printer-current-time"))
-+    ippAddDate(con->response, IPP_TAG_PRINTER, "printer-current-time",
-+               ippTimeToDate(curtime));
-+
-+  if (!ra || cupsArrayFind(ra, "printer-error-policy"))
-+    ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME,
-+        	 "printer-error-policy", NULL, printer->error_policy);
-+
-+  if (!ra || cupsArrayFind(ra, "printer-is-accepting-jobs"))
-+    ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-accepting-jobs",
-+                  printer->accepting);
-+
-+  if (!ra || cupsArrayFind(ra, "printer-is-shared"))
-+    ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-shared",
-+                  printer->shared);
-+
-+  if (!ra || cupsArrayFind(ra, "printer-op-policy"))
-+    ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME,
-+        	 "printer-op-policy", NULL, printer->op_policy);
-+
-+  if (!ra || cupsArrayFind(ra, "printer-state"))
-+    ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
-+                  printer->state);
-+
-+  if (!ra || cupsArrayFind(ra, "printer-state-change-time"))
-+    ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
-+                  "printer-state-change-time", printer->state_time);
-+                
-+  if (MaxPrinterHistory > 0 && printer->num_history > 0 &&
-+      cupsArrayFind(ra, "printer-state-history"))
-+  {
-+   /*
-+    * Printer history is only sent if specifically requested, so that
-+    * older CUPS/IPP clients won't barf on the collection attributes.
-+    */
-+
-+    history = ippAddCollections(con->response, IPP_TAG_PRINTER,
-+                                "printer-state-history",
-+                                printer->num_history, NULL);
-+
-+    for (i = 0; i < printer->num_history; i ++)
-+      copy_attrs(history->values[i].collection = ippNew(), printer->history[i],
-+                 NULL, IPP_TAG_ZERO, 0);
-+  }
-+
-+  if (!ra || cupsArrayFind(ra, "printer-state-message"))
-+    ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_TEXT,
-+        	 "printer-state-message", NULL, printer->state_message);
-+
-+  if (!ra || cupsArrayFind(ra, "printer-state-reasons"))
-+    add_printer_state_reasons(con, printer);
-+
-+  if (!ra || cupsArrayFind(ra, "printer-type"))
-+  {
-+    int type;				/* printer-type value */
-+
-+
-+   /*
-+    * Add the CUPS-specific printer-type attribute...
-+    */
-+
-+    type = printer->type;
-+
-+    if (printer == DefaultPrinter)
-+      type |= CUPS_PRINTER_DEFAULT;
-+
-+    if (!printer->accepting)
-+      type |= CUPS_PRINTER_REJECTING;
-+
-+    if (!printer->shared)
-+      type |= CUPS_PRINTER_NOT_SHARED;
-+
-+    ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-type",
-+		  type);
-+  }
-+
-+  if (!ra || cupsArrayFind(ra, "printer-up-time"))
-+    ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
-+                  "printer-up-time", curtime);
-+
-+  if ((!ra || cupsArrayFind(ra, "printer-uri-supported")) &&
-+      !ippFindAttribute(printer->attrs, "printer-uri-supported",
-+                        IPP_TAG_URI))
-+  {
-+    httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri),
-+                     "ipp", NULL, con->servername, con->serverport,
-+		     (printer->type & CUPS_PRINTER_CLASS) ?
-+		         "/classes/%s" : "/printers/%s", printer->name);
-+    ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI,
-+        	 "printer-uri-supported", NULL, printer_uri);
-+    cupsdLogMessage(CUPSD_LOG_DEBUG2, "printer-uri-supported=\"%s\"",
-+                    printer_uri);
-+  }
-+
-+  if (!ra || cupsArrayFind(ra, "queued-job-count"))
-+    add_queued_job_count(con, printer);
-+
-+  copy_attrs(con->response, printer->attrs, ra, IPP_TAG_ZERO, 0);
-+  copy_attrs(con->response, CommonData, ra, IPP_TAG_ZERO, IPP_TAG_COPY);
-+}
-+
-+
-+/*
-+ * 'copy_subscription_attrs()' - Copy subscription attributes.
-+ */
-+
-+static void
-+copy_subscription_attrs(
-+    cupsd_client_t       *con,		/* I - Client connection */
-+    cupsd_subscription_t *sub,		/* I - Subscription */
-+    cups_array_t         *ra)		/* I - Requested attributes array */
-+{
-+  ipp_attribute_t	*attr;		/* Current attribute */
-+  char			printer_uri[HTTP_MAX_URI];
-+					/* Printer URI */
-+  int			count;		/* Number of events */
-+  unsigned		mask;		/* Current event mask */
-+  const char		*name;		/* Current event name */
-+
-+
-+ /*
-+  * Copy the subscription attributes to the response using the
-+  * requested-attributes attribute that may be provided by the client.
-+  */
-+
-+  if (!ra || cupsArrayFind(ra, "notify-events"))
-+  {
-+    if ((name = cupsdEventName((cupsd_eventmask_t)sub->mask)) != NULL)
-+    {
-+     /*
-+      * Simple event list...
-+      */
-+
-+      ippAddString(con->response, IPP_TAG_SUBSCRIPTION,
-+                   (ipp_tag_t)(IPP_TAG_KEYWORD | IPP_TAG_COPY),
-+                   "notify-events", NULL, name);
-+    }
-+    else
-+    {
-+     /*
-+      * Complex event list...
-+      */
-+
-+      for (mask = 1, count = 0; mask < CUPSD_EVENT_ALL; mask <<= 1)
-+	if (sub->mask & mask)
-+          count ++;
-+
-+      attr = ippAddStrings(con->response, IPP_TAG_SUBSCRIPTION,
-+                           (ipp_tag_t)(IPP_TAG_KEYWORD | IPP_TAG_COPY),
-+                           "notify-events", count, NULL, NULL);
-+
-+      for (mask = 1, count = 0; mask < CUPSD_EVENT_ALL; mask <<= 1)
-+	if (sub->mask & mask)
-+	{
-+          attr->values[count].string.text =
-+	      (char *)cupsdEventName((cupsd_eventmask_t)mask);
-+
-+          count ++;
-+	}
-+    }
-+  }
-+
-+  if (sub->job && (!ra || cupsArrayFind(ra, "notify-job-id")))
-+    ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
-+                  "notify-job-id", sub->job->id);
-+
-+  if (!sub->job && (!ra || cupsArrayFind(ra, "notify-lease-duration")))
-+    ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
-+                  "notify-lease-duration", sub->lease);
-+
-+  if (sub->dest && (!ra || cupsArrayFind(ra, "notify-printer-uri")))
-+  {
-+    httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri),
-+                     "ipp", NULL, con->servername, con->serverport,
-+		     "/printers/%s", sub->dest->name);
-+    ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI,
-+        	 "notify-printer-uri", NULL, printer_uri);
-+  }
-+
-+  if (sub->recipient && (!ra || cupsArrayFind(ra, "notify-recipient-uri")))
-+    ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI,
-+        	 "notify-recipient-uri", NULL, sub->recipient);
-+  else if (!ra || cupsArrayFind(ra, "notify-pull-method"))
-+    ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD,
-+                 "notify-pull-method", NULL, "ippget");
-+
-+  if (!ra || cupsArrayFind(ra, "notify-subscriber-user-name"))
-+    ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_NAME,
-+        	 "notify-subscriber-user-name", NULL, sub->owner);
-+
-+  if (!ra || cupsArrayFind(ra, "notify-subscription-id"))
-+    ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
-+                  "notify-subscription-id", sub->id);
-+
-+  if (!ra || cupsArrayFind(ra, "notify-time-interval"))
-+    ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
-+                  "notify-time-interval", sub->interval);
-+
-+  if (sub->user_data_len > 0 && (!ra || cupsArrayFind(ra, "notify-user-data")))
-+    ippAddOctetString(con->response, IPP_TAG_SUBSCRIPTION, "notify-user-data",
-+                      sub->user_data, sub->user_data_len);
-+}
-+
-+
-+/*
-+ * 'create_job()' - Print a file to a printer or class.
-+ */
-+
-+static void
-+create_job(cupsd_client_t  *con,	/* I - Client connection */
-+	   ipp_attribute_t *uri)	/* I - Printer URI */
-+{
-+  cupsd_job_t	*job;			/* New job */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "create_job(%p[%d], %s)", con,
-+                  con->http.fd, uri->values[0].string.text);
-+
-+ /*
-+  * Create the job object...
-+  */
-+
-+  if ((job = add_job(con, uri, NULL, NULL)) == NULL)
-+    return;
-+
-+ /*
-+  * Save and log the job...
-+  */
-+   
-+  cupsdSaveJob(job);
-+
-+  cupsdLogMessage(CUPSD_LOG_INFO, "Job %d created on \"%s\" by \"%s\".",
-+                  job->id, job->dest, job->username);
-+}
-+
-+
-+/*
-+ * 'create_requested_array()' - Create an array for the requested-attributes.
-+ */
-+
-+static cups_array_t *			/* O - Array of attributes or NULL */
-+create_requested_array(ipp_t *request)	/* I - IPP request */
-+{
-+  int			i;		/* Looping var */
-+  ipp_attribute_t	*requested;	/* requested-attributes attribute */
-+  cups_array_t		*ra;		/* Requested attributes array */
-+  char			*value;		/* Current value */
-+
-+
-+ /*
-+  * Get the requested-attributes attribute, and return NULL if we don't
-+  * have one...
-+  */
-+
-+  if ((requested = ippFindAttribute(request, "requested-attributes",
-+                                    IPP_TAG_KEYWORD)) == NULL)
-+    return (NULL);
-+
-+ /*
-+  * If the attribute contains a single "all" keyword, return NULL...
-+  */
-+
-+  if (requested->num_values == 1 &&
-+      !strcmp(requested->values[0].string.text, "all"))
-+    return (NULL);
-+
-+ /*
-+  * Create an array using "strcmp" as the comparison function...
-+  */
-+
-+  ra = cupsArrayNew((cups_array_func_t)strcmp, NULL);
-+
-+  for (i = 0; i < requested->num_values; i ++)
-+  {
-+    value = requested->values[i].string.text;
-+
-+    if (!strcmp(value, "job-template"))
-+    {
-+      cupsArrayAdd(ra, "copies");
-+      cupsArrayAdd(ra, "copies-default");
-+      cupsArrayAdd(ra, "copies-supported");
-+      cupsArrayAdd(ra, "finishings");
-+      cupsArrayAdd(ra, "finishings-default");
-+      cupsArrayAdd(ra, "finishings-supported");
-+      cupsArrayAdd(ra, "job-hold-until");
-+      cupsArrayAdd(ra, "job-hold-until-default");
-+      cupsArrayAdd(ra, "job-hold-until-supported");
-+      cupsArrayAdd(ra, "job-priority");
-+      cupsArrayAdd(ra, "job-priority-default");
-+      cupsArrayAdd(ra, "job-priority-supported");
-+      cupsArrayAdd(ra, "job-sheets");
-+      cupsArrayAdd(ra, "job-sheets-default");
-+      cupsArrayAdd(ra, "job-sheets-supported");
-+      cupsArrayAdd(ra, "media");
-+      cupsArrayAdd(ra, "media-default");
-+      cupsArrayAdd(ra, "media-supported");
-+      cupsArrayAdd(ra, "multiple-document-handling");
-+      cupsArrayAdd(ra, "multiple-document-handling-default");
-+      cupsArrayAdd(ra, "multiple-document-handling-supported");
-+      cupsArrayAdd(ra, "number-up");
-+      cupsArrayAdd(ra, "number-up-default");
-+      cupsArrayAdd(ra, "number-up-supported");
-+      cupsArrayAdd(ra, "orientation-requested");
-+      cupsArrayAdd(ra, "orientation-requested-default");
-+      cupsArrayAdd(ra, "orientation-requested-supported");
-+      cupsArrayAdd(ra, "page-ranges");
-+      cupsArrayAdd(ra, "page-ranges-supported");
-+      cupsArrayAdd(ra, "printer-resolution");
-+      cupsArrayAdd(ra, "printer-resolution-default");
-+      cupsArrayAdd(ra, "printer-resolution-supported");
-+      cupsArrayAdd(ra, "print-quality");
-+      cupsArrayAdd(ra, "print-quality-default");
-+      cupsArrayAdd(ra, "print-quality-supported");
-+      cupsArrayAdd(ra, "sides");
-+      cupsArrayAdd(ra, "sides-default");
-+      cupsArrayAdd(ra, "sides-supported");
-+    }
-+    else if (!strcmp(value, "job-description"))
-+    {
-+      cupsArrayAdd(ra, "date-time-at-completed");
-+      cupsArrayAdd(ra, "date-time-at-creation");
-+      cupsArrayAdd(ra, "date-time-at-processing");
-+      cupsArrayAdd(ra, "job-detailed-status-message");
-+      cupsArrayAdd(ra, "job-document-access-errors");
-+      cupsArrayAdd(ra, "job-id");
-+      cupsArrayAdd(ra, "job-impressions");
-+      cupsArrayAdd(ra, "job-impressions-completed");
-+      cupsArrayAdd(ra, "job-k-octets");
-+      cupsArrayAdd(ra, "job-k-octets-processed");
-+      cupsArrayAdd(ra, "job-media-sheets");
-+      cupsArrayAdd(ra, "job-media-sheets-completed");
-+      cupsArrayAdd(ra, "job-message-from-operator");
-+      cupsArrayAdd(ra, "job-more-info");
-+      cupsArrayAdd(ra, "job-name");
-+      cupsArrayAdd(ra, "job-originating-user-name");
-+      cupsArrayAdd(ra, "job-printer-up-time");
-+      cupsArrayAdd(ra, "job-printer-uri");
-+      cupsArrayAdd(ra, "job-state");
-+      cupsArrayAdd(ra, "job-state-message");
-+      cupsArrayAdd(ra, "job-state-reasons");
-+      cupsArrayAdd(ra, "job-uri");
-+      cupsArrayAdd(ra, "number-of-documents");
-+      cupsArrayAdd(ra, "number-of-intervening-jobs");
-+      cupsArrayAdd(ra, "output-device-assigned");
-+      cupsArrayAdd(ra, "time-at-completed");
-+      cupsArrayAdd(ra, "time-at-creation");
-+      cupsArrayAdd(ra, "time-at-processing");
-+    }
-+    else if (!strcmp(value, "printer-description"))
-+    {
-+      cupsArrayAdd(ra, "charset-configured");
-+      cupsArrayAdd(ra, "charset-supported");
-+      cupsArrayAdd(ra, "color-supported");
-+      cupsArrayAdd(ra, "compression-supported");
-+      cupsArrayAdd(ra, "document-format-default");
-+      cupsArrayAdd(ra, "document-format-supported");
-+      cupsArrayAdd(ra, "generated-natural-language-supported");
-+      cupsArrayAdd(ra, "ipp-versions-supported");
-+      cupsArrayAdd(ra, "job-impressions-supported");
-+      cupsArrayAdd(ra, "job-k-octets-supported");
-+      cupsArrayAdd(ra, "job-media-sheets-supported");
-+      cupsArrayAdd(ra, "multiple-document-jobs-supported");
-+      cupsArrayAdd(ra, "multiple-operation-time-out");
-+      cupsArrayAdd(ra, "natural-language-configured");
-+      cupsArrayAdd(ra, "notify-attributes-supported");
-+      cupsArrayAdd(ra, "notify-lease-duration-default");
-+      cupsArrayAdd(ra, "notify-lease-duration-supported");
-+      cupsArrayAdd(ra, "notify-max-events-supported");
-+      cupsArrayAdd(ra, "notify-events-default");
-+      cupsArrayAdd(ra, "notify-events-supported");
-+      cupsArrayAdd(ra, "notify-pull-method-supported");
-+      cupsArrayAdd(ra, "notify-schemes-supported");
-+      cupsArrayAdd(ra, "operations-supported");
-+      cupsArrayAdd(ra, "pages-per-minute");
-+      cupsArrayAdd(ra, "pages-per-minute-color");
-+      cupsArrayAdd(ra, "pdl-override-supported");
-+      cupsArrayAdd(ra, "printer-current-time");
-+      cupsArrayAdd(ra, "printer-driver-installer");
-+      cupsArrayAdd(ra, "printer-info");
-+      cupsArrayAdd(ra, "printer-is-accepting-jobs");
-+      cupsArrayAdd(ra, "printer-location");
-+      cupsArrayAdd(ra, "printer-make-and-model");
-+      cupsArrayAdd(ra, "printer-message-from-operator");
-+      cupsArrayAdd(ra, "printer-more-info");
-+      cupsArrayAdd(ra, "printer-more-info-manufacturer");
-+      cupsArrayAdd(ra, "printer-name");
-+      cupsArrayAdd(ra, "printer-state");
-+      cupsArrayAdd(ra, "printer-state-message");
-+      cupsArrayAdd(ra, "printer-state-reasons");
-+      cupsArrayAdd(ra, "printer-up-time");
-+      cupsArrayAdd(ra, "printer-uri-supported");
-+      cupsArrayAdd(ra, "queued-job-count");
-+      cupsArrayAdd(ra, "reference-uri-schemes-supported");
-+      cupsArrayAdd(ra, "uri-authentication-supported");
-+      cupsArrayAdd(ra, "uri-security-supported");
-+    }
-+    else if (!strcmp(value, "subscription-template"))
-+    {
-+      cupsArrayAdd(ra, "notify-attributes");
-+      cupsArrayAdd(ra, "notify-charset");
-+      cupsArrayAdd(ra, "notify-events");
-+      cupsArrayAdd(ra, "notify-lease-duration");
-+      cupsArrayAdd(ra, "notify-natural-language");
-+      cupsArrayAdd(ra, "notify-pull-method");
-+      cupsArrayAdd(ra, "notify-recipient-uri");
-+      cupsArrayAdd(ra, "notify-time-interval");
-+      cupsArrayAdd(ra, "notify-user-data");
-+    }
-+    else
-+      cupsArrayAdd(ra, value);
-+  }
-+
-+  return (ra);
-+}
-+
-+
-+/*
-+ * 'create_subscription()' - Create a notification subscription.
-+ */
-+
-+static void
-+create_subscription(
-+    cupsd_client_t  *con,		/* I - Client connection */
-+    ipp_attribute_t *uri)		/* I - Printer URI */
-+{
-+  http_status_t	status;			/* Policy status */
-+  int			i;		/* Looping var */
-+  ipp_attribute_t	*attr;		/* Current attribute */
-+  cups_ptype_t		dtype;		/* Destination type (printer or class) */
-+  char			scheme[HTTP_MAX_URI],
-+					/* Scheme portion of URI */
-+			userpass[HTTP_MAX_URI],
-+					/* Username portion of URI */
-+			host[HTTP_MAX_URI],
-+					/* Host portion of URI */
-+			resource[HTTP_MAX_URI];
-+					/* Resource portion of URI */
-+  int			port;		/* Port portion of URI */
-+  cupsd_printer_t	*printer;	/* Printer/class */
-+  cupsd_job_t		*job;		/* Job */
-+  int			jobid;		/* Job ID */
-+  cupsd_subscription_t	*sub;		/* Subscription object */
-+  const char		*username,	/* requesting-user-name or authenticated username */
-+			*recipient,	/* notify-recipient-uri */
-+			*pullmethod;	/* notify-pull-method */
-+  ipp_attribute_t	*user_data;	/* notify-user-data */
-+  int			interval,	/* notify-time-interval */
-+			lease;		/* notify-lease-duration */
-+  unsigned		mask;		/* notify-events */
-+
-+
-+#ifdef DEBUG
-+  for (attr = con->request->attrs; attr; attr = attr->next)
-+  {
-+    if (attr->group_tag != IPP_TAG_ZERO)
-+      cupsdLogMessage(CUPSD_LOG_DEBUG, "g%04x v%04x %s", attr->group_tag,
-+                      attr->value_tag, attr->name);
-+    else
-+      cupsdLogMessage(CUPSD_LOG_DEBUG, "----SEP----");
-+  }
-+#endif /* DEBUG */
-+
-+ /*
-+  * Is the destination valid?
-+  */
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG,
-+                  "cupsdCreateSubscription(con=%p(%d), uri=\"%s\")",
-+                  con, con->http.fd, uri->values[0].string.text);
-+
-+  httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
-+                  sizeof(scheme), userpass, sizeof(userpass), host,
-+		  sizeof(host), &port, resource, sizeof(resource));
-+
-+  if (!strcmp(resource, "/"))
-+  {
-+    dtype   = (cups_ptype_t)0;
-+    printer = NULL;
-+  }
-+  else if (!strncmp(resource, "/printers", 9) && strlen(resource) <= 10)
-+  {
-+    dtype   = (cups_ptype_t)0;
-+    printer = NULL;
-+  }
-+  else if (!strncmp(resource, "/classes", 8) && strlen(resource) <= 9)
-+  {
-+    dtype   = CUPS_PRINTER_CLASS;
-+    printer = NULL;
-+  }
-+  else if (!cupsdValidateDest(host, resource, &dtype, &printer))
-+  {
-+   /*
-+    * Bad URI...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_FOUND,
-+                    _("The printer or class was not found."));
-+    return;
-+  }
-+
-+ /*
-+  * Check policy...
-+  */
-+
-+  if (printer)
-+  {
-+    if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
-+    {
-+      send_http_error(con, status);
-+      return;
-+    }
-+  }
-+  else if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
-+  {
-+    send_http_error(con, status);
-+    return;
-+  }
-+
-+ /*
-+  * Get the user that is requesting the subscription...
-+  */
-+
-+  username = get_username(con);
-+
-+ /*
-+  * Find the first subscription group attribute; return if we have
-+  * none...
-+  */
-+
-+  for (attr = con->request->attrs; attr; attr = attr->next)
-+    if (attr->group_tag == IPP_TAG_SUBSCRIPTION)
-+      break;
-+
-+  if (!attr)
-+  {
-+    send_ipp_status(con, IPP_BAD_REQUEST,
-+                    _("No subscription attributes in request!"));
-+    return;
-+  }
-+
-+ /*
-+  * Process the subscription attributes in the request...
-+  */
-+
-+  con->response->request.status.status_code = IPP_BAD_REQUEST;
-+
-+  while (attr)
-+  {
-+    recipient = NULL;
-+    pullmethod = NULL;
-+    user_data  = NULL;
-+    interval   = 0;
-+    lease      = DefaultLeaseDuration;
-+    jobid      = 0;
-+    mask       = CUPSD_EVENT_NONE;
-+
-+    while (attr && attr->group_tag != IPP_TAG_ZERO)
-+    {
-+      if (!strcmp(attr->name, "notify-recipient") &&
-+          attr->value_tag == IPP_TAG_URI)
-+      {
-+       /*
-+        * Validate the recipient scheme against the ServerBin/notifier
-+	* directory...
-+	*/
-+
-+	char	notifier[1024];		/* Notifier filename */
-+
-+
-+        recipient = attr->values[0].string.text;
-+
-+	if (httpSeparateURI(HTTP_URI_CODING_ALL, recipient,
-+	                    scheme, sizeof(scheme), userpass, sizeof(userpass),
-+			    host, sizeof(host), &port,
-+			    resource, sizeof(resource)) < HTTP_URI_OK)
-+        {
-+          send_ipp_status(con, IPP_NOT_POSSIBLE,
-+	                  _("Bad notify-recipient URI \"%s\"!"), recipient);
-+	  ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
-+	                "notify-status-code", IPP_URI_SCHEME);
-+	  return;
-+	}
-+
-+        snprintf(notifier, sizeof(notifier), "%s/notifier/%s", ServerBin,
-+	         scheme);
-+        if (access(notifier, X_OK))
-+	{
-+          send_ipp_status(con, IPP_NOT_POSSIBLE,
-+	                  _("notify-recipient URI \"%s\" uses unknown scheme!"),
-+			  recipient);
-+	  ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
-+	                "notify-status-code", IPP_URI_SCHEME);
-+	  return;
-+	}
-+      }
-+      else if (!strcmp(attr->name, "notify-pull-method") &&
-+               attr->value_tag == IPP_TAG_KEYWORD)
-+      {
-+        pullmethod = attr->values[0].string.text;
-+
-+        if (strcmp(pullmethod, "ippget"))
-+	{
-+          send_ipp_status(con, IPP_NOT_POSSIBLE,
-+	                  _("Bad notify-pull-method \"%s\"!"), pullmethod);
-+	  ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
-+	                "notify-status-code", IPP_ATTRIBUTES);
-+	  return;
-+	}
-+      }
-+      else if (!strcmp(attr->name, "notify-charset") &&
-+               attr->value_tag == IPP_TAG_CHARSET &&
-+	       strcmp(attr->values[0].string.text, "us-ascii") &&
-+	       strcmp(attr->values[0].string.text, "utf-8"))
-+      {
-+        send_ipp_status(con, IPP_CHARSET,
-+	                _("Character set \"%s\" not supported!"),
-+			attr->values[0].string.text);
-+	return;
-+      }
-+      else if (!strcmp(attr->name, "notify-natural-language") &&
-+               (attr->value_tag != IPP_TAG_LANGUAGE ||
-+	        strcmp(attr->values[0].string.text, DefaultLanguage)))
-+      {
-+        send_ipp_status(con, IPP_CHARSET,
-+	                _("Language \"%s\" not supported!"),
-+			attr->values[0].string.text);
-+	return;
-+      }
-+      else if (!strcmp(attr->name, "notify-user-data") &&
-+               attr->value_tag == IPP_TAG_STRING)
-+      {
-+        if (attr->num_values > 1 || attr->values[0].unknown.length > 63)
-+	{
-+          send_ipp_status(con, IPP_REQUEST_VALUE,
-+	                  _("The notify-user-data value is too large "
-+			    "(%d > 63 octets)!"),
-+			  attr->values[0].unknown.length);
-+	  return;
-+	}
-+
-+        user_data = attr;
-+      }
-+      else if (!strcmp(attr->name, "notify-events") &&
-+               attr->value_tag == IPP_TAG_KEYWORD)
-+      {
-+        for (i = 0; i < attr->num_values; i ++)
-+	  mask |= cupsdEventValue(attr->values[i].string.text);
-+      }
-+      else if (!strcmp(attr->name, "notify-lease-duration") &&
-+               attr->value_tag == IPP_TAG_INTEGER)
-+        lease = attr->values[0].integer;
-+      else if (!strcmp(attr->name, "notify-time-interval") &&
-+               attr->value_tag == IPP_TAG_INTEGER)
-+        interval = attr->values[0].integer;
-+      else if (!strcmp(attr->name, "notify-job-id") &&
-+               attr->value_tag == IPP_TAG_INTEGER)
-+        jobid = attr->values[0].integer;
-+
-+      attr = attr->next;
-+    }
-+
-+    if (recipient)
-+      cupsdLogMessage(CUPSD_LOG_DEBUG, "recipient=\"%s\"", recipient);
-+    if (pullmethod)
-+      cupsdLogMessage(CUPSD_LOG_DEBUG, "pullmethod=\"%s\"", pullmethod);
-+    cupsdLogMessage(CUPSD_LOG_DEBUG, "notify-lease-duration=%d", lease);
-+    cupsdLogMessage(CUPSD_LOG_DEBUG, "notify-time-interval=%d", interval);
-+
-+    if (!recipient && !pullmethod)
-+      break;
-+
-+    if (mask == CUPSD_EVENT_NONE)
-+    {
-+      if (jobid)
-+        mask = CUPSD_EVENT_JOB_COMPLETED;
-+      else if (printer)
-+        mask = CUPSD_EVENT_PRINTER_STATE_CHANGED;
-+      else
-+      {
-+        send_ipp_status(con, IPP_BAD_REQUEST,
-+	                _("notify-events not specified!"));
-+	return;
-+      }
-+    }
-+
-+    if (MaxLeaseDuration && (lease == 0 || lease > MaxLeaseDuration))
-+    {
-+      cupsdLogMessage(CUPSD_LOG_INFO,
-+                      "create_subscription: Limiting notify-lease-duration to "
-+		      "%d seconds.",
-+		      MaxLeaseDuration);
-+      lease = MaxLeaseDuration;
-+    }
-+
-+    if (jobid)
-+    {
-+      if ((job = cupsdFindJob(jobid)) == NULL)
-+      {
-+	send_ipp_status(con, IPP_NOT_FOUND, _("Job %d not found!"), jobid);
-+	return;
-+      }
-+    }
-+    else
-+      job = NULL;
-+
-+    sub = cupsdAddSubscription(mask, printer, job, recipient, 0);
-+
-+    if (job)
-+      cupsdLogMessage(CUPSD_LOG_DEBUG, "Added subscription %d for job %d",
-+		      sub->id, job->id);
-+    else if (printer)
-+      cupsdLogMessage(CUPSD_LOG_DEBUG,
-+                      "Added subscription %d for printer \"%s\"",
-+		      sub->id, printer->name);
-+    else
-+      cupsdLogMessage(CUPSD_LOG_DEBUG, "Added subscription %d for server",
-+		      sub->id);
-+
-+    sub->interval = interval;
-+    sub->lease    = lease;
-+    sub->expire   = lease ? time(NULL) + lease : 0;
-+
-+    cupsdSetString(&sub->owner, username);
-+
-+    if (user_data)
-+    {
-+      sub->user_data_len = user_data->values[0].unknown.length;
-+      memcpy(sub->user_data, user_data->values[0].unknown.data,
-+             sub->user_data_len);
-+    }
-+
-+    ippAddSeparator(con->response);
-+    ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
-+                  "notify-subscription-id", sub->id);
-+
-+    con->response->request.status.status_code = IPP_OK;
-+
-+    if (attr)
-+      attr = attr->next;
-+  }
-+
-+  cupsdSaveAllSubscriptions();
-+
-+}
-+
-+
-+/*
-+ * 'delete_printer()' - Remove a printer or class from the system.
-+ */
-+
-+static void
-+delete_printer(cupsd_client_t  *con,	/* I - Client connection */
-+               ipp_attribute_t *uri)	/* I - URI of printer or class */
-+{
-+  http_status_t	status;			/* Policy status */
-+  const char	*dest;			/* Destination */
-+  cups_ptype_t	dtype;			/* Destination type (printer or class) */
-+  char		method[HTTP_MAX_URI],	/* Method portion of URI */
-+		username[HTTP_MAX_URI],	/* Username portion of URI */
-+		host[HTTP_MAX_URI],	/* Host portion of URI */
-+		resource[HTTP_MAX_URI];	/* Resource portion of URI */
-+  int		port;			/* Port portion of URI */
-+  cupsd_printer_t *printer;		/* Printer/class */
-+  char		filename[1024];		/* Script/PPD filename */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "delete_printer(%p[%d], %s)", con,
-+                  con->http.fd, uri->values[0].string.text);
-+
-+ /*
-+  * Do we have a valid URI?
-+  */
-+
-+  httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
-+                  sizeof(method), username, sizeof(username), host,
-+		  sizeof(host), &port, resource, sizeof(resource));
-+
-+  if ((dest = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL)
-+  {
-+   /*
-+    * Bad URI...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_FOUND,
-+                    _("The printer or class was not found."));
-+    return;
-+  }
-+
-+ /*
-+  * Check policy...
-+  */
-+
-+  if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
-+  {
-+    send_http_error(con, status);
-+    return;
-+  }
-+
-+ /*
-+  * Remove old jobs...
-+  */
-+
-+  cupsdCancelJobs(dest, NULL, 1);
-+
-+ /*
-+  * Remove old subscriptions and send a "deleted printer" event...
-+  */
-+
-+  cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, printer, NULL,
-+                "%s \"%s\" deleted by \"%s\".",
-+		(dtype & CUPS_PRINTER_CLASS) ? "Class" : "Printer",
-+		dest, get_username(con));
-+
-+  cupsdExpireSubscriptions(printer, NULL);
-+ 
-+ /*
-+  * Remove any old PPD or script files...
-+  */
-+
-+  snprintf(filename, sizeof(filename), "%s/interfaces/%s", ServerRoot, dest);
-+  unlink(filename);
-+
-+  snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot, dest);
-+  unlink(filename);
-+
-+  if (dtype & CUPS_PRINTER_CLASS)
-+  {
-+    cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" deleted by \"%s\".", dest,
-+                    get_username(con));
-+
-+    cupsdDeletePrinter(printer, 0);
-+    cupsdSaveAllClasses();
-+  }
-+  else
-+  {
-+    cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" deleted by \"%s\".", dest,
-+                    get_username(con));
-+
-+    cupsdDeletePrinter(printer, 0);
-+    cupsdSaveAllPrinters();
-+  }
-+
-+  cupsdWritePrintcap();
-+
-+ /*
-+  * Return with no errors...
-+  */
-+
-+  con->response->request.status.status_code = IPP_OK;
-+}
-+
-+
-+/*
-+ * 'get_default()' - Get the default destination.
-+ */
-+
-+static void
-+get_default(cupsd_client_t *con)	/* I - Client connection */
-+{
-+  http_status_t	status;			/* Policy status */
-+  cups_array_t	*ra;			/* Requested attributes array */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_default(%p[%d])", con, con->http.fd);
-+
-+ /*
-+  * Check policy...
-+  */
-+
-+  if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
-+  {
-+    send_http_error(con, status);
-+    return;
-+  }
-+
-+  if (DefaultPrinter)
-+  {
-+    ra = create_requested_array(con->request);
-+
-+    copy_printer_attrs(con, DefaultPrinter, ra);
-+
-+    cupsArrayDelete(ra);
-+
-+    con->response->request.status.status_code = IPP_OK;
-+  }
-+  else
-+    send_ipp_status(con, IPP_NOT_FOUND, _("No default printer"));
-+}
-+
-+
-+/*
-+ * 'get_devices()' - Get the list of available devices on the local system.
-+ */
-+
-+static void
-+get_devices(cupsd_client_t *con)	/* I - Client connection */
-+{
-+  http_status_t		status;		/* Policy status */
-+  ipp_attribute_t	*limit,		/* Limit attribute */
-+			*requested;	/* requested-attributes attribute */
-+  char			command[1024],	/* cups-deviced command */
-+			options[1024],	/* Options to pass to command */
-+			requested_str[256];
-+					/* String for requested attributes */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_devices(%p[%d])", con, con->http.fd);
-+
-+ /*
-+  * Check policy...
-+  */
-+
-+  if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
-+  {
-+    send_http_error(con, status);
-+    return;
-+  }
-+
-+ /*
-+  * Run cups-deviced command with the given options...
-+  */
-+
-+  limit = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER);
-+  requested = ippFindAttribute(con->request, "requested-attributes",
-+                               IPP_TAG_KEYWORD);
-+
-+  if (requested)
-+    url_encode_attr(requested, requested_str, sizeof(requested_str));
-+  else
-+    strlcpy(requested_str, "requested-attributes=all", sizeof(requested_str));
-+
-+  snprintf(command, sizeof(command), "%s/daemon/cups-deviced", ServerBin);
-+  snprintf(options, sizeof(options),
-+           "%d+%d+%d+%s",
-+           con->request->request.op.request_id,
-+           limit ? limit->values[0].integer : 0, (int)User,
-+	   requested_str);
-+
-+  if (cupsdSendCommand(con, command, options, 1))
-+  {
-+   /*
-+    * Command started successfully, don't send an IPP response here...
-+    */
-+
-+    ippDelete(con->response);
-+    con->response = NULL;
-+  }
-+  else
-+  {
-+   /*
-+    * Command failed, return "internal error" so the user knows something
-+    * went wrong...
-+    */
-+
-+    send_ipp_status(con, IPP_INTERNAL_ERROR,
-+                    _("cups-deviced failed to execute."));
-+  }
-+}
-+
-+
-+/*
-+ * 'get_job_attrs()' - Get job attributes.
-+ */
-+
-+static void
-+get_job_attrs(cupsd_client_t  *con,	/* I - Client connection */
-+	      ipp_attribute_t *uri)	/* I - Job URI */
-+{
-+  http_status_t	status;			/* Policy status */
-+  ipp_attribute_t *attr;		/* Current attribute */
-+  int		jobid;			/* Job ID */
-+  cupsd_job_t	*job;			/* Current job */
-+  char		method[HTTP_MAX_URI],	/* Method portion of URI */
-+		username[HTTP_MAX_URI],	/* Username portion of URI */
-+		host[HTTP_MAX_URI],	/* Host portion of URI */
-+		resource[HTTP_MAX_URI];	/* Resource portion of URI */
-+  int		port;			/* Port portion of URI */
-+  cups_array_t	*ra;			/* Requested attributes array */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_job_attrs(%p[%d], %s)", con,
-+                  con->http.fd, uri->values[0].string.text);
-+
-+ /*
-+  * See if we have a job URI or a printer URI...
-+  */
-+
-+  if (!strcmp(uri->name, "printer-uri"))
-+  {
-+   /*
-+    * Got a printer URI; see if we also have a job-id attribute...
-+    */
-+
-+    if ((attr = ippFindAttribute(con->request, "job-id",
-+                                 IPP_TAG_INTEGER)) == NULL)
-+    {
-+      send_ipp_status(con, IPP_BAD_REQUEST,
-+                      _("Got a printer-uri attribute but no job-id!"));
-+      return;
-+    }
-+
-+    jobid = attr->values[0].integer;
-+  }
-+  else
-+  {
-+   /*
-+    * Got a job URI; parse it to get the job ID...
-+    */
-+
-+    httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
-+                    sizeof(method), username, sizeof(username), host,
-+		    sizeof(host), &port, resource, sizeof(resource));
-+
-+    if (strncmp(resource, "/jobs/", 6))
-+    {
-+     /*
-+      * Not a valid URI!
-+      */
-+
-+      send_ipp_status(con, IPP_BAD_REQUEST,
-+                      _("Bad job-uri attribute \"%s\"!"),
-+                      uri->values[0].string.text);
-+      return;
-+    }
-+
-+    jobid = atoi(resource + 6);
-+  }
-+
-+ /*
-+  * See if the job exists...
-+  */
-+
-+  if ((job = cupsdFindJob(jobid)) == NULL)
-+  {
-+   /*
-+    * Nope - return a "not found" error...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), jobid);
-+    return;
-+  }
-+
-+ /*
-+  * Check policy...
-+  */
-+
-+  if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
-+  {
-+    send_http_error(con, status);
-+    return;
-+  }
-+
-+ /*
-+  * Copy attributes...
-+  */
-+
-+  cupsdLoadJob(job);
-+
-+  ra = create_requested_array(con->request);
-+  copy_job_attrs(con, job, ra);
-+  cupsArrayDelete(ra);
-+
-+  con->response->request.status.status_code = IPP_OK;
-+}
-+
-+
-+/*
-+ * 'get_jobs()' - Get a list of jobs for the specified printer.
-+ */
-+
-+static void
-+get_jobs(cupsd_client_t  *con,		/* I - Client connection */
-+	 ipp_attribute_t *uri)		/* I - Printer URI */
-+{
-+  http_status_t	status;			/* Policy status */
-+  ipp_attribute_t *attr;		/* Current attribute */
-+  const char	*dest;			/* Destination */
-+  cups_ptype_t	dtype;			/* Destination type (printer or class) */
-+  cups_ptype_t	dmask;			/* Destination type mask */
-+  char		method[HTTP_MAX_URI],	/* Method portion of URI */
-+		username[HTTP_MAX_URI],	/* Username portion of URI */
-+		host[HTTP_MAX_URI],	/* Host portion of URI */
-+		resource[HTTP_MAX_URI];	/* Resource portion of URI */
-+  int		port;			/* Port portion of URI */
-+  int		completed;		/* Completed jobs? */
-+  int		first_job_id;		/* First job ID */
-+  int		limit;			/* Maximum number of jobs to return */
-+  int		count;			/* Number of jobs that match */
-+  cupsd_job_t	*job;			/* Current job pointer */
-+  cupsd_printer_t *printer;		/* Printer */
-+  cups_array_t	*list;			/* Which job list... */
-+  cups_array_t	*ra;			/* Requested attributes array */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs(%p[%d], %s)", con, con->http.fd,
-+                  uri->values[0].string.text);
-+
-+ /*
-+  * Is the destination valid?
-+  */
-+
-+  httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
-+                  sizeof(method), username, sizeof(username), host,
-+		  sizeof(host), &port, resource, sizeof(resource));
-+
-+  if (!strcmp(resource, "/") ||
-+      (!strncmp(resource, "/jobs", 5) && strlen(resource) <= 6))
-+  {
-+    dest    = NULL;
-+    dtype   = (cups_ptype_t)0;
-+    dmask   = (cups_ptype_t)0;
-+    printer = NULL;
-+  }
-+  else if (!strncmp(resource, "/printers", 9) && strlen(resource) <= 10)
-+  {
-+    dest    = NULL;
-+    dtype   = (cups_ptype_t)0;
-+    dmask   = CUPS_PRINTER_CLASS;
-+    printer = NULL;
-+  }
-+  else if (!strncmp(resource, "/classes", 8) && strlen(resource) <= 9)
-+  {
-+    dest    = NULL;
-+    dtype   = CUPS_PRINTER_CLASS;
-+    dmask   = CUPS_PRINTER_CLASS;
-+    printer = NULL;
-+  }
-+  else if ((dest = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL)
-+  {
-+   /*
-+    * Bad URI...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_FOUND,
-+                    _("The printer or class was not found."));
-+    return;
-+  }
-+  else
-+  {
-+    dtype &= CUPS_PRINTER_CLASS;
-+    dmask = CUPS_PRINTER_CLASS;
-+  }
-+
-+ /*
-+  * Check policy...
-+  */
-+
-+  if (printer)
-+  {
-+    if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
-+    {
-+      send_http_error(con, status);
-+      return;
-+    }
-+  }
-+  else if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
-+  {
-+    send_http_error(con, status);
-+    return;
-+  }
-+
-+ /*
-+  * See if the "which-jobs" attribute have been specified...
-+  */
-+
-+  if ((attr = ippFindAttribute(con->request, "which-jobs",
-+                               IPP_TAG_KEYWORD)) != NULL &&
-+      !strcmp(attr->values[0].string.text, "completed"))
-+  {
-+    completed = 1;
-+    list      = Jobs;
-+  }
-+  else if (attr && !strcmp(attr->values[0].string.text, "all"))
-+  {
-+    completed = 0;
-+    list      = Jobs;
-+  }
-+  else
-+  {
-+    completed = 0;
-+    list      = ActiveJobs;
-+  }
-+
-+ /*
-+  * See if they want to limit the number of jobs reported...
-+  */
-+
-+  if ((attr = ippFindAttribute(con->request, "limit",
-+                               IPP_TAG_INTEGER)) != NULL)
-+    limit = attr->values[0].integer;
-+  else
-+    limit = 1000000;
-+
-+  if ((attr = ippFindAttribute(con->request, "first-job-id",
-+                               IPP_TAG_INTEGER)) != NULL)
-+    first_job_id = attr->values[0].integer;
-+  else
-+    first_job_id = 1;
-+
-+ /*
-+  * See if we only want to see jobs for a specific user...
-+  */
-+
-+  if ((attr = ippFindAttribute(con->request, "my-jobs",
-+                               IPP_TAG_BOOLEAN)) != NULL &&
-+      attr->values[0].boolean)
-+    strlcpy(username, get_username(con), sizeof(username));
-+  else
-+    username[0] = '\0';
-+
-+  ra = create_requested_array(con->request);
-+
-+ /*
-+  * OK, build a list of jobs for this printer...
-+  */
-+
-+  for (count = 0, job = (cupsd_job_t *)cupsArrayFirst(list);
-+       count < limit && job;
-+       job = (cupsd_job_t *)cupsArrayNext(list))
-+  {
-+   /*
-+    * Filter out jobs that don't match...
-+    */
-+
-+    cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: job->id = %d", job->id);
-+
-+    if ((dest && strcmp(job->dest, dest)) &&
-+        (!job->printer || !dest || strcmp(job->printer->name, dest)))
-+      continue;
-+    if ((job->dtype & dmask) != dtype &&
-+        (!job->printer || (job->printer->type & dmask) != dtype))
-+      continue;
-+    if (username[0] && strcasecmp(username, job->username))
-+      continue;
-+
-+    if (completed && job->state_value <= IPP_JOB_STOPPED)
-+      continue;
-+
-+    if (job->id < first_job_id)
-+      continue;
-+
-+    cupsdLoadJob(job);
-+
-+    if (!job->attrs)
-+      continue;
-+
-+    if (count > 0)
-+      ippAddSeparator(con->response);
-+
-+    count ++;
-+
-+    cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: count = %d", count);
-+
-+    copy_job_attrs(con, job, ra);
-+  }
-+
-+  cupsArrayDelete(ra);
-+
-+  con->response->request.status.status_code = IPP_OK;
-+}
-+
-+
-+/*
-+ * 'get_notifications()' - Get events for a subscription.
-+ */
-+
-+static void
-+get_notifications(cupsd_client_t *con)	/* I - Client connection */
-+{
-+  int			i, j;		/* Looping vars */
-+  http_status_t		status;		/* Policy status */
-+  cupsd_subscription_t	*sub;		/* Subscription */
-+  ipp_attribute_t	*ids,		/* notify-subscription-ids */
-+			*sequences;	/* notify-sequence-numbers */
-+  int			min_seq;	/* Minimum sequence number */
-+  int			interval;	/* Poll interval */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_subscription_attrs(con=%p[%d])",
-+                  con, con->http.fd);
-+
-+ /*
-+  * Get subscription attributes...
-+  */
-+
-+  ids       = ippFindAttribute(con->request, "notify-subscription-ids",
-+                               IPP_TAG_INTEGER);
-+  sequences = ippFindAttribute(con->request, "notify-sequence-numbers",
-+                               IPP_TAG_INTEGER);
-+
-+  if (!ids)
-+  {
-+    send_ipp_status(con, IPP_BAD_REQUEST,
-+                    _("Missing notify-subscription-ids attribute!"));
-+    return;
-+  }
-+
-+ /*
-+  * Are the subscription IDs valid?
-+  */
-+
-+  for (i = 0, interval = 60; i < ids->num_values; i ++)
-+  {
-+    if ((sub = cupsdFindSubscription(ids->values[i].integer)) == NULL)
-+    {
-+     /*
-+      * Bad subscription ID...
-+      */
-+
-+      send_ipp_status(con, IPP_NOT_FOUND,
-+                      _("notify-subscription-id %d no good!"),
-+		      ids->values[i].integer);
-+      return;
-+    }
-+
-+   /*
-+    * Check policy...
-+    */
-+
-+    if ((status = cupsdCheckPolicy(sub->dest ? sub->dest->op_policy_ptr :
-+                                               DefaultPolicyPtr,
-+                                   con, sub->owner)) != HTTP_OK)
-+    {
-+      send_http_error(con, status);
-+      return;
-+    }
-+
-+   /*
-+    * Check the subscription type and update the interval accordingly.
-+    */
-+
-+    if (sub->job && sub->job->state_value == IPP_JOB_PROCESSING &&
-+        interval > 10)
-+      interval = 10;
-+    else if (sub->job && sub->job->state_value >= IPP_JOB_STOPPED)
-+      interval = 0;
-+    else if (sub->dest && sub->dest->state == IPP_PRINTER_PROCESSING &&
-+             interval > 30)
-+      interval = 30;
-+  }
-+
-+ /*
-+  * Tell the client to poll again in N seconds...
-+  */
-+
-+  if (interval > 0)
-+    ippAddInteger(con->response, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
-+                  "notify-get-interval", interval);
-+
-+  ippAddInteger(con->response, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
-+                "printer-up-time", time(NULL));
-+
-+ /*
-+  * Copy the subscription event attributes to the response.
-+  */
-+
-+  con->response->request.status.status_code =
-+      interval ? IPP_OK : IPP_OK_EVENTS_COMPLETE;
-+
-+  for (i = 0; i < ids->num_values; i ++)
-+  {
-+   /*
-+    * Get the subscription and sequence number...
-+    */
-+
-+    sub = cupsdFindSubscription(ids->values[i].integer);
-+
-+    if (sequences && i < sequences->num_values)
-+      min_seq = sequences->values[i].integer;
-+    else
-+      min_seq = 1;
-+
-+   /*
-+    * If we don't have any new events, nothing to do here...
-+    */
-+
-+    if (min_seq > (sub->first_event_id + sub->num_events))
-+      continue;
-+
-+   /*
-+    * Otherwise copy all of the new events...
-+    */
-+
-+    if (sub->first_event_id > min_seq)
-+      j = 0;
-+    else
-+      j = min_seq - sub->first_event_id;
-+
-+    for (; j < sub->num_events; j ++)
-+    {
-+      ippAddSeparator(con->response);
-+
-+      copy_attrs(con->response, sub->events[j]->attrs, NULL,
-+        	 IPP_TAG_EVENT_NOTIFICATION, 0);
-+    }
-+  }
-+}
-+
-+
-+/*
-+ * 'get_ppds()' - Get the list of PPD files on the local system.
-+ */
-+
-+static void
-+get_ppds(cupsd_client_t *con)		/* I - Client connection */
-+{
-+  http_status_t		status;		/* Policy status */
-+  ipp_attribute_t	*limit,		/* Limit attribute */
-+			*make,		/* ppd-make attribute */
-+			*requested;	/* requested-attributes attribute */
-+  char			command[1024],	/* cups-deviced command */
-+			options[1024],	/* Options to pass to command */
-+			requested_str[256],
-+					/* String for requested attributes */
-+			make_str[256];	/* Escaped ppd-make string */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_ppds(%p[%d])", con, con->http.fd);
-+
-+ /*
-+  * Check policy...
-+  */
-+
-+  if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
-+  {
-+    send_http_error(con, status);
-+    return;
-+  }
-+
-+ /*
-+  * Run cups-driverd command with the given options...
-+  */
-+
-+  limit     = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER);
-+  make      = ippFindAttribute(con->request, "ppd-make", IPP_TAG_TEXT);
-+  requested = ippFindAttribute(con->request, "requested-attributes",
-+                               IPP_TAG_KEYWORD);
-+
-+  if (requested)
-+    url_encode_attr(requested, requested_str, sizeof(requested_str));
-+  else
-+    strlcpy(requested_str, "requested-attributes=all", sizeof(requested_str));
-+
-+  if (make)
-+    url_encode_attr(make, make_str, sizeof(make_str));
-+  else
-+    make_str[0] = '\0';
-+
-+  snprintf(command, sizeof(command), "%s/daemon/cups-driverd", ServerBin);
-+  snprintf(options, sizeof(options), "list+%d+%d+%s%s%s",
-+           con->request->request.op.request_id,
-+           limit ? limit->values[0].integer : 0,
-+	   requested_str, make ? "%20" : "", make_str);
-+
-+  if (cupsdSendCommand(con, command, options, 0))
-+  {
-+   /*
-+    * Command started successfully, don't send an IPP response here...
-+    */
-+
-+    ippDelete(con->response);
-+    con->response = NULL;
-+  }
-+  else
-+  {
-+   /*
-+    * Command failed, return "internal error" so the user knows something
-+    * went wrong...
-+    */
-+
-+    send_ipp_status(con, IPP_INTERNAL_ERROR,
-+                    _("cups-driverd failed to execute."));
-+  }
-+}
-+
-+
-+/*
-+ * 'get_printer_attrs()' - Get printer attributes.
-+ */
-+
-+static void
-+get_printer_attrs(cupsd_client_t  *con,	/* I - Client connection */
-+		  ipp_attribute_t *uri)	/* I - Printer URI */
-+{
-+  http_status_t		status;		/* Policy status */
-+  cups_ptype_t		dtype;		/* Destination type (printer or class) */
-+  char			method[HTTP_MAX_URI],
-+					/* Method portion of URI */
-+			username[HTTP_MAX_URI],
-+					/* Username portion of URI */
-+			host[HTTP_MAX_URI],
-+					/* Host portion of URI */
-+			resource[HTTP_MAX_URI];
-+					/* Resource portion of URI */
-+  int			port;		/* Port portion of URI */
-+  cupsd_printer_t	*printer;	/* Printer/class */
-+  cups_array_t		*ra;		/* Requested attributes array */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_printer_attrs(%p[%d], %s)", con,
-+                  con->http.fd, uri->values[0].string.text);
-+
-+ /*
-+  * Is the destination valid?
-+  */
-+
-+  httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
-+                  sizeof(method), username, sizeof(username), host,
-+		  sizeof(host), &port, resource, sizeof(resource));
-+
-+  if (!cupsdValidateDest(host, resource, &dtype, &printer))
-+  {
-+   /*
-+    * Bad URI...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_FOUND,
-+                    _("The printer or class was not found."));
-+    return;
-+  }
-+
-+ /*
-+  * Check policy...
-+  */
-+
-+  if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
-+  {
-+    send_http_error(con, status);
-+    return;
-+  }
-+
-+ /*
-+  * Send the attributes...
-+  */
-+
-+  ra = create_requested_array(con->request);
-+
-+  copy_printer_attrs(con, printer, ra);
-+
-+  cupsArrayDelete(ra);
-+
-+  con->response->request.status.status_code = IPP_OK;
-+}
-+
-+
-+/*
-+ * 'get_printers()' - Get a list of printers or classes.
-+ */
-+
-+static void
-+get_printers(cupsd_client_t *con,	/* I - Client connection */
-+             int            type)	/* I - 0 or CUPS_PRINTER_CLASS */
-+{
-+  http_status_t	status;			/* Policy status */
-+  ipp_attribute_t *attr;		/* Current attribute */
-+  int		limit;			/* Maximum number of printers to return */
-+  int		count;			/* Number of printers that match */
-+  cupsd_printer_t *printer;		/* Current printer pointer */
-+  int		printer_type,		/* printer-type attribute */
-+		printer_mask;		/* printer-type-mask attribute */
-+  char		*location;		/* Location string */
-+  const char	*username;		/* Current user */
-+  char		*first_printer_name;	/* first-printer-name attribute */
-+  cups_array_t	*ra;			/* Requested attributes array */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_printers(%p[%d], %x)", con,
-+                  con->http.fd, type);
-+
-+ /*
-+  * Check policy...
-+  */
-+
-+  if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
-+  {
-+    send_http_error(con, status);
-+    return;
-+  }
-+
-+ /*
-+  * Check for printers...
-+  */
-+
-+  if (!Printers || !cupsArrayCount(Printers))
-+  {
-+    send_ipp_status(con, IPP_NOT_FOUND, _("No destinations added."));
-+    return;
-+  }
-+
-+ /*
-+  * See if they want to limit the number of printers reported...
-+  */
-+
-+  if ((attr = ippFindAttribute(con->request, "limit",
-+                               IPP_TAG_INTEGER)) != NULL)
-+    limit = attr->values[0].integer;
-+  else
-+    limit = 10000000;
-+
-+  if ((attr = ippFindAttribute(con->request, "first-printer-name",
-+                               IPP_TAG_NAME)) != NULL)
-+    first_printer_name = attr->values[0].string.text;
-+  else
-+    first_printer_name = NULL;
-+
-+ /*
-+  * Support filtering...
-+  */
-+
-+  if ((attr = ippFindAttribute(con->request, "printer-type",
-+                               IPP_TAG_ENUM)) != NULL)
-+    printer_type = attr->values[0].integer;
-+  else
-+    printer_type = 0;
-+
-+  if ((attr = ippFindAttribute(con->request, "printer-type-mask",
-+                               IPP_TAG_ENUM)) != NULL)
-+    printer_mask = attr->values[0].integer;
-+  else
-+    printer_mask = 0;
-+
-+  if ((attr = ippFindAttribute(con->request, "printer-location",
-+                               IPP_TAG_TEXT)) != NULL)
-+    location = attr->values[0].string.text;
-+  else
-+    location = NULL;
-+
-+  if (con->username[0])
-+    username = con->username;
-+  else if ((attr = ippFindAttribute(con->request, "requesting-user-name",
-+                                    IPP_TAG_NAME)) != NULL)
-+    username = attr->values[0].string.text;
-+  else
-+    username = NULL;
-+
-+  ra = create_requested_array(con->request);
-+
-+ /*
-+  * OK, build a list of printers for this printer...
-+  */
-+
-+  if (first_printer_name)
-+  {
-+    if ((printer = cupsdFindDest(first_printer_name)) == NULL)
-+      printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
-+  }
-+  else
-+    printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
-+
-+  for (count = 0;
-+       count < limit && printer;
-+       printer = (cupsd_printer_t *)cupsArrayNext(Printers))
-+  {
-+    if ((!type || (printer->type & CUPS_PRINTER_CLASS) == type) &&
-+        (printer->type & printer_mask) == printer_type &&
-+	(!location || !printer->location ||
-+	 !strcasecmp(printer->location, location)))
-+    {
-+     /*
-+      * If HideImplicitMembers is enabled, see if this printer or class
-+      * is a member of an implicit class...
-+      */
-+
-+      if (ImplicitClasses && HideImplicitMembers &&
-+          printer->in_implicit_class)
-+        continue;
-+
-+     /*
-+      * If a username is specified, see if it is allowed or denied
-+      * access...
-+      */
-+
-+      if (printer->num_users && username && !user_allowed(printer, username))
-+        continue;
-+
-+     /*
-+      * Add the group separator as needed...
-+      */
-+
-+      if (count > 0)
-+        ippAddSeparator(con->response);
-+
-+      count ++;
-+
-+     /*
-+      * Send the attributes...
-+      */
-+
-+      copy_printer_attrs(con, printer, ra);
-+    }
-+  }
-+
-+  cupsArrayDelete(ra);
-+
-+  con->response->request.status.status_code = IPP_OK;
-+}
-+
-+
-+/*
-+ * 'get_subscription_attrs()' - Get subscription attributes.
-+ */
-+
-+static void
-+get_subscription_attrs(
-+    cupsd_client_t *con,		/* I - Client connection */
-+    int            sub_id)		/* I - Subscription ID */
-+{
-+  http_status_t		status;		/* Policy status */
-+  cupsd_subscription_t	*sub;		/* Subscription */
-+  cups_array_t		*ra;		/* Requested attributes array */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-+                  "get_subscription_attrs(con=%p[%d], sub_id=%d)",
-+                  con, con->http.fd, sub_id);
-+
-+ /*
-+  * Is the subscription ID valid?
-+  */
-+
-+  if ((sub = cupsdFindSubscription(sub_id)) == NULL)
-+  {
-+   /*
-+    * Bad subscription ID...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_FOUND,
-+                    _("notify-subscription-id %d no good!"), sub_id);
-+    return;
-+  }
-+
-+ /*
-+  * Check policy...
-+  */
-+
-+  if ((status = cupsdCheckPolicy(sub->dest ? sub->dest->op_policy_ptr :
-+                                             DefaultPolicyPtr,
-+                                 con, sub->owner)) != HTTP_OK)
-+  {
-+    send_http_error(con, status);
-+    return;
-+  }
-+
-+ /*
-+  * Copy the subscription attributes to the response using the
-+  * requested-attributes attribute that may be provided by the client.
-+  */
-+
-+  ra = create_requested_array(con->request);
-+
-+  copy_subscription_attrs(con, sub, ra);
-+
-+  cupsArrayDelete(ra);
-+
-+  con->response->request.status.status_code = IPP_OK;
-+}
-+
-+
-+/*
-+ * 'get_subscriptions()' - Get subscriptions.
-+ */
-+
-+static void
-+get_subscriptions(cupsd_client_t  *con,	/* I - Client connection */
-+                  ipp_attribute_t *uri)	/* I - Printer/job URI */
-+{
-+  http_status_t		status;		/* Policy status */
-+  int			count;		/* Number of subscriptions */
-+  int			limit;		/* Limit */
-+  cupsd_subscription_t	*sub;		/* Subscription */
-+  cups_array_t		*ra;		/* Requested attributes array */
-+  ipp_attribute_t	*attr;		/* Attribute */
-+  cups_ptype_t		dtype;		/* Destination type (printer or class) */
-+  char			method[HTTP_MAX_URI],
-+					/* Method portion of URI */
-+			username[HTTP_MAX_URI],
-+					/* Username portion of URI */
-+			host[HTTP_MAX_URI],
-+					/* Host portion of URI */
-+			resource[HTTP_MAX_URI];
-+					/* Resource portion of URI */
-+  int			port;		/* Port portion of URI */
-+  cupsd_job_t		*job;		/* Job pointer */
-+  cupsd_printer_t	*printer;	/* Printer */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-+                  "get_subscriptions(con=%p[%d], uri=%s)",
-+                  con, con->http.fd, uri->values[0].string.text);
-+
-+ /*
-+  * Is the destination valid?
-+  */
-+
-+  httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
-+                  sizeof(method), username, sizeof(username), host,
-+		  sizeof(host), &port, resource, sizeof(resource));
-+
-+  if (!strcmp(resource, "/") ||
-+      (!strncmp(resource, "/jobs", 5) && strlen(resource) <= 6) ||
-+      (!strncmp(resource, "/printers", 9) && strlen(resource) <= 10) ||
-+      (!strncmp(resource, "/classes", 8) && strlen(resource) <= 9))
-+  {
-+    printer = NULL;
-+    job     = NULL;
-+  }
-+  else if (!strncmp(resource, "/jobs/", 6) && resource[6])
-+  {
-+    printer = NULL;
-+    job     = cupsdFindJob(atoi(resource + 6));
-+
-+    if (!job)
-+    {
-+      send_ipp_status(con, IPP_NOT_FOUND, _("Job #%s does not exist!"),
-+                      resource + 6);
-+      return;
-+    }
-+  }
-+  else if (!cupsdValidateDest(host, resource, &dtype, &printer))
-+  {
-+   /*
-+    * Bad URI...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_FOUND,
-+                    _("The printer or class was not found."));
-+    return;
-+  }
-+  else if ((attr = ippFindAttribute(con->request, "notify-job-id",
-+                                    IPP_TAG_INTEGER)) != NULL)
-+  {
-+    job = cupsdFindJob(attr->values[0].integer);
-+
-+    if (!job)
-+    {
-+      send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"),
-+                      attr->values[0].integer);
-+      return;
-+    }
-+  }
-+  else
-+    job = NULL;
-+
-+ /*
-+  * Check policy...
-+  */
-+
-+  if ((status = cupsdCheckPolicy(printer ? printer->op_policy_ptr :
-+                                           DefaultPolicyPtr,
-+                                 con, NULL)) != HTTP_OK)
-+  {
-+    send_http_error(con, status);
-+    return;
-+  }
-+
-+ /*
-+  * Copy the subscription attributes to the response using the
-+  * requested-attributes attribute that may be provided by the client.
-+  */
-+
-+  ra = create_requested_array(con->request);
-+
-+  if ((attr = ippFindAttribute(con->request, "limit",
-+                               IPP_TAG_INTEGER)) != NULL)
-+    limit = attr->values[0].integer;
-+  else
-+    limit = 0;
-+
-+ /*
-+  * See if we only want to see subscriptions for a specific user...
-+  */
-+
-+  if ((attr = ippFindAttribute(con->request, "my-subscriptions",
-+                               IPP_TAG_BOOLEAN)) != NULL &&
-+      attr->values[0].boolean)
-+    strlcpy(username, get_username(con), sizeof(username));
-+  else
-+    username[0] = '\0';
-+
-+  for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions), count = 0;
-+       sub;
-+       sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
-+    if ((!printer || sub->dest == printer) && (!job || sub->job == job) &&
-+        (!username[0] || !strcasecmp(username, sub->owner)))
-+    {
-+      ippAddSeparator(con->response);
-+      copy_subscription_attrs(con, sub, ra);
-+
-+      count ++;
-+      if (limit && count >= limit)
-+        break;
-+    }
-+
-+  cupsArrayDelete(ra);
-+
-+  if (count)
-+    con->response->request.status.status_code = IPP_OK;
-+  else
-+    send_ipp_status(con, IPP_NOT_FOUND, _("No subscriptions found."));
-+}
-+
-+
-+/*
-+ * 'get_username()' - Get the username associated with a request.
-+ */
-+
-+static const char *			/* O - Username */
-+get_username(cupsd_client_t *con)	/* I - Connection */
-+{
-+  ipp_attribute_t	*attr;		/* Attribute */
-+
-+
-+  if (con->username[0])
-+    return (con->username);
-+  else if ((attr = ippFindAttribute(con->request, "requesting-user-name",
-+                                    IPP_TAG_NAME)) != NULL)
-+    return (attr->values[0].string.text);
-+  else
-+    return ("anonymous");
-+}
-+
-+
-+/*
-+ * 'hold_job()' - Hold a print job.
-+ */
-+
-+static void
-+hold_job(cupsd_client_t  *con,		/* I - Client connection */
-+         ipp_attribute_t *uri)		/* I - Job or Printer URI */
-+{
-+  ipp_attribute_t *attr,		/* Current job-hold-until */
-+		*newattr;		/* New job-hold-until */
-+  int		jobid;			/* Job ID */
-+  char		method[HTTP_MAX_URI],	/* Method portion of URI */
-+		username[HTTP_MAX_URI],	/* Username portion of URI */
-+		host[HTTP_MAX_URI],	/* Host portion of URI */
-+		resource[HTTP_MAX_URI];	/* Resource portion of URI */
-+  int		port;			/* Port portion of URI */
-+  cupsd_job_t	*job;			/* Job information */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "hold_job(%p[%d], %s)", con, con->http.fd,
-+                  uri->values[0].string.text);
-+
-+ /*
-+  * See if we have a job URI or a printer URI...
-+  */
-+
-+  if (!strcmp(uri->name, "printer-uri"))
-+  {
-+   /*
-+    * Got a printer URI; see if we also have a job-id attribute...
-+    */
-+
-+    if ((attr = ippFindAttribute(con->request, "job-id",
-+                                 IPP_TAG_INTEGER)) == NULL)
-+    {
-+      send_ipp_status(con, IPP_BAD_REQUEST,
-+                      _("Got a printer-uri attribute but no job-id!"));
-+      return;
-+    }
-+
-+    jobid = attr->values[0].integer;
-+  }
-+  else
-+  {
-+   /*
-+    * Got a job URI; parse it to get the job ID...
-+    */
-+
-+    httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
-+                    sizeof(method), username, sizeof(username), host,
-+		    sizeof(host), &port, resource, sizeof(resource));
-+
-+    if (strncmp(resource, "/jobs/", 6))
-+    {
-+     /*
-+      * Not a valid URI!
-+      */
-+
-+      send_ipp_status(con, IPP_BAD_REQUEST,
-+                      _("Bad job-uri attribute \"%s\"!"),
-+                      uri->values[0].string.text);
-+      return;
-+    }
-+
-+    jobid = atoi(resource + 6);
-+  }
-+
-+ /*
-+  * See if the job exists...
-+  */
-+
-+  if ((job = cupsdFindJob(jobid)) == NULL)
-+  {
-+   /*
-+    * Nope - return a "not found" error...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), jobid);
-+    return;
-+  }
-+
-+ /*
-+  * See if the job is owned by the requesting user...
-+  */
-+
-+  if (!validate_user(job, con, job->username, username, sizeof(username)))
-+  {
-+    send_http_error(con, HTTP_UNAUTHORIZED);
-+    return;
-+  }
-+
-+ /*
-+  * Hold the job and return...
-+  */
-+
-+  cupsdHoldJob(job);
-+
-+  cupsdAddEvent(CUPSD_EVENT_JOB_STATE, job->printer, job,
-+                "Job held by user.");
-+
-+  if ((newattr = ippFindAttribute(con->request, "job-hold-until",
-+                                  IPP_TAG_KEYWORD)) == NULL)
-+    newattr = ippFindAttribute(con->request, "job-hold-until", IPP_TAG_NAME);
-+
-+  if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
-+                               IPP_TAG_KEYWORD)) == NULL)
-+    attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
-+
-+  if (attr)
-+  {
-+   /*
-+    * Free the old hold value and copy the new one over...
-+    */
-+
-+    _cupsStrFree(attr->values[0].string.text);
-+
-+    if (newattr)
-+    {
-+      attr->value_tag = newattr->value_tag;
-+      attr->values[0].string.text =
-+          _cupsStrAlloc(newattr->values[0].string.text);
-+    }
-+    else
-+    {
-+      attr->value_tag = IPP_TAG_KEYWORD;
-+      attr->values[0].string.text = _cupsStrAlloc("indefinite");
-+    }
-+
-+   /*
-+    * Hold job until specified time...
-+    */
-+
-+    cupsdSetJobHoldUntil(job, attr->values[0].string.text);
-+
-+    cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, job->printer, job,
-+                  "Job job-hold-until value changed by user.");
-+  }
-+
-+  cupsdLogMessage(CUPSD_LOG_INFO, "Job %d was held by \"%s\".", jobid,
-+                  username);
-+
-+  con->response->request.status.status_code = IPP_OK;
-+}
-+
-+
-+/*
-+ * 'move_job()' - Move a job to a new destination.
-+ */
-+
-+static void
-+move_job(cupsd_client_t  *con,		/* I - Client connection */
-+	 ipp_attribute_t *uri)		/* I - Job URI */
-+{
-+  http_status_t	status;			/* Policy status */
-+  ipp_attribute_t *attr;		/* Current attribute */
-+  int		jobid;			/* Job ID */
-+  cupsd_job_t	*job;			/* Current job */
-+  const char	*src;			/* Source printer/class */
-+  cups_ptype_t	stype,			/* Source type (printer or class) */
-+		dtype;			/* Destination type (printer or class) */
-+  char		method[HTTP_MAX_URI],	/* Method portion of URI */
-+		username[HTTP_MAX_URI],	/* Username portion of URI */
-+		host[HTTP_MAX_URI],	/* Host portion of URI */
-+		resource[HTTP_MAX_URI];	/* Resource portion of URI */
-+  int		port;			/* Port portion of URI */
-+  cupsd_printer_t *sprinter,		/* Source printer */
-+		*dprinter;		/* Destination printer */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "move_job(%p[%d], %s)", con, con->http.fd,
-+                  uri->values[0].string.text);
-+
-+ /*
-+  * Get the new printer or class...
-+  */
-+
-+  if ((attr = ippFindAttribute(con->request, "job-printer-uri",
-+                               IPP_TAG_URI)) == NULL)
-+  {
-+   /*
-+    * Need job-printer-uri...
-+    */
-+
-+    send_ipp_status(con, IPP_BAD_REQUEST,
-+                    _("job-printer-uri attribute missing!"));
-+    return;
-+  }
-+    
-+  httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[0].string.text, method,
-+                  sizeof(method), username, sizeof(username), host,
-+		  sizeof(host), &port, resource, sizeof(resource));
-+
-+  if (!cupsdValidateDest(host, resource, &dtype, &dprinter))
-+  {
-+   /*
-+    * Bad URI...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_FOUND,
-+                    _("The printer or class was not found."));
-+    return;
-+  }
-+
-+ /*
-+  * Check policy...
-+  */
-+
-+  if ((status = cupsdCheckPolicy(dprinter->op_policy_ptr, con, NULL)) != HTTP_OK)
-+  {
-+    send_http_error(con, status);
-+    return;
-+  }
-+
-+ /*
-+  * See if we have a job URI or a printer URI...
-+  */
-+
-+  httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
-+                  sizeof(method), username, sizeof(username), host,
-+		  sizeof(host), &port, resource, sizeof(resource));
-+
-+  if (!strcmp(uri->name, "printer-uri"))
-+  {
-+   /*
-+    * Got a printer URI; see if we also have a job-id attribute...
-+    */
-+
-+    if ((attr = ippFindAttribute(con->request, "job-id",
-+                                 IPP_TAG_INTEGER)) == NULL)
-+    {
-+     /*
-+      * Move all jobs...
-+      */
-+
-+      if ((src = cupsdValidateDest(host, resource, &stype, &sprinter)) == NULL)
-+      {
-+       /*
-+	* Bad URI...
-+	*/
-+
-+	send_ipp_status(con, IPP_NOT_FOUND,
-+                	_("The printer or class was not found."));
-+	return;
-+      }
-+
-+      job = NULL;
-+    }
-+    else
-+    {
-+     /*
-+      * Otherwise, just move a single job...
-+      */
-+
-+      if ((job = cupsdFindJob(attr->values[0].integer)) == NULL)
-+      {
-+       /*
-+	* Nope - return a "not found" error...
-+	*/
-+
-+	send_ipp_status(con, IPP_NOT_FOUND,
-+                	_("Job #%d does not exist!"), attr->values[0].integer);
-+	return;
-+      }
-+      else
-+      {
-+       /*
-+        * Job found, initialize source pointers...
-+	*/
-+
-+	src      = NULL;
-+	sprinter = NULL;
-+      }
-+    }
-+  }
-+  else
-+  {
-+   /*
-+    * Got a job URI; parse it to get the job ID...
-+    */
-+
-+    if (strncmp(resource, "/jobs/", 6))
-+    {
-+     /*
-+      * Not a valid URI!
-+      */
-+
-+      send_ipp_status(con, IPP_BAD_REQUEST,
-+                      _("Bad job-uri attribute \"%s\"!"),
-+                      uri->values[0].string.text);
-+      return;
-+    }
-+
-+   /*
-+    * See if the job exists...
-+    */
-+
-+    jobid = atoi(resource + 6);
-+
-+    if ((job = cupsdFindJob(jobid)) == NULL)
-+    {
-+     /*
-+      * Nope - return a "not found" error...
-+      */
-+
-+      send_ipp_status(con, IPP_NOT_FOUND,
-+                      _("Job #%d does not exist!"), jobid);
-+      return;
-+    }
-+    else
-+    {
-+     /*
-+      * Job found, initialize source pointers...
-+      */
-+
-+      src      = NULL;
-+      sprinter = NULL;
-+    }
-+  }
-+
-+ /*
-+  * Now move the job or jobs...
-+  */
-+
-+  if (job)
-+  {
-+   /*
-+    * See if the job has been completed...
-+    */
-+
-+    if (job->state_value > IPP_JOB_STOPPED)
-+    {
-+     /*
-+      * Return a "not-possible" error...
-+      */
-+
-+      send_ipp_status(con, IPP_NOT_POSSIBLE,
-+                      _("Job #%d is finished and cannot be altered!"),
-+		      job->id);
-+      return;
-+    }
-+
-+   /*
-+    * See if the job is owned by the requesting user...
-+    */
-+
-+    if (!validate_user(job, con, job->username, username, sizeof(username)))
-+    {
-+      send_http_error(con, HTTP_UNAUTHORIZED);
-+      return;
-+    }
-+
-+   /*
-+    * Move the job to a different printer or class...
-+    */
-+
-+    cupsdMoveJob(job, dprinter);
-+  }
-+  else
-+  {
-+   /*
-+    * Got the source printer, now look through the jobs...
-+    */
-+
-+    for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
-+         job;
-+	 job = (cupsd_job_t *)cupsArrayNext(Jobs))
-+    {
-+     /*
-+      * See if the job is pointing at the source printer or has not been
-+      * completed...
-+      */
-+
-+      if (strcasecmp(job->dest, src) ||
-+          job->state_value > IPP_JOB_STOPPED)
-+	continue;
-+
-+     /*
-+      * See if the job can be moved by the requesting user...
-+      */
-+
-+      if (!validate_user(job, con, job->username, username, sizeof(username)))
-+        continue;
-+
-+     /*
-+      * Move the job to a different printer or class...
-+      */
-+
-+      cupsdMoveJob(job, dprinter);
-+    }
-+  }
-+
-+ /*
-+  * Start jobs if possible...
-+  */
-+
-+  cupsdCheckJobs();
-+
-+ /*
-+  * Return with "everything is OK" status...
-+  */
-+
-+  con->response->request.status.status_code = IPP_OK;
-+}
-+
-+
-+/*
-+ * 'ppd_parse_line()' - Parse a PPD default line.
-+ */
-+
-+static int				/* O - 0 on success, -1 on failure */
-+ppd_parse_line(const char *line,	/* I - Line */
-+               char       *option,	/* O - Option name */
-+	       int        olen,		/* I - Size of option name */
-+               char       *choice,	/* O - Choice name */
-+	       int        clen)		/* I - Size of choice name */
-+{
-+ /*
-+  * Verify this is a default option line...
-+  */
-+
-+  if (strncmp(line, "*Default", 8))
-+    return (-1);
-+
-+ /*
-+  * Read the option name...
-+  */
-+
-+  for (line += 8, olen --; isalnum(*line & 255); line ++)
-+    if (olen > 0)
-+    {
-+      *option++ = *line;
-+      olen --;
-+    }
-+
-+  *option = '\0';
-+
-+ /*
-+  * Skip everything else up to the colon (:)...
-+  */
-+
-+  while (*line && *line != ':')
-+    line ++;
-+
-+  if (!*line)
-+    return (-1);
-+
-+  line ++;
-+
-+ /*
-+  * Now grab the option choice, skipping leading whitespace...
-+  */
-+
-+  while (isspace(*line & 255))
-+    line ++;
-+
-+  for (clen --; isalnum(*line & 255); line ++)
-+    if (clen > 0)
-+    {
-+      *choice++ = *line;
-+      clen --;
-+    }
-+
-+  *choice = '\0';
-+
-+ /*
-+  * Return with no errors...
-+  */
-+
-+  return (0);
-+}
-+
-+
-+/*
-+ * 'print_job()' - Print a file to a printer or class.
-+ */
-+
-+static void
-+print_job(cupsd_client_t  *con,		/* I - Client connection */
-+	  ipp_attribute_t *uri)		/* I - Printer URI */
-+{
-+  ipp_attribute_t *attr;		/* Current attribute */
-+  ipp_attribute_t *format;		/* Document-format attribute */
-+  cupsd_job_t	*job;			/* New job */
-+  char		filename[1024];		/* Job filename */
-+  mime_type_t	*filetype;		/* Type of file */
-+  char		super[MIME_MAX_SUPER],	/* Supertype of file */
-+		type[MIME_MAX_TYPE],	/* Subtype of file */
-+		mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2];
-+					/* Textual name of mime type */
-+  cupsd_printer_t *printer;		/* Printer data */
-+  struct stat	fileinfo;		/* File information */
-+  int		kbytes;			/* Size of file */
-+  int		compression;		/* Document compression */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "print_job(%p[%d], %s)", con, con->http.fd,
-+                  uri->values[0].string.text);
-+
-+ /*
-+  * Validate print file attributes, for now just document-format and
-+  * compression (CUPS only supports "none" and "gzip")...
-+  */
-+
-+  compression = CUPS_FILE_NONE;
-+
-+  if ((attr = ippFindAttribute(con->request, "compression",
-+                               IPP_TAG_KEYWORD)) != NULL)
-+  {
-+    if (strcmp(attr->values[0].string.text, "none")
-+#ifdef HAVE_LIBZ
-+        && strcmp(attr->values[0].string.text, "gzip")
-+#endif /* HAVE_LIBZ */
-+      )
-+    {
-+      send_ipp_status(con, IPP_ATTRIBUTES,
-+                      _("Unsupported compression \"%s\"!"),
-+        	      attr->values[0].string.text);
-+      ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD,
-+	           "compression", NULL, attr->values[0].string.text);
-+      return;
-+    }
-+
-+#ifdef HAVE_LIBZ
-+    if (!strcmp(attr->values[0].string.text, "gzip"))
-+      compression = CUPS_FILE_GZIP;
-+#endif /* HAVE_LIBZ */
-+  }
-+
-+ /*
-+  * Do we have a file to print?
-+  */
-+
-+  if (!con->filename)
-+  {
-+    send_ipp_status(con, IPP_BAD_REQUEST, _("No file!?!"));
-+    return;
-+  }
-+
-+ /*
-+  * Is it a format we support?
-+  */
-+
-+  if ((format = ippFindAttribute(con->request, "document-format",
-+                                 IPP_TAG_MIMETYPE)) != NULL)
-+  {
-+   /*
-+    * Grab format from client...
-+    */
-+
-+    if (sscanf(format->values[0].string.text, "%15[^/]/%31[^;]", super, type) != 2)
-+    {
-+      send_ipp_status(con, IPP_BAD_REQUEST,
-+                      _("Could not scan type \"%s\"!"),
-+		      format->values[0].string.text);
-+      return;
-+    }
-+  }
-+  else
-+  {
-+   /*
-+    * No document format attribute?  Auto-type it!
-+    */
-+
-+    strcpy(super, "application");
-+    strcpy(type, "octet-stream");
-+  }
-+
-+  if (!strcmp(super, "application") && !strcmp(type, "octet-stream"))
-+  {
-+   /*
-+    * Auto-type the file...
-+    */
-+
-+    ipp_attribute_t	*doc_name;	/* document-name attribute */
-+
-+
-+    cupsdLogMessage(CUPSD_LOG_DEBUG, "print_job: auto-typing file...");
-+
-+    doc_name = ippFindAttribute(con->request, "document-name", IPP_TAG_NAME);
-+    filetype = mimeFileType(MimeDatabase, con->filename,
-+                            doc_name ? doc_name->values[0].string.text : NULL,
-+			    &compression);
-+
-+    if (filetype)
-+    {
-+     /*
-+      * Replace the document-format attribute value with the auto-typed one.
-+      */
-+
-+      snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super,
-+               filetype->type);
-+
-+      if (format)
-+      {
-+	  _cupsStrFree(format->values[0].string.text);
-+
-+	format->values[0].string.text = _cupsStrAlloc(mimetype);
-+      }
-+      else
-+        ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE,
-+	             "document-format", NULL, mimetype);
-+    }
-+    else
-+      filetype = mimeType(MimeDatabase, super, type);
-+  }
-+  else
-+    filetype = mimeType(MimeDatabase, super, type);
-+
-+  if (!filetype)
-+  {
-+    send_ipp_status(con, IPP_DOCUMENT_FORMAT,
-+                    _("Unsupported format \'%s/%s\'!"), super, type);
-+    cupsdLogMessage(CUPSD_LOG_INFO,
-+                    "Hint: Do you have the raw file printing rules enabled?");
-+
-+    if (format)
-+      ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE,
-+                   "document-format", NULL, format->values[0].string.text);
-+
-+    return;
-+  }
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG, "print_job: request file type is %s/%s.",
-+	          filetype->super, filetype->type);
-+
-+ /*
-+  * Read any embedded job ticket info from PS files...
-+  */
-+
-+  if (!strcasecmp(filetype->super, "application") &&
-+      !strcasecmp(filetype->type, "postscript"))
-+    read_ps_job_ticket(con);
-+
-+ /*
-+  * Create the job object...
-+  */
-+
-+  if ((job = add_job(con, uri, &printer, filetype)) == NULL)
-+    return;
-+
-+ /*
-+  * Update quota data...
-+  */
-+
-+  if (stat(con->filename, &fileinfo))
-+    kbytes = 0;
-+  else
-+    kbytes = (fileinfo.st_size + 1023) / 1024;
-+
-+  cupsdUpdateQuota(printer, job->username, 0, kbytes);
-+
-+  if ((attr = ippFindAttribute(job->attrs, "job-k-octets",
-+                               IPP_TAG_INTEGER)) != NULL)
-+    attr->values[0].integer += kbytes;
-+
-+ /*
-+  * Add the job file...
-+  */
-+
-+  if (add_file(con, job, filetype, compression))
-+    return;
-+
-+  snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, job->id,
-+           job->num_files);
-+  rename(con->filename, filename);
-+  cupsdClearString(&con->filename);
-+
-+ /*
-+  * See if we need to add the ending sheet...
-+  */
-+
-+  attr = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME);
-+
-+  if (!(printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) &&
-+      attr && attr->num_values > 1)
-+  {
-+   /*
-+    * Yes...
-+    */
-+
-+    cupsdLogMessage(CUPSD_LOG_INFO, "Adding end banner page \"%s\" to job %d.",
-+                    attr->values[1].string.text, job->id);
-+
-+    kbytes = copy_banner(con, job, attr->values[1].string.text);
-+
-+    cupsdUpdateQuota(printer, job->username, 0, kbytes);
-+  }
-+
-+ /*
-+  * Log and save the job...
-+  */
-+
-+  cupsdLogMessage(CUPSD_LOG_INFO, "Job %d queued on \"%s\" by \"%s\".", job->id,
-+                  job->dest, job->username);
-+  cupsdLogMessage(CUPSD_LOG_DEBUG, "Job %d hold_until = %d", job->id,
-+                  (int)job->hold_until);
-+
-+  cupsdSaveJob(job);
-+
-+ /*
-+  * Start the job if possible...
-+  */
-+
-+  cupsdCheckJobs();
-+}
-+
-+
-+/*
-+ * 'read_ps_job_ticket()' - Reads a job ticket embedded in a PS file.
-+ *
-+ * This function only gets called when printing a single PostScript
-+ * file using the Print-Job operation.  It doesn't work for Create-Job +
-+ * Send-File, since the job attributes need to be set at job creation
-+ * time for banners to work.  The embedded PS job ticket stuff is here
-+ * only to allow the Windows printer driver for CUPS to pass in JCL
-+ * options and IPP attributes which otherwise would be lost.
-+ *
-+ * The format of a PS job ticket is simple:
-+ *
-+ *     %cupsJobTicket: attr1=value1 attr2=value2 ... attrN=valueN
-+ *
-+ *     %cupsJobTicket: attr1=value1
-+ *     %cupsJobTicket: attr2=value2
-+ *     ...
-+ *     %cupsJobTicket: attrN=valueN
-+ *
-+ * Job ticket lines must appear immediately after the first line that
-+ * specifies PostScript format (%!PS-Adobe-3.0), and CUPS will stop
-+ * looking for job ticket info when it finds a line that does not begin
-+ * with "%cupsJobTicket:".
-+ *
-+ * The maximum length of a job ticket line, including the prefix, is
-+ * 255 characters to conform with the Adobe DSC.
-+ *
-+ * Read-only attributes are rejected with a notice to the error log in
-+ * case a malicious user tries anything.  Since the job ticket is read
-+ * prior to attribute validation in print_job(), job ticket attributes
-+ * will go through the same validation as IPP attributes...
-+ */
-+
-+static void
-+read_ps_job_ticket(cupsd_client_t *con)	/* I - Client connection */
-+{
-+  cups_file_t		*fp;		/* File to read from */
-+  char			line[256];	/* Line data */
-+  int			num_options;	/* Number of options */
-+  cups_option_t		*options;	/* Options */
-+  ipp_t			*ticket;	/* New attributes */
-+  ipp_attribute_t	*attr,		/* Current attribute */
-+			*attr2,		/* Job attribute */
-+			*prev2;		/* Previous job attribute */
-+
-+
-+ /*
-+  * First open the print file...
-+  */
-+
-+  if ((fp = cupsFileOpen(con->filename, "rb")) == NULL)
-+  {
-+    cupsdLogMessage(CUPSD_LOG_ERROR,
-+                    "read_ps_job_ticket: Unable to open PostScript print file "
-+		    "- %s",
-+                    strerror(errno));
-+    return;
-+  }
-+
-+ /*
-+  * Skip the first line...
-+  */
-+
-+  if (cupsFileGets(fp, line, sizeof(line)) == NULL)
-+  {
-+    cupsdLogMessage(CUPSD_LOG_ERROR,
-+                    "read_ps_job_ticket: Unable to read from PostScript print "
-+		    "file - %s",
-+                    strerror(errno));
-+    cupsFileClose(fp);
-+    return;
-+  }
-+
-+  if (strncmp(line, "%!PS-Adobe-", 11))
-+  {
-+   /*
-+    * Not a DSC-compliant file, so no job ticket info will be available...
-+    */
-+
-+    cupsFileClose(fp);
-+    return;
-+  }
-+
-+ /*
-+  * Read job ticket info from the file...
-+  */
-+
-+  num_options = 0;
-+  options     = NULL;
-+
-+  while (cupsFileGets(fp, line, sizeof(line)))
-+  {
-+   /*
-+    * Stop at the first non-ticket line...
-+    */
-+
-+    if (strncmp(line, "%cupsJobTicket:", 15))
-+      break;
-+
-+   /*
-+    * Add the options to the option array...
-+    */
-+
-+    num_options = cupsParseOptions(line + 15, num_options, &options);
-+  }
-+
-+ /*
-+  * Done with the file; see if we have any options...
-+  */
-+
-+  cupsFileClose(fp);
-+
-+  if (num_options == 0)
-+    return;
-+
-+ /*
-+  * OK, convert the options to an attribute list, and apply them to
-+  * the request...
-+  */
-+
-+  ticket = ippNew();
-+  cupsEncodeOptions(ticket, num_options, options);
-+
-+ /*
-+  * See what the user wants to change.
-+  */
-+
-+  for (attr = ticket->attrs; attr; attr = attr->next)
-+  {
-+    if (attr->group_tag != IPP_TAG_JOB || !attr->name)
-+      continue;
-+
-+    if (!strcmp(attr->name, "job-originating-host-name") ||
-+        !strcmp(attr->name, "job-originating-user-name") ||
-+	!strcmp(attr->name, "job-media-sheets-completed") ||
-+	!strcmp(attr->name, "job-k-octets") ||
-+	!strcmp(attr->name, "job-id") ||
-+	!strncmp(attr->name, "job-state", 9) ||
-+	!strncmp(attr->name, "time-at-", 8))
-+      continue; /* Read-only attrs */
-+
-+    if ((attr2 = ippFindAttribute(con->request, attr->name,
-+                                  IPP_TAG_ZERO)) != NULL)
-+    {
-+     /*
-+      * Some other value; first free the old value...
-+      */
-+
-+      if (con->request->attrs == attr2)
-+      {
-+	con->request->attrs = attr2->next;
-+	prev2               = NULL;
-+      }
-+      else
-+      {
-+	for (prev2 = con->request->attrs; prev2; prev2 = prev2->next)
-+	  if (prev2->next == attr2)
-+	  {
-+	    prev2->next = attr2->next;
-+	    break;
-+	  }
-+      }
-+
-+      if (con->request->last == attr2)
-+        con->request->last = prev2;
-+
-+      _ippFreeAttr(attr2);
-+    }
-+
-+   /*
-+    * Add new option by copying it...
-+    */
-+
-+    copy_attribute(con->request, attr, 0);
-+  }
-+
-+ /*
-+  * Then free the attribute list and option array...
-+  */
-+
-+  ippDelete(ticket);
-+  cupsFreeOptions(num_options, options);
-+}
-+
-+
-+/*
-+ * 'reject_jobs()' - Reject print jobs to a printer.
-+ */
-+
-+static void
-+reject_jobs(cupsd_client_t  *con,	/* I - Client connection */
-+            ipp_attribute_t *uri)	/* I - Printer or class URI */
-+{
-+  http_status_t	status;			/* Policy status */
-+  cups_ptype_t	dtype;			/* Destination type (printer or class) */
-+  char		method[HTTP_MAX_URI],	/* Method portion of URI */
-+		username[HTTP_MAX_URI],	/* Username portion of URI */
-+		host[HTTP_MAX_URI],	/* Host portion of URI */
-+		resource[HTTP_MAX_URI];	/* Resource portion of URI */
-+  int		port;			/* Port portion of URI */
-+  const char	*name;			/* Printer name */
-+  cupsd_printer_t *printer;		/* Printer data */
-+  ipp_attribute_t *attr;		/* printer-state-message text */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "reject_jobs(%p[%d], %s)", con,
-+                  con->http.fd, uri->values[0].string.text);
-+
-+ /*
-+  * Is the destination valid?
-+  */
-+
-+  httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
-+                  sizeof(method), username, sizeof(username), host,
-+		  sizeof(host), &port, resource, sizeof(resource));
-+
-+  if ((name = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL)
-+  {
-+   /*
-+    * Bad URI...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_FOUND,
-+                    _("The printer or class was not found."));
-+    return;
-+  }
-+
-+ /*
-+  * Check policy...
-+  */
-+
-+  if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
-+  {
-+    send_http_error(con, status);
-+    return;
-+  }
-+
-+ /*
-+  * Reject jobs sent to the printer...
-+  */
-+
-+  printer->accepting = 0;
-+
-+  if ((attr = ippFindAttribute(con->request, "printer-state-message",
-+                               IPP_TAG_TEXT)) == NULL)
-+    strcpy(printer->state_message, "Rejecting Jobs");
-+  else
-+    strlcpy(printer->state_message, attr->values[0].string.text,
-+            sizeof(printer->state_message));
-+
-+  cupsdAddPrinterHistory(printer);
-+
-+  if (dtype & CUPS_PRINTER_CLASS)
-+  {
-+    cupsdSaveAllClasses();
-+
-+    cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" rejecting jobs (\"%s\").",
-+                    name, get_username(con));
-+  }
-+  else
-+  {
-+    cupsdSaveAllPrinters();
-+
-+    cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" rejecting jobs (\"%s\").",
-+                    name, get_username(con));
-+  }
-+
-+ /*
-+  * Everything was ok, so return OK status...
-+  */
-+
-+  con->response->request.status.status_code = IPP_OK;
-+}
-+
-+
-+/*
-+ * 'release_job()' - Release a held print job.
-+ */
-+
-+static void
-+release_job(cupsd_client_t  *con,	/* I - Client connection */
-+            ipp_attribute_t *uri)	/* I - Job or Printer URI */
-+{
-+  ipp_attribute_t *attr;		/* Current attribute */
-+  int		jobid;			/* Job ID */
-+  char		method[HTTP_MAX_URI],	/* Method portion of URI */
-+		username[HTTP_MAX_URI],	/* Username portion of URI */
-+		host[HTTP_MAX_URI],	/* Host portion of URI */
-+		resource[HTTP_MAX_URI];	/* Resource portion of URI */
-+  int		port;			/* Port portion of URI */
-+  cupsd_job_t	*job;			/* Job information */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "release_job(%p[%d], %s)", con,
-+                  con->http.fd, uri->values[0].string.text);
-+
-+ /*
-+  * See if we have a job URI or a printer URI...
-+  */
-+
-+  if (!strcmp(uri->name, "printer-uri"))
-+  {
-+   /*
-+    * Got a printer URI; see if we also have a job-id attribute...
-+    */
-+
-+    if ((attr = ippFindAttribute(con->request, "job-id",
-+                                 IPP_TAG_INTEGER)) == NULL)
-+    {
-+      send_ipp_status(con, IPP_BAD_REQUEST,
-+                      _("Got a printer-uri attribute but no job-id!"));
-+      return;
-+    }
-+
-+    jobid = attr->values[0].integer;
-+  }
-+  else
-+  {
-+   /*
-+    * Got a job URI; parse it to get the job ID...
-+    */
-+
-+    httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
-+                    sizeof(method), username, sizeof(username), host,
-+		    sizeof(host), &port, resource, sizeof(resource));
-+
-+    if (strncmp(resource, "/jobs/", 6))
-+    {
-+     /*
-+      * Not a valid URI!
-+      */
-+
-+      send_ipp_status(con, IPP_BAD_REQUEST,
-+                      _("Bad job-uri attribute \"%s\"!"),
-+                      uri->values[0].string.text);
-+      return;
-+    }
-+
-+    jobid = atoi(resource + 6);
-+  }
-+
-+ /*
-+  * See if the job exists...
-+  */
-+
-+  if ((job = cupsdFindJob(jobid)) == NULL)
-+  {
-+   /*
-+    * Nope - return a "not found" error...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), jobid);
-+    return;
-+  }
-+
-+ /*
-+  * See if job is "held"...
-+  */
-+
-+  if (job->state_value != IPP_JOB_HELD)
-+  {
-+   /*
-+    * Nope - return a "not possible" error...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_POSSIBLE, _("Job #%d is not held!"), jobid);
-+    return;
-+  }
-+
-+ /*
-+  * See if the job is owned by the requesting user...
-+  */
-+
-+  if (!validate_user(job, con, job->username, username, sizeof(username)))
-+  {
-+    send_http_error(con, HTTP_UNAUTHORIZED);
-+    return;
-+  }
-+
-+ /*
-+  * Reset the job-hold-until value to "no-hold"...
-+  */
-+
-+  if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
-+                               IPP_TAG_KEYWORD)) == NULL)
-+    attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
-+
-+  if (attr)
-+  {
-+    _cupsStrFree(attr->values[0].string.text);
-+
-+    attr->value_tag = IPP_TAG_KEYWORD;
-+    attr->values[0].string.text = _cupsStrAlloc("no-hold");
-+
-+    cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, job->printer, job,
-+                  "Job job-hold-until value changed by user.");
-+  }
-+
-+ /*
-+  * Release the job and return...
-+  */
-+
-+  cupsdReleaseJob(job);
-+
-+  cupsdAddEvent(CUPSD_EVENT_JOB_STATE, job->printer, job,
-+                "Job released by user.");
-+
-+  cupsdLogMessage(CUPSD_LOG_INFO, "Job %d was released by \"%s\".", jobid,
-+                  username);
-+
-+  con->response->request.status.status_code = IPP_OK;
-+}
-+
-+
-+/*
-+ * 'renew_subscription()' - Renew an existing subscription...
-+ */
-+
-+static void
-+renew_subscription(
-+    cupsd_client_t *con,		/* I - Client connection */
-+    int            sub_id)		/* I - Subscription ID */
-+{
-+  http_status_t		status;		/* Policy status */
-+  cupsd_subscription_t	*sub;		/* Subscription */
-+  ipp_attribute_t	*lease;		/* notify-lease-duration */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-+                  "renew_subscription(con=%p[%d], sub_id=%d)",
-+                  con, con->http.fd, sub_id);
-+
-+ /*
-+  * Is the subscription ID valid?
-+  */
-+
-+  if ((sub = cupsdFindSubscription(sub_id)) == NULL)
-+  {
-+   /*
-+    * Bad subscription ID...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_FOUND,
-+                    _("notify-subscription-id %d no good!"), sub_id);
-+    return;
-+  }
-+
-+  if (sub->job)
-+  {
-+   /*
-+    * Job subscriptions cannot be renewed...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_POSSIBLE,
-+                    _("Job subscriptions cannot be renewed!"));
-+    return;
-+  }
-+
-+ /*
-+  * Check policy...
-+  */
-+
-+  if ((status = cupsdCheckPolicy(sub->dest ? sub->dest->op_policy_ptr :
-+                                             DefaultPolicyPtr,
-+                                 con, sub->owner)) != HTTP_OK)
-+  {
-+    send_http_error(con, status);
-+    return;
-+  }
-+
-+ /*
-+  * Renew the subscription...
-+  */
-+
-+  lease = ippFindAttribute(con->request, "notify-lease-duration",
-+                           IPP_TAG_INTEGER);
-+
-+  sub->lease = lease ? lease->values[0].integer : DefaultLeaseDuration;
-+
-+  if (MaxLeaseDuration && (sub->lease == 0 || sub->lease > MaxLeaseDuration))
-+  {
-+    cupsdLogMessage(CUPSD_LOG_INFO,
-+                    "renew_subscription: Limiting notify-lease-duration to "
-+		    "%d seconds.",
-+		    MaxLeaseDuration);
-+    sub->lease = MaxLeaseDuration;
-+  }
-+
-+  sub->expire = sub->lease ? time(NULL) + sub->lease : 0;
-+
-+  cupsdSaveAllSubscriptions();
-+
-+  con->response->request.status.status_code = IPP_OK;
-+}
-+
-+
-+/*
-+ * 'restart_job()' - Restart an old print job.
-+ */
-+
-+static void
-+restart_job(cupsd_client_t  *con,	/* I - Client connection */
-+            ipp_attribute_t *uri)	/* I - Job or Printer URI */
-+{
-+  ipp_attribute_t *attr;		/* Current attribute */
-+  int		jobid;			/* Job ID */
-+  char		method[HTTP_MAX_URI],	/* Method portion of URI */
-+		username[HTTP_MAX_URI],	/* Username portion of URI */
-+		host[HTTP_MAX_URI],	/* Host portion of URI */
-+		resource[HTTP_MAX_URI];	/* Resource portion of URI */
-+  int		port;			/* Port portion of URI */
-+  cupsd_job_t	*job;			/* Job information */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "restart_job(%p[%d], %s)", con,
-+                  con->http.fd, uri->values[0].string.text);
-+
-+ /*
-+  * See if we have a job URI or a printer URI...
-+  */
-+
-+  if (!strcmp(uri->name, "printer-uri"))
-+  {
-+   /*
-+    * Got a printer URI; see if we also have a job-id attribute...
-+    */
-+
-+    if ((attr = ippFindAttribute(con->request, "job-id",
-+                                 IPP_TAG_INTEGER)) == NULL)
-+    {
-+      send_ipp_status(con, IPP_BAD_REQUEST,
-+                      _("Got a printer-uri attribute but no job-id!"));
-+      return;
-+    }
-+
-+    jobid = attr->values[0].integer;
-+  }
-+  else
-+  {
-+   /*
-+    * Got a job URI; parse it to get the job ID...
-+    */
-+
-+    httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
-+                    sizeof(method), username, sizeof(username), host,
-+		    sizeof(host), &port, resource, sizeof(resource));
-+
-+    if (strncmp(resource, "/jobs/", 6))
-+    {
-+     /*
-+      * Not a valid URI!
-+      */
-+
-+      send_ipp_status(con, IPP_BAD_REQUEST,
-+                      _("Bad job-uri attribute \"%s\"!"),
-+                      uri->values[0].string.text);
-+      return;
-+    }
-+
-+    jobid = atoi(resource + 6);
-+  }
-+
-+ /*
-+  * See if the job exists...
-+  */
-+
-+  if ((job = cupsdFindJob(jobid)) == NULL)
-+  {
-+   /*
-+    * Nope - return a "not found" error...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), jobid);
-+    return;
-+  }
-+
-+ /*
-+  * See if job is in any of the "completed" states...
-+  */
-+
-+  if (job->state_value <= IPP_JOB_PROCESSING)
-+  {
-+   /*
-+    * Nope - return a "not possible" error...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_POSSIBLE, _("Job #%d is not complete!"),
-+                    jobid);
-+    return;
-+  }
-+
-+ /*
-+  * See if we have retained the job files...
-+  */
-+
-+  cupsdLoadJob(job);
-+
-+  if (!job->attrs || job->num_files == 0)
-+  {
-+   /*
-+    * Nope - return a "not possible" error...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_POSSIBLE,
-+                    _("Job #%d cannot be restarted - no files!"), jobid);
-+    return;
-+  }
-+
-+ /*
-+  * See if the job is owned by the requesting user...
-+  */
-+
-+  if (!validate_user(job, con, job->username, username, sizeof(username)))
-+  {
-+    send_http_error(con, HTTP_UNAUTHORIZED);
-+    return;
-+  }
-+
-+ /*
-+  * Restart the job and return...
-+  */
-+
-+  cupsdRestartJob(job);
-+
-+  cupsdLogMessage(CUPSD_LOG_INFO, "Job %d was restarted by \"%s\".", jobid,
-+                  username);
-+
-+  con->response->request.status.status_code = IPP_OK;
-+}
-+
-+
-+/*
-+ * 'save_auth_info()' - Save authentication information for a job.
-+ */
-+
-+static void
-+save_auth_info(cupsd_client_t *con,	/* I - Client connection */
-+               cupsd_job_t    *job)	/* I - Job */
-+{
-+  int		i;			/* Looping var */
-+  char		filename[1024];		/* Job authentication filename */
-+  cups_file_t	*fp;			/* Job authentication file */
-+  char		line[1024];		/* Line for file */
-+
-+
-+ /*
-+  * This function saves the in-memory authentication information for
-+  * a job so that it can be used to authenticate with a remote host.
-+  * The information is stored in a file that is readable only by the
-+  * root user.  The username and password are Base-64 encoded, each
-+  * on a separate line, followed by random number (up to 1024) of
-+  * newlines to limit the amount of information that is exposed.
-+  *
-+  * Because of the potential for exposing of authentication information,
-+  * this functionality is only enabled when running cupsd as root.
-+  *
-+  * This caching only works for the Basic and BasicDigest authentication
-+  * types.  Digest authentication cannot be cached this way, and in
-+  * the future Kerberos authentication may make all of this obsolete.
-+  *
-+  * Authentication information is saved whenever an authenticated
-+  * Print-Job, Create-Job, or CUPS-Authenticate-Job operation is
-+  * performed.
-+  *
-+  * This information is deleted after a job is completed or canceled,
-+  * so reprints may require subsequent re-authentication.
-+  */
-+
-+  if (RunUser)
-+    return;
-+
-+ /*
-+  * Create the authentication file and change permissions...
-+  */
-+
-+  snprintf(filename, sizeof(filename), "%s/a%05d", RequestRoot, job->id);
-+  if ((fp = cupsFileOpen(filename, "w")) == NULL)
-+  {
-+    cupsdLogMessage(CUPSD_LOG_ERROR,
-+                    "Unable to save authentication info to \"%s\" - %s",
-+                    filename, strerror(errno));
-+    return;
-+  }
-+
-+  fchown(cupsFileNumber(fp), 0, 0);
-+  fchmod(cupsFileNumber(fp), 0400);
-+
-+ /*
-+  * Write the authenticated username...
-+  */
-+
-+  httpEncode64_2(line, sizeof(line), con->username, strlen(con->username));
-+  cupsFilePrintf(fp, "%s\n", line);
-+
-+ /*
-+  * Write the authenticated password...
-+  */
-+
-+  httpEncode64_2(line, sizeof(line), con->password, strlen(con->password));
-+  cupsFilePrintf(fp, "%s\n", line);
-+
-+ /*
-+  * Write a random number of newlines to the end of the file...
-+  */
-+
-+  for (i = (rand() % 1024); i >= 0; i --)
-+    cupsFilePutChar(fp, '\n');
-+
-+ /*
-+  * Close the file and return...
-+  */
-+
-+  cupsFileClose(fp);
-+}
-+
-+
-+/*
-+ * 'send_document()' - Send a file to a printer or class.
-+ */
-+
-+static void
-+send_document(cupsd_client_t  *con,	/* I - Client connection */
-+	      ipp_attribute_t *uri)	/* I - Printer URI */
-+{
-+  ipp_attribute_t	*attr;		/* Current attribute */
-+  ipp_attribute_t	*format;	/* Document-format attribute */
-+  int			jobid;		/* Job ID number */
-+  cupsd_job_t		*job;		/* Current job */
-+  char			job_uri[HTTP_MAX_URI],
-+					/* Job URI */
-+			method[HTTP_MAX_URI],
-+					/* Method portion of URI */
-+			username[HTTP_MAX_URI],
-+					/* Username portion of URI */
-+			host[HTTP_MAX_URI],
-+					/* Host portion of URI */
-+			resource[HTTP_MAX_URI];
-+					/* Resource portion of URI */
-+  int			port;		/* Port portion of URI */
-+  mime_type_t		*filetype;	/* Type of file */
-+  char			super[MIME_MAX_SUPER],
-+					/* Supertype of file */
-+			type[MIME_MAX_TYPE],
-+					/* Subtype of file */
-+			mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2];
-+					/* Textual name of mime type */
-+  char			filename[1024];	/* Job filename */
-+  cupsd_printer_t	*printer;	/* Current printer */
-+  struct stat		fileinfo;	/* File information */
-+  int			kbytes;		/* Size of file */
-+  int			compression;	/* Type of compression */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_document(%p[%d], %s)", con,
-+                  con->http.fd, uri->values[0].string.text);
-+
-+ /*
-+  * See if we have a job URI or a printer URI...
-+  */
-+
-+  if (!strcmp(uri->name, "printer-uri"))
-+  {
-+   /*
-+    * Got a printer URI; see if we also have a job-id attribute...
-+    */
-+
-+    if ((attr = ippFindAttribute(con->request, "job-id",
-+                                 IPP_TAG_INTEGER)) == NULL)
-+    {
-+      send_ipp_status(con, IPP_BAD_REQUEST,
-+                      _("Got a printer-uri attribute but no job-id!"));
-+      return;
-+    }
-+
-+    jobid = attr->values[0].integer;
-+  }
-+  else
-+  {
-+   /*
-+    * Got a job URI; parse it to get the job ID...
-+    */
-+
-+    httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
-+                    sizeof(method), username, sizeof(username), host,
-+		    sizeof(host), &port, resource, sizeof(resource));
-+
-+    if (strncmp(resource, "/jobs/", 6))
-+    {
-+     /*
-+      * Not a valid URI!
-+      */
-+
-+      send_ipp_status(con, IPP_BAD_REQUEST,
-+                      _("Bad job-uri attribute \"%s\"!"),
-+                      uri->values[0].string.text);
-+      return;
-+    }
-+
-+    jobid = atoi(resource + 6);
-+  }
-+
-+ /*
-+  * See if the job exists...
-+  */
-+
-+  if ((job = cupsdFindJob(jobid)) == NULL)
-+  {
-+   /*
-+    * Nope - return a "not found" error...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), jobid);
-+    return;
-+  }
-+
-+  printer = cupsdFindDest(job->dest);
-+
-+ /*
-+  * See if the job is owned by the requesting user...
-+  */
-+
-+  if (!validate_user(job, con, job->username, username, sizeof(username)))
-+  {
-+    send_http_error(con, HTTP_UNAUTHORIZED);
-+    return;
-+  }
-+
-+ /*
-+  * OK, see if the client is sending the document compressed - CUPS
-+  * only supports "none" and "gzip".
-+  */
-+
-+  compression = CUPS_FILE_NONE;
-+
-+  if ((attr = ippFindAttribute(con->request, "compression",
-+                               IPP_TAG_KEYWORD)) != NULL)
-+  {
-+    if (strcmp(attr->values[0].string.text, "none")
-+#ifdef HAVE_LIBZ
-+        && strcmp(attr->values[0].string.text, "gzip")
-+#endif /* HAVE_LIBZ */
-+      )
-+    {
-+      send_ipp_status(con, IPP_ATTRIBUTES, _("Unsupported compression \"%s\"!"),
-+        	      attr->values[0].string.text);
-+      ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD,
-+	           "compression", NULL, attr->values[0].string.text);
-+      return;
-+    }
-+
-+#ifdef HAVE_LIBZ
-+    if (!strcmp(attr->values[0].string.text, "gzip"))
-+      compression = CUPS_FILE_GZIP;
-+#endif /* HAVE_LIBZ */
-+  }
-+
-+ /*
-+  * Do we have a file to print?
-+  */
-+
-+  if (!con->filename)
-+  {
-+    send_ipp_status(con, IPP_BAD_REQUEST, _("No file!?!"));
-+    return;
-+  }
-+
-+ /*
-+  * Is it a format we support?
-+  */
-+
-+  if ((format = ippFindAttribute(con->request, "document-format",
-+                                 IPP_TAG_MIMETYPE)) != NULL)
-+  {
-+   /*
-+    * Grab format from client...
-+    */
-+
-+    if (sscanf(format->values[0].string.text, "%15[^/]/%31[^;]", super, type) != 2)
-+    {
-+      send_ipp_status(con, IPP_BAD_REQUEST, _("Bad document-format \"%s\"!"),
-+	              format->values[0].string.text);
-+      return;
-+    }
-+  }
-+  else
-+  {
-+   /*
-+    * No document format attribute?  Auto-type it!
-+    */
-+
-+    strcpy(super, "application");
-+    strcpy(type, "octet-stream");
-+  }
-+
-+  if (!strcmp(super, "application") && !strcmp(type, "octet-stream"))
-+  {
-+   /*
-+    * Auto-type the file...
-+    */
-+
-+    ipp_attribute_t	*doc_name;	/* document-name attribute */
-+
-+
-+    cupsdLogMessage(CUPSD_LOG_DEBUG, "send_document: auto-typing file...");
-+
-+    doc_name = ippFindAttribute(con->request, "document-name", IPP_TAG_NAME);
-+    filetype = mimeFileType(MimeDatabase, con->filename,
-+                            doc_name ? doc_name->values[0].string.text : NULL,
-+			    &compression);
-+
-+    if (filetype)
-+    {
-+     /*
-+      * Replace the document-format attribute value with the auto-typed one.
-+      */
-+
-+      snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super,
-+               filetype->type);
-+
-+      if (format)
-+      {
-+	_cupsStrFree(format->values[0].string.text);
-+	format->values[0].string.text = _cupsStrAlloc(mimetype);
-+      }
-+      else
-+        ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE,
-+	             "document-format", NULL, mimetype);
-+    }
-+    else
-+      filetype = mimeType(MimeDatabase, super, type);
-+  }
-+  else
-+    filetype = mimeType(MimeDatabase, super, type);
-+
-+  if (!filetype)
-+  {
-+    send_ipp_status(con, IPP_DOCUMENT_FORMAT,
-+                    _("Unsupported format \'%s/%s\'!"), super, type);
-+    cupsdLogMessage(CUPSD_LOG_INFO,
-+                    "Hint: Do you have the raw file printing rules enabled?");
-+
-+    if (format)
-+      ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE,
-+                   "document-format", NULL, format->values[0].string.text);
-+
-+    return;
-+  }
-+
-+  if (printer->filetypes && !cupsArrayFind(printer->filetypes, filetype))
-+  {
-+    snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super,
-+             filetype->type);
-+
-+    send_ipp_status(con, IPP_DOCUMENT_FORMAT,
-+                    _("Unsupported format \'%s\'!"), mimetype);
-+
-+    ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE,
-+                 "document-format", NULL, mimetype);
-+
-+    return;
-+  }
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG,
-+                  "send_document: request file type is %s/%s.",
-+	          filetype->super, filetype->type);
-+
-+ /*
-+  * Add the file to the job...
-+  */
-+
-+  cupsdLoadJob(job);
-+
-+  if (add_file(con, job, filetype, compression))
-+    return;
-+
-+  if (stat(con->filename, &fileinfo))
-+    kbytes = 0;
-+  else
-+    kbytes = (fileinfo.st_size + 1023) / 1024;
-+
-+  cupsdUpdateQuota(printer, job->username, 0, kbytes);
-+
-+  if ((attr = ippFindAttribute(job->attrs, "job-k-octets",
-+                               IPP_TAG_INTEGER)) != NULL)
-+    attr->values[0].integer += kbytes;
-+
-+  snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, job->id,
-+           job->num_files);
-+  rename(con->filename, filename);
-+
-+  cupsdClearString(&con->filename);
-+
-+  cupsdLogMessage(CUPSD_LOG_INFO,
-+                  "File of type %s/%s queued in job #%d by \"%s\".",
-+                  filetype->super, filetype->type, job->id, job->username);
-+
-+ /*
-+  * Start the job if this is the last document...
-+  */
-+
-+  if ((attr = ippFindAttribute(con->request, "last-document",
-+                               IPP_TAG_BOOLEAN)) != NULL &&
-+      attr->values[0].boolean)
-+  {
-+   /*
-+    * See if we need to add the ending sheet...
-+    */
-+
-+    if (printer &&
-+        !(printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) &&
-+        (attr = ippFindAttribute(job->attrs, "job-sheets",
-+	                         IPP_TAG_ZERO)) != NULL &&
-+        attr->num_values > 1)
-+    {
-+     /*
-+      * Yes...
-+      */
-+
-+      cupsdLogMessage(CUPSD_LOG_INFO,
-+                      "Adding end banner page \"%s\" to job %d.",
-+        	      attr->values[1].string.text, job->id);
-+
-+      kbytes = copy_banner(con, job, attr->values[1].string.text);
-+
-+      cupsdUpdateQuota(printer, job->username, 0, kbytes);
-+    }
-+
-+    if (job->state_value == IPP_JOB_STOPPED)
-+    {
-+      job->state->values[0].integer = IPP_JOB_PENDING;
-+      job->state_value              = IPP_JOB_PENDING;
-+    }
-+    else if (job->state_value == IPP_JOB_HELD)
-+    {
-+      if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
-+                                   IPP_TAG_KEYWORD)) == NULL)
-+	attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
-+
-+      if (!attr || !strcmp(attr->values[0].string.text, "no-hold"))
-+      {
-+	job->state->values[0].integer = IPP_JOB_PENDING;
-+	job->state_value              = IPP_JOB_PENDING;
-+      }
-+    }
-+
-+    cupsdSaveJob(job);
-+
-+   /*
-+    * Start the job if possible...  Since cupsdCheckJobs() can cancel a
-+    * job if it doesn't print, we need to re-find the job afterwards...
-+    */
-+
-+    jobid = job->id;
-+
-+    cupsdCheckJobs();
-+
-+    job = cupsdFindJob(jobid);
-+  }
-+  else
-+  {
-+    if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
-+                                 IPP_TAG_KEYWORD)) == NULL)
-+      attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
-+
-+    if (!attr || !strcmp(attr->values[0].string.text, "no-hold"))
-+    {
-+      job->state->values[0].integer = IPP_JOB_HELD;
-+      job->state_value              = IPP_JOB_HELD;
-+      job->hold_until               = time(NULL) + 60;
-+      cupsdSaveJob(job);
-+    }
-+  }
-+
-+ /*
-+  * Fill in the response info...
-+  */
-+
-+  snprintf(job_uri, sizeof(job_uri), "http://%s:%d/jobs/%d", ServerName,
-+	   LocalPort, jobid);
-+
-+  ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL,
-+               job_uri);
-+
-+  ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", jobid);
-+
-+  ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state",
-+                job ? job->state_value : IPP_JOB_CANCELED);
-+  add_job_state_reasons(con, job);
-+
-+  con->response->request.status.status_code = IPP_OK;
-+}
-+
-+
-+/*
-+ * 'send_http_error()' - Send a HTTP error back to the IPP client.
-+ */
-+
-+static void
-+send_http_error(cupsd_client_t *con,	/* I - Client connection */
-+                http_status_t  status)	/* I - HTTP status code */
-+{
-+  cupsdLogMessage(CUPSD_LOG_ERROR, "%s: %s",
-+                  ippOpString(con->request->request.op.operation_id),
-+		  httpStatus(status));
-+
-+  cupsdSendError(con, status);
-+
-+  ippDelete(con->response);
-+  con->response = NULL;
-+
-+  return;
-+}
-+
-+
-+/*
-+ * 'send_ipp_status()' - Send a status back to the IPP client.
-+ */
-+
-+static void
-+send_ipp_status(cupsd_client_t *con,	/* I - Client connection */
-+               ipp_status_t   status,	/* I - IPP status code */
-+	       const char     *message,	/* I - Status message */
-+	       ...)			/* I - Additional args as needed */
-+{
-+  va_list	ap;			/* Pointer to additional args */
-+  char		formatted[1024];	/* Formatted errror message */
-+
-+
-+  if (message)
-+  {
-+    va_start(ap, message);
-+    vsnprintf(formatted, sizeof(formatted),
-+              _cupsLangString(con->language, message), ap);
-+    va_end(ap);
-+
-+    cupsdLogMessage(CUPSD_LOG_DEBUG, "%s %s: %s",
-+		    ippOpString(con->request->request.op.operation_id),
-+		    ippErrorString(status), formatted);
-+  }
-+  else
-+    cupsdLogMessage(CUPSD_LOG_DEBUG, "%s %s",
-+		    ippOpString(con->request->request.op.operation_id),
-+		    ippErrorString(status));
-+
-+  con->response->request.status.status_code = status;
-+
-+  if (ippFindAttribute(con->response, "attributes-charset",
-+                       IPP_TAG_ZERO) == NULL)
-+    ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
-+                 "attributes-charset", NULL, DefaultCharset);
-+
-+  if (ippFindAttribute(con->response, "attributes-natural-language",
-+                       IPP_TAG_ZERO) == NULL)
-+    ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
-+                 "attributes-natural-language", NULL, DefaultLanguage);
-+
-+  if (message)
-+    ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_TEXT,
-+        	 "status-message", NULL, formatted);
-+}
-+
-+
-+/*
-+ * 'set_default()' - Set the default destination...
-+ */
-+
-+static void
-+set_default(cupsd_client_t  *con,	/* I - Client connection */
-+            ipp_attribute_t *uri)	/* I - Printer URI */
-+{
-+  http_status_t		status;		/* Policy status */
-+  cups_ptype_t		dtype;		/* Destination type (printer or class) */
-+  char			method[HTTP_MAX_URI],
-+					/* Method portion of URI */
-+			username[HTTP_MAX_URI],
-+					/* Username portion of URI */
-+			host[HTTP_MAX_URI],
-+					/* Host portion of URI */
-+			resource[HTTP_MAX_URI];
-+					/* Resource portion of URI */
-+  int			port;		/* Port portion of URI */
-+  const char		*name;		/* Printer name */
-+  cupsd_printer_t	*printer;	/* Printer */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_default(%p[%d], %s)", con,
-+                  con->http.fd, uri->values[0].string.text);
-+
-+ /*
-+  * Is the destination valid?
-+  */
-+
-+  httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
-+                  sizeof(method), username, sizeof(username), host,
-+		  sizeof(host), &port, resource, sizeof(resource));
-+
-+  if ((name = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL)
-+  {
-+   /*
-+    * Bad URI...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_FOUND,
-+                    _("The printer or class was not found."));
-+    return;
-+  }
-+
-+ /*
-+  * Check policy...
-+  */
-+
-+  if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
-+  {
-+    send_http_error(con, status);
-+    return;
-+  }
-+
-+ /*
-+  * Set it as the default...
-+  */
-+
-+  DefaultPrinter = printer;
-+
-+  cupsdSaveAllPrinters();
-+  cupsdSaveAllClasses();
-+
-+  cupsdWritePrintcap();
-+
-+  cupsdLogMessage(CUPSD_LOG_INFO,
-+                  "Default destination set to \"%s\" by \"%s\".", name,
-+                  get_username(con));
-+
-+ /*
-+  * Everything was ok, so return OK status...
-+  */
-+
-+  con->response->request.status.status_code = IPP_OK;
-+}
-+
-+
-+/*
-+ * 'set_job_attrs()' - Set job attributes.
-+ */
-+
-+static void
-+set_job_attrs(cupsd_client_t  *con,	/* I - Client connection */
-+	      ipp_attribute_t *uri)	/* I - Job URI */
-+{
-+  ipp_attribute_t	*attr,		/* Current attribute */
-+			*attr2;		/* Job attribute */
-+  int			jobid;		/* Job ID */
-+  cupsd_job_t		*job;		/* Current job */
-+  char			method[HTTP_MAX_URI],
-+					/* Method portion of URI */
-+			username[HTTP_MAX_URI],
-+					/* Username portion of URI */
-+			host[HTTP_MAX_URI],
-+					/* Host portion of URI */
-+			resource[HTTP_MAX_URI];
-+					/* Resource portion of URI */
-+  int			port;		/* Port portion of URI */
-+  int			event;		/* Events? */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_job_attrs(%p[%d], %s)", con,
-+                  con->http.fd, uri->values[0].string.text);
-+
-+ /*
-+  * Start with "everything is OK" status...
-+  */
-+
-+  con->response->request.status.status_code = IPP_OK;
-+
-+ /*
-+  * See if we have a job URI or a printer URI...
-+  */
-+
-+  if (!strcmp(uri->name, "printer-uri"))
-+  {
-+   /*
-+    * Got a printer URI; see if we also have a job-id attribute...
-+    */
-+
-+    if ((attr = ippFindAttribute(con->request, "job-id",
-+                                 IPP_TAG_INTEGER)) == NULL)
-+    {
-+      send_ipp_status(con, IPP_BAD_REQUEST,
-+                      _("Got a printer-uri attribute but no job-id!"));
-+      return;
-+    }
-+
-+    jobid = attr->values[0].integer;
-+  }
-+  else
-+  {
-+   /*
-+    * Got a job URI; parse it to get the job ID...
-+    */
-+
-+    httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
-+                    sizeof(method), username, sizeof(username), host,
-+		    sizeof(host), &port, resource, sizeof(resource));
-+
-+    if (strncmp(resource, "/jobs/", 6))
-+    {
-+     /*
-+      * Not a valid URI!
-+      */
-+
-+      send_ipp_status(con, IPP_BAD_REQUEST,
-+                      _("Bad job-uri attribute \"%s\"!"),
-+                      uri->values[0].string.text);
-+      return;
-+    }
-+
-+    jobid = atoi(resource + 6);
-+  }
-+
-+ /*
-+  * See if the job exists...
-+  */
-+
-+  if ((job = cupsdFindJob(jobid)) == NULL)
-+  {
-+   /*
-+    * Nope - return a "not found" error...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), jobid);
-+    return;
-+  }
-+
-+ /*
-+  * See if the job has been completed...
-+  */
-+
-+  if (job->state_value > IPP_JOB_STOPPED)
-+  {
-+   /*
-+    * Return a "not-possible" error...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_POSSIBLE,
-+                    _("Job #%d is finished and cannot be altered!"), jobid);
-+    return;
-+  }
-+
-+ /*
-+  * See if the job is owned by the requesting user...
-+  */
-+
-+  if (!validate_user(job, con, job->username, username, sizeof(username)))
-+  {
-+    send_http_error(con, HTTP_UNAUTHORIZED);
-+    return;
-+  }
-+
-+ /*
-+  * See what the user wants to change.
-+  */
-+
-+  cupsdLoadJob(job);
-+
-+  event = 0;
-+
-+  for (attr = con->request->attrs; attr; attr = attr->next)
-+  {
-+    if (attr->group_tag != IPP_TAG_JOB || !attr->name)
-+      continue;
-+
-+    if (!strcmp(attr->name, "attributes-charset") ||
-+	!strcmp(attr->name, "attributes-natural-language") ||
-+	!strcmp(attr->name, "document-compression") ||
-+	!strcmp(attr->name, "document-format") ||
-+	!strcmp(attr->name, "job-detailed-status-messages") ||
-+	!strcmp(attr->name, "job-document-access-errors") ||
-+	!strcmp(attr->name, "job-id") ||
-+	!strcmp(attr->name, "job-k-octets") ||
-+        !strcmp(attr->name, "job-originating-host-name") ||
-+        !strcmp(attr->name, "job-originating-user-name") ||
-+	!strcmp(attr->name, "job-printer-up-time") ||
-+	!strcmp(attr->name, "job-printer-uri") ||
-+	!strcmp(attr->name, "job-sheets") ||
-+	!strcmp(attr->name, "job-state-message") ||
-+	!strcmp(attr->name, "job-state-reasons") ||
-+	!strcmp(attr->name, "job-uri") ||
-+	!strcmp(attr->name, "number-of-documents") ||
-+	!strcmp(attr->name, "number-of-intervening-jobs") ||
-+	!strcmp(attr->name, "output-device-assigned") ||
-+	!strncmp(attr->name, "date-time-at-", 13) ||
-+	!strncmp(attr->name, "job-impressions", 15) ||
-+	!strncmp(attr->name, "job-k-octets", 12) ||
-+	!strncmp(attr->name, "job-media-sheets", 16) ||
-+	!strncmp(attr->name, "time-at-", 8))
-+    {
-+     /*
-+      * Read-only attrs!
-+      */
-+
-+      send_ipp_status(con, IPP_ATTRIBUTES_NOT_SETTABLE,
-+                      _("%s cannot be changed."), attr->name);
-+
-+      if ((attr2 = copy_attribute(con->response, attr, 0)) != NULL)
-+        attr2->group_tag = IPP_TAG_UNSUPPORTED_GROUP;
-+
-+      continue;
-+    }
-+
-+    if (!strcmp(attr->name, "job-priority"))
-+    {
-+     /*
-+      * Change the job priority...
-+      */
-+
-+      if (attr->value_tag != IPP_TAG_INTEGER)
-+      {
-+	send_ipp_status(con, IPP_REQUEST_VALUE, _("Bad job-priority value!"));
-+
-+	if ((attr2 = copy_attribute(con->response, attr, 0)) != NULL)
-+          attr2->group_tag = IPP_TAG_UNSUPPORTED_GROUP;
-+      }
-+      else if (job->state_value >= IPP_JOB_PROCESSING)
-+      {
-+	send_ipp_status(con, IPP_NOT_POSSIBLE,
-+	                _("Job is completed and cannot be changed."));
-+	return;
-+      }
-+      else if (con->response->request.status.status_code == IPP_OK)
-+      {
-+        cupsdSetJobPriority(job, attr->values[0].integer);
-+        event |= CUPSD_EVENT_JOB_CONFIG_CHANGED;
-+      }
-+    }
-+    else if (!strcmp(attr->name, "job-state"))
-+    {
-+     /*
-+      * Change the job state...
-+      */
-+
-+      if (attr->value_tag != IPP_TAG_ENUM)
-+      {
-+	send_ipp_status(con, IPP_REQUEST_VALUE, _("Bad job-state value!"));
-+
-+	if ((attr2 = copy_attribute(con->response, attr, 0)) != NULL)
-+          attr2->group_tag = IPP_TAG_UNSUPPORTED_GROUP;
-+      }
-+      else
-+      {
-+        switch (attr->values[0].integer)
-+	{
-+	  case IPP_JOB_PENDING :
-+	  case IPP_JOB_HELD :
-+	      if (job->state_value > IPP_JOB_HELD)
-+	      {
-+		send_ipp_status(con, IPP_NOT_POSSIBLE,
-+		                _("Job state cannot be changed."));
-+		return;
-+	      }
-+              else if (con->response->request.status.status_code == IPP_OK)
-+	      {
-+		job->state->values[0].integer = attr->values[0].integer;
-+		job->state_value              = (ipp_jstate_t)attr->values[0].integer;
-+
-+                event |= CUPSD_EVENT_JOB_STATE;
-+	      }
-+	      break;
-+
-+	  case IPP_JOB_PROCESSING :
-+	  case IPP_JOB_STOPPED :
-+	      if (job->state_value != attr->values[0].integer)
-+	      {
-+		send_ipp_status(con, IPP_NOT_POSSIBLE,
-+		                _("Job state cannot be changed."));
-+		return;
-+	      }
-+	      break;
-+
-+	  case IPP_JOB_CANCELED :
-+	  case IPP_JOB_ABORTED :
-+	  case IPP_JOB_COMPLETED :
-+	      if (job->state_value > IPP_JOB_PROCESSING)
-+	      {
-+		send_ipp_status(con, IPP_NOT_POSSIBLE,
-+		                _("Job state cannot be changed."));
-+		return;
-+	      }
-+              else if (con->response->request.status.status_code == IPP_OK)
-+                cupsdCancelJob(job, 0, (ipp_jstate_t)attr->values[0].integer);
-+	      break;
-+	}
-+      }
-+    }
-+    else if (con->response->request.status.status_code != IPP_OK)
-+      continue;
-+    else if ((attr2 = ippFindAttribute(job->attrs, attr->name,
-+                                       IPP_TAG_ZERO)) != NULL)
-+    {
-+     /*
-+      * Some other value; first free the old value...
-+      */
-+
-+      if (job->attrs->prev)
-+        job->attrs->prev->next = attr2->next;
-+      else
-+        job->attrs->attrs = attr2->next;
-+
-+      if (job->attrs->last == attr2)
-+        job->attrs->last = job->attrs->prev;
-+
-+      _ippFreeAttr(attr2);
-+
-+     /*
-+      * Then copy the attribute...
-+      */
-+
-+      copy_attribute(job->attrs, attr, 0);
-+
-+     /*
-+      * See if the job-name or job-hold-until is being changed.
-+      */
-+
-+      if (!strcmp(attr->name, "job-hold-until"))
-+      {
-+        cupsdSetJobHoldUntil(job, attr->values[0].string.text);
-+
-+	if (!strcmp(attr->values[0].string.text, "no-hold"))
-+	  cupsdReleaseJob(job);
-+	else
-+	  cupsdHoldJob(job);
-+
-+        event |= CUPSD_EVENT_JOB_CONFIG_CHANGED | CUPSD_EVENT_JOB_STATE;
-+      }
-+    }
-+    else if (attr->value_tag == IPP_TAG_DELETEATTR)
-+    {
-+     /*
-+      * Delete the attribute...
-+      */
-+
-+      if ((attr2 = ippFindAttribute(job->attrs, attr->name,
-+                                    IPP_TAG_ZERO)) != NULL)
-+      {
-+        if (job->attrs->prev)
-+	  job->attrs->prev->next = attr2->next;
-+	else
-+	  job->attrs->attrs = attr2->next;
-+
-+        if (attr2 == job->attrs->last)
-+	  job->attrs->last = job->attrs->prev;
-+
-+        _ippFreeAttr(attr2);
-+
-+        event |= CUPSD_EVENT_JOB_CONFIG_CHANGED;
-+      }
-+    }
-+    else
-+    {
-+     /*
-+      * Add new option by copying it...
-+      */
-+
-+      copy_attribute(job->attrs, attr, 0);
-+
-+      event |= CUPSD_EVENT_JOB_CONFIG_CHANGED;
-+    }
-+  }
-+
-+ /*
-+  * Save the job...
-+  */
-+
-+  cupsdSaveJob(job);
-+
-+ /*
-+  * Send events as needed...
-+  */
-+
-+  if (event & CUPSD_EVENT_JOB_STATE)
-+    cupsdAddEvent(CUPSD_EVENT_JOB_STATE, job->printer, job,
-+                  job->state_value == IPP_JOB_HELD ?
-+		      "Job held by user." : "Job restarted by user.");
-+
-+  if (event & CUPSD_EVENT_JOB_CONFIG_CHANGED)
-+    cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, job->printer, job,
-+                  "Job options changed by user.");
-+
-+ /*
-+  * Start jobs if possible...
-+  */
-+
-+  cupsdCheckJobs();
-+}
-+
-+
-+/*
-+ * 'set_printer_defaults()' - Set printer default options from a request.
-+ */
-+
-+static void
-+set_printer_defaults(
-+    cupsd_client_t  *con,		/* I - Client connection */
-+    cupsd_printer_t *printer)		/* I - Printer */
-+{
-+  int			i;		/* Looping var */
-+  ipp_attribute_t 	*attr;		/* Current attribute */
-+  int			namelen;	/* Length of attribute name */
-+  char			name[256],	/* New attribute name */
-+			value[256];	/* String version of integer attrs */
-+
-+
-+  for (attr = con->request->attrs; attr; attr = attr->next)
-+  {
-+   /*
-+    * Skip non-printer attributes...
-+    */
-+
-+    if (attr->group_tag != IPP_TAG_PRINTER || !attr->name)
-+      continue;
-+
-+    cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_printer_defaults: %s", attr->name);
-+
-+    if (!strcmp(attr->name, "job-sheets-default"))
-+    {
-+     /*
-+      * Only allow keywords and names...
-+      */
-+
-+      if (attr->value_tag != IPP_TAG_NAME && attr->value_tag != IPP_TAG_KEYWORD)
-+        continue;
-+
-+     /*
-+      * Only allow job-sheets-default to be set when running without a
-+      * system high classification level...
-+      */
-+
-+      if (Classification)
-+        continue;
-+
-+      cupsdSetString(&printer->job_sheets[0], attr->values[0].string.text);
-+
-+      if (attr->num_values > 1)
-+	cupsdSetString(&printer->job_sheets[1], attr->values[1].string.text);
-+      else
-+	cupsdSetString(&printer->job_sheets[1], "none");
-+    }
-+    else if (!strcmp(attr->name, "requesting-user-name-allowed"))
-+    {
-+      cupsdFreePrinterUsers(printer);
-+
-+      printer->deny_users = 0;
-+
-+      if (attr->value_tag == IPP_TAG_NAME &&
-+          (attr->num_values > 1 ||
-+	   strcmp(attr->values[0].string.text, "all")))
-+      {
-+	for (i = 0; i < attr->num_values; i ++)
-+	  cupsdAddPrinterUser(printer, attr->values[i].string.text);
-+      }
-+    }
-+    else if (!strcmp(attr->name, "requesting-user-name-denied"))
-+    {
-+      cupsdFreePrinterUsers(printer);
-+
-+      printer->deny_users = 1;
-+
-+      if (attr->value_tag == IPP_TAG_NAME &&
-+          (attr->num_values > 1 ||
-+	   strcmp(attr->values[0].string.text, "none")))
-+      {
-+	for (i = 0; i < attr->num_values; i ++)
-+	  cupsdAddPrinterUser(printer, attr->values[i].string.text);
-+      }
-+    }
-+    else if (!strcmp(attr->name, "job-quota-period"))
-+    {
-+      if (attr->value_tag != IPP_TAG_INTEGER)
-+        continue;
-+
-+      cupsdLogMessage(CUPSD_LOG_DEBUG, "Setting job-quota-period to %d...",
-+        	      attr->values[0].integer);
-+      cupsdFreeQuotas(printer);
-+
-+      printer->quota_period = attr->values[0].integer;
-+    }
-+    else if (!strcmp(attr->name, "job-k-limit"))
-+    {
-+      if (attr->value_tag != IPP_TAG_INTEGER)
-+        continue;
-+
-+      cupsdLogMessage(CUPSD_LOG_DEBUG, "Setting job-k-limit to %d...",
-+        	      attr->values[0].integer);
-+      cupsdFreeQuotas(printer);
-+
-+      printer->k_limit = attr->values[0].integer;
-+    }
-+    else if (!strcmp(attr->name, "job-page-limit"))
-+    {
-+      if (attr->value_tag != IPP_TAG_INTEGER)
-+        continue;
-+
-+      cupsdLogMessage(CUPSD_LOG_DEBUG, "Setting job-page-limit to %d...",
-+        	      attr->values[0].integer);
-+      cupsdFreeQuotas(printer);
-+
-+      printer->page_limit = attr->values[0].integer;
-+    }
-+    else if (!strcmp(attr->name, "printer-op-policy"))
-+    {
-+      cupsd_policy_t *p;		/* Policy */
-+
-+
-+      if (attr->value_tag != IPP_TAG_NAME)
-+        continue;
-+
-+      if ((p = cupsdFindPolicy(attr->values[0].string.text)) != NULL)
-+      {
-+	cupsdLogMessage(CUPSD_LOG_DEBUG,
-+                	"Setting printer-op-policy to \"%s\"...",
-+                	attr->values[0].string.text);
-+	cupsdSetString(&printer->op_policy, attr->values[0].string.text);
-+	printer->op_policy_ptr = p;
-+      }
-+      else
-+      {
-+	send_ipp_status(con, IPP_NOT_POSSIBLE,
-+                	_("Unknown printer-op-policy \"%s\"."),
-+                	attr->values[0].string.text);
-+	return;
-+      }
-+    }
-+    else if (!strcmp(attr->name, "printer-error-policy"))
-+    {
-+      if (attr->value_tag != IPP_TAG_NAME && attr->value_tag != IPP_TAG_KEYWORD)
-+        continue;
-+
-+      if (strcmp(attr->values[0].string.text, "abort-job") &&
-+          strcmp(attr->values[0].string.text, "retry-job") &&
-+          strcmp(attr->values[0].string.text, "stop-printer"))
-+      {
-+	send_ipp_status(con, IPP_NOT_POSSIBLE,
-+                	_("Unknown printer-error-policy \"%s\"."),
-+                	attr->values[0].string.text);
-+	return;
-+      }
-+
-+      cupsdLogMessage(CUPSD_LOG_DEBUG,
-+                      "Setting printer-error-policy to \"%s\"...",
-+                      attr->values[0].string.text);
-+      cupsdSetString(&printer->error_policy, attr->values[0].string.text);
-+    }
-+    else if (!strcmp(attr->name, "document-format-default") ||
-+             !strcmp(attr->name, "notify-lease-duration-default") ||
-+             !strcmp(attr->name, "notify-events-default"))
-+      continue;
-+
-+   /*
-+    * Skip any other non-default attributes...
-+    */
-+
-+    namelen = strlen(attr->name);
-+    if (namelen < 9 || strcmp(attr->name + namelen - 8, "-default") ||
-+        namelen > (sizeof(name) - 1) || attr->num_values != 1)
-+      continue;
-+
-+   /*
-+    * OK, anything else must be a user-defined default...
-+    */
-+
-+    strlcpy(name, attr->name, sizeof(name));
-+    name[namelen - 8] = '\0';		/* Strip "-default" */
-+
-+    switch (attr->value_tag)
-+    {
-+      case IPP_TAG_DELETEATTR :
-+          printer->num_options = cupsRemoveOption(name,
-+						  printer->num_options,
-+						  &(printer->options));
-+          cupsdLogMessage(CUPSD_LOG_DEBUG,
-+	                  "Deleting %s", attr->name);
-+          break;
-+
-+      case IPP_TAG_NAME :
-+      case IPP_TAG_KEYWORD :
-+      case IPP_TAG_URI :
-+          printer->num_options = cupsAddOption(name,
-+	                                       attr->values[0].string.text,
-+					       printer->num_options,
-+					       &(printer->options));
-+          cupsdLogMessage(CUPSD_LOG_DEBUG,
-+	                  "Setting %s to \"%s\"...", attr->name,
-+			  attr->values[0].string.text);
-+          break;
-+
-+      case IPP_TAG_BOOLEAN :
-+          printer->num_options = cupsAddOption(name,
-+	                                       attr->values[0].boolean ?
-+					           "true" : "false",
-+					       printer->num_options,
-+					       &(printer->options));
-+          cupsdLogMessage(CUPSD_LOG_DEBUG,
-+	                  "Setting %s to %s...", attr->name,
-+			  attr->values[0].boolean ? "true" : "false");
-+          break;
-+
-+      case IPP_TAG_INTEGER :
-+      case IPP_TAG_ENUM :
-+          sprintf(value, "%d", attr->values[0].integer);
-+          printer->num_options = cupsAddOption(name, value,
-+					       printer->num_options,
-+					       &(printer->options));
-+          cupsdLogMessage(CUPSD_LOG_DEBUG,
-+	                  "Setting %s to %s...", attr->name, value);
-+          break;
-+
-+      case IPP_TAG_RANGE :
-+          sprintf(value, "%d-%d", attr->values[0].range.lower,
-+	          attr->values[0].range.upper);
-+          printer->num_options = cupsAddOption(name, value,
-+					       printer->num_options,
-+					       &(printer->options));
-+          cupsdLogMessage(CUPSD_LOG_DEBUG,
-+	                  "Setting %s to %s...", attr->name, value);
-+          break;
-+
-+      case IPP_TAG_RESOLUTION :
-+          sprintf(value, "%dx%d%s", attr->values[0].resolution.xres,
-+	          attr->values[0].resolution.yres,
-+		  attr->values[0].resolution.units == IPP_RES_PER_INCH ?
-+		      "dpi" : "dpc");
-+          printer->num_options = cupsAddOption(name, value,
-+					       printer->num_options,
-+					       &(printer->options));
-+          cupsdLogMessage(CUPSD_LOG_DEBUG,
-+	                  "Setting %s to %s...", attr->name, value);
-+          break;
-+
-+      default :
-+          /* Do nothing for other values */
-+	  break;
-+    }
-+  }
-+}
-+
-+
-+/*
-+ * 'start_printer()' - Start a printer.
-+ */
-+
-+static void
-+start_printer(cupsd_client_t  *con,	/* I - Client connection */
-+              ipp_attribute_t *uri)	/* I - Printer URI */
-+{
-+  http_status_t		status;		/* Policy status */
-+  cups_ptype_t		dtype;		/* Destination type (printer or class) */
-+  char			method[HTTP_MAX_URI],
-+					/* Method portion of URI */
-+			username[HTTP_MAX_URI],
-+					/* Username portion of URI */
-+			host[HTTP_MAX_URI],
-+					/* Host portion of URI */
-+			resource[HTTP_MAX_URI];
-+					/* Resource portion of URI */
-+  int			port;		/* Port portion of URI */
-+  const char		*name;		/* Printer name */
-+  cupsd_printer_t	*printer;	/* Printer data */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "start_printer(%p[%d], %s)", con,
-+                  con->http.fd, uri->values[0].string.text);
-+
-+ /*
-+  * Is the destination valid?
-+  */
-+
-+  httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
-+                  sizeof(method), username, sizeof(username), host,
-+		  sizeof(host), &port, resource, sizeof(resource));
-+
-+  if ((name = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL)
-+  {
-+   /*
-+    * Bad URI...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_FOUND,
-+                    _("The printer or class was not found."));
-+    return;
-+  }
-+
-+ /*
-+  * Check policy...
-+  */
-+
-+  if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
-+  {
-+    send_http_error(con, status);
-+    return;
-+  }
-+
-+ /*
-+  * Start the printer...
-+  */
-+
-+  printer->state_message[0] = '\0';
-+
-+  cupsdStartPrinter(printer, 1);
-+
-+  if (dtype & CUPS_PRINTER_CLASS)
-+    cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" started by \"%s\".", name,
-+                    get_username(con));
-+  else
-+    cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" started by \"%s\".", name,
-+                    get_username(con));
-+
-+  cupsdCheckJobs();
-+
-+ /*
-+  * Everything was ok, so return OK status...
-+  */
-+
-+  con->response->request.status.status_code = IPP_OK;
-+}
-+
-+
-+/*
-+ * 'stop_printer()' - Stop a printer.
-+ */
-+
-+static void
-+stop_printer(cupsd_client_t  *con,	/* I - Client connection */
-+             ipp_attribute_t *uri)	/* I - Printer URI */
-+{
-+  http_status_t		status;		/* Policy status */
-+  cups_ptype_t		dtype;		/* Destination type (printer or class) */
-+  char			method[HTTP_MAX_URI],
-+					/* Method portion of URI */
-+			username[HTTP_MAX_URI],
-+					/* Username portion of URI */
-+			host[HTTP_MAX_URI],
-+					/* Host portion of URI */
-+			resource[HTTP_MAX_URI];
-+					/* Resource portion of URI */
-+  int			port;		/* Port portion of URI */
-+  const char		*name;		/* Printer name */
-+  cupsd_printer_t	*printer;	/* Printer data */
-+  ipp_attribute_t	*attr;		/* printer-state-message attribute */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "stop_printer(%p[%d], %s)", con,
-+                  con->http.fd, uri->values[0].string.text);
-+
-+ /*
-+  * Is the destination valid?
-+  */
-+
-+  httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
-+                  sizeof(method), username, sizeof(username), host,
-+		  sizeof(host), &port, resource, sizeof(resource));
-+
-+  if ((name = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL)
-+  {
-+   /*
-+    * Bad URI...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_FOUND,
-+                    _("The printer or class was not found."));
-+    return;
-+  }
-+
-+ /*
-+  * Check policy...
-+  */
-+
-+  if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
-+  {
-+    send_http_error(con, status);
-+    return;
-+  }
-+
-+ /*
-+  * Stop the printer...
-+  */
-+
-+  if ((attr = ippFindAttribute(con->request, "printer-state-message",
-+                               IPP_TAG_TEXT)) == NULL)
-+    strcpy(printer->state_message, "Paused");
-+  else
-+  {
-+    strlcpy(printer->state_message, attr->values[0].string.text,
-+            sizeof(printer->state_message));
-+  }
-+
-+  cupsdStopPrinter(printer, 1);
-+
-+  if (dtype & CUPS_PRINTER_CLASS)
-+    cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" stopped by \"%s\".", name,
-+                    get_username(con));
-+  else
-+    cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" stopped by \"%s\".", name,
-+                    get_username(con));
-+
-+ /*
-+  * Everything was ok, so return OK status...
-+  */
-+
-+  con->response->request.status.status_code = IPP_OK;
-+}
-+
-+
-+/*
-+ * 'url_encode_attr()' - URL-encode a string attribute.
-+ */
-+
-+static void
-+url_encode_attr(ipp_attribute_t *attr,	/* I - Attribute */
-+                char            *buffer,/* I - String buffer */
-+		int             bufsize)/* I - Size of buffer */
-+{
-+  int	i;				/* Looping var */
-+  char	*bufptr,			/* Pointer into buffer */
-+	*bufend,			/* End of buffer */
-+	*valptr;			/* Pointer into value */
-+
-+
-+  strlcpy(buffer, attr->name, bufsize);
-+  bufptr = buffer + strlen(buffer);
-+  bufend = buffer + bufsize - 1;
-+
-+  for (i = 0; i < attr->num_values; i ++)
-+  {
-+    if (bufptr >= bufend)
-+      break;
-+
-+    if (i)
-+      *bufptr++ = ',';
-+    else
-+      *bufptr++ = '=';
-+
-+    if (bufptr >= bufend)
-+      break;
-+
-+    *bufptr++ = '\'';
-+
-+    for (valptr = attr->values[i].string.text;
-+         *valptr && bufptr < bufend;
-+	 valptr ++)
-+      if (*valptr == ' ')
-+      {
-+        if (bufptr >= (bufend - 2))
-+	  break;
-+
-+        *bufptr++ = '%';
-+	*bufptr++ = '2';
-+	*bufptr++ = '0';
-+      }
-+      else if (*valptr == '\'' || *valptr == '\\')
-+      {
-+        *bufptr++ = '\\';
-+        *bufptr++ = *valptr;
-+      }
-+      else
-+        *bufptr++ = *valptr;
-+
-+    if (bufptr >= bufend)
-+      break;
-+
-+    *bufptr++ = '\'';
-+  }
-+
-+  *bufptr = '\0';
-+}
-+
-+
-+/*
-+ * 'user_allowed()' - See if a user is allowed to print to a queue.
-+ */
-+
-+static int				/* O - 0 if not allowed, 1 if allowed */
-+user_allowed(cupsd_printer_t *p,	/* I - Printer or class */
-+             const char      *username)	/* I - Username */
-+{
-+  int		i;			/* Looping var */
-+  struct passwd	*pw;			/* User password data */
-+
-+
-+  if (p->num_users == 0)
-+    return (1);
-+
-+  if (!strcmp(username, "root"))
-+    return (1);
-+
-+  pw = getpwnam(username);
-+  endpwent();
-+
-+  for (i = 0; i < p->num_users; i ++)
-+  {
-+    if (p->users[i][0] == '@')
-+    {
-+     /*
-+      * Check group membership...
-+      */
-+
-+      if (cupsdCheckGroup(username, pw, p->users[i] + 1))
-+        break;
-+    }
-+    else if (!strcasecmp(username, p->users[i]))
-+      break;
-+  }
-+
-+  return ((i < p->num_users) != p->deny_users);
-+}
-+
-+
-+/*
-+ * 'validate_job()' - Validate printer options and destination.
-+ */
-+
-+static void
-+validate_job(cupsd_client_t  *con,	/* I - Client connection */
-+	     ipp_attribute_t *uri)	/* I - Printer URI */
-+{
-+  http_status_t		status;		/* Policy status */
-+  ipp_attribute_t	*attr;		/* Current attribute */
-+  ipp_attribute_t	*format;	/* Document-format attribute */
-+  cups_ptype_t		dtype;		/* Destination type (printer or class) */
-+  char			method[HTTP_MAX_URI],
-+					/* Method portion of URI */
-+			username[HTTP_MAX_URI],
-+					/* Username portion of URI */
-+			host[HTTP_MAX_URI],
-+					/* Host portion of URI */
-+			resource[HTTP_MAX_URI];
-+					/* Resource portion of URI */
-+  int			port;		/* Port portion of URI */
-+  char			super[MIME_MAX_SUPER],
-+					/* Supertype of file */
-+			type[MIME_MAX_TYPE];
-+					/* Subtype of file */
-+  cupsd_printer_t	*printer;	/* Printer */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "validate_job(%p[%d], %s)", con,
-+                  con->http.fd, uri->values[0].string.text);
-+
-+ /*
-+  * OK, see if the client is sending the document compressed - CUPS
-+  * doesn't support compression yet...
-+  */
-+
-+  if ((attr = ippFindAttribute(con->request, "compression",
-+                               IPP_TAG_KEYWORD)) != NULL &&
-+      !strcmp(attr->values[0].string.text, "none"))
-+  {
-+    send_ipp_status(con, IPP_ATTRIBUTES,
-+                    _("Unsupported compression attribute %s!"),
-+                    attr->values[0].string.text);
-+    ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD,
-+	         "compression", NULL, attr->values[0].string.text);
-+    return;
-+  }
-+
-+ /*
-+  * Is it a format we support?
-+  */
-+
-+  if ((format = ippFindAttribute(con->request, "document-format",
-+                                 IPP_TAG_MIMETYPE)) != NULL)
-+  {
-+    if (sscanf(format->values[0].string.text, "%15[^/]/%31[^;]", super, type) != 2)
-+    {
-+      send_ipp_status(con, IPP_BAD_REQUEST, _("Bad document-format \"%s\"!"),
-+		      format->values[0].string.text);
-+      return;
-+    }
-+
-+    if ((strcmp(super, "application") || strcmp(type, "octet-stream")) &&
-+	!mimeType(MimeDatabase, super, type))
-+    {
-+      cupsdLogMessage(CUPSD_LOG_INFO,
-+                      "Hint: Do you have the raw file printing rules enabled?");
-+      send_ipp_status(con, IPP_DOCUMENT_FORMAT,
-+                      _("Unsupported format \"%s\"!"),
-+		      format->values[0].string.text);
-+      ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE,
-+                   "document-format", NULL, format->values[0].string.text);
-+      return;
-+    }
-+  }
-+
-+ /*
-+  * Is the destination valid?
-+  */
-+
-+  httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
-+                  sizeof(method), username, sizeof(username), host,
-+		  sizeof(host), &port, resource, sizeof(resource));
-+
-+  if (cupsdValidateDest(host, resource, &dtype, &printer) == NULL)
-+  {
-+   /*
-+    * Bad URI...
-+    */
-+
-+    send_ipp_status(con, IPP_NOT_FOUND,
-+                    _("The printer or class was not found."));
-+    return;
-+  }
-+
-+ /*
-+  * Check policy...
-+  */
-+
-+  if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
-+  {
-+    send_http_error(con, status);
-+    return;
-+  }
-+
-+ /*
-+  * Everything was ok, so return OK status...
-+  */
-+
-+  con->response->request.status.status_code = IPP_OK;
-+}
-+
-+
-+/*
-+ * 'validate_name()' - Make sure the printer name only contains valid chars.
-+ */
-+
-+static int			/* O - 0 if name is no good, 1 if name is good */
-+validate_name(const char *name)	/* I - Name to check */
-+{
-+  const char	*ptr;		/* Pointer into name */
-+
-+
-+ /*
-+  * Scan the whole name...
-+  */
-+
-+  for (ptr = name; *ptr; ptr ++)
-+    if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#')
-+      return (0);
-+
-+ /*
-+  * All the characters are good; validate the length, too...
-+  */
-+
-+  return ((ptr - name) < 128);
-+}
-+
-+
-+/*
-+ * 'validate_user()' - Validate the user for the request.
-+ */
-+
-+static int				/* O - 1 if permitted, 0 otherwise */
-+validate_user(cupsd_job_t    *job,	/* I - Job */
-+              cupsd_client_t *con,	/* I - Client connection */
-+              const char     *owner,	/* I - Owner of job/resource */
-+              char           *username,	/* O - Authenticated username */
-+	      int            userlen)	/* I - Length of username */
-+{
-+  cupsd_printer_t	*printer;	/* Printer for job */
-+
-+
-+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-+                  "validate_user(job=%d, con=%d, owner=\"%s\", username=%p, "
-+		  "userlen=%d)",
-+        	  job ? job->id : 0, con->http.fd, owner ? owner : "(null)",
-+		  username, userlen);
-+
-+ /*
-+  * Validate input...
-+  */
-+
-+  if (!con || !owner || !username || userlen <= 0)
-+    return (0);
-+
-+ /*
-+  * Get the best authenticated username that is available.
-+  */
-+
-+  strlcpy(username, get_username(con), userlen);
-+
-+ /*
-+  * Check the username against the owner...
-+  */
-+
-+  printer = cupsdFindDest(job->dest);
-+
-+  return (cupsdCheckPolicy(printer ? printer->op_policy_ptr : DefaultPolicyPtr,
-+                           con, owner) == HTTP_OK);
-+}
-+
-+
-+/*
-+ * End of "$Id: ipp.c 6145 2006-12-06 20:10:16Z mike $".
-+ */
 diff -urNad cupsys-1.2.8~/scheduler/log.c cupsys-1.2.8/scheduler/log.c
---- cupsys-1.2.8~/scheduler/log.c	2007-03-13 15:02:07.000000000 +0000
-+++ cupsys-1.2.8/scheduler/log.c	2007-03-13 15:02:07.000000000 +0000
+--- cupsys-1.2.8~/scheduler/log.c	2007-03-14 15:53:31.000000000 +0000
++++ cupsys-1.2.8/scheduler/log.c	2007-03-14 15:53:31.000000000 +0000
 @@ -420,9 +420,10 @@
  check_log_file(cups_file_t **lf,	/* IO - Log file */
  	       const char  *logname)	/* I  - Log filename */
@@ -12384,574 +3215,9 @@
  
      *ptr = '\0';
    }
-diff -urNad cupsys-1.2.8~/scheduler/log.c.orig cupsys-1.2.8/scheduler/log.c.orig
---- cupsys-1.2.8~/scheduler/log.c.orig	1970-01-01 01:00:00.000000000 +0100
-+++ cupsys-1.2.8/scheduler/log.c.orig	2007-03-13 15:02:07.000000000 +0000
-@@ -0,0 +1,561 @@
-+/*
-+ * "$Id: log.c 6027 2006-10-11 21:04:58Z mike $"
-+ *
-+ *   Log file routines for the Common UNIX Printing System (CUPS).
-+ *
-+ *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
-+ *
-+ *   These coded instructions, statements, and computer programs are the
-+ *   property of Easy Software Products and are protected by Federal
-+ *   copyright law.  Distribution and use rights are outlined in the file
-+ *   "LICENSE.txt" which should have been included with this file.  If this
-+ *   file is missing or damaged please contact Easy Software Products
-+ *   at:
-+ *
-+ *       Attn: CUPS Licensing Information
-+ *       Easy Software Products
-+ *       44141 Airport View Drive, Suite 204
-+ *       Hollywood, Maryland 20636 USA
-+ *
-+ *       Voice: (301) 373-9600
-+ *       EMail: cups-info at cups.org
-+ *         WWW: http://www.cups.org
-+ *
-+ * Contents:
-+ *
-+ *   cupsdGetDateTime() - Returns a pointer to a date/time string.
-+ *   cupsdLogMessage()  - Log a message to the error log file.
-+ *   cupsdLogPage()     - Log a page to the page log file.
-+ *   cupsdLogRequest()  - Log an HTTP request in Common Log Format.
-+ *   check_log_file()   - Open/rotate a log file if it needs it.
-+ */
-+
-+/*
-+ * Include necessary headers...
-+ */
-+
-+#include "cupsd.h"
-+#include <stdarg.h>
-+#include <syslog.h>
-+
-+
-+/*
-+ * Local functions...
-+ */
-+
-+static int	check_log_file(cups_file_t **, const char *);
-+
-+
-+/*
-+ * 'cupsdGetDateTime()' - Returns a pointer to a date/time string.
-+ */
-+
-+char *					/* O - Date/time string */
-+cupsdGetDateTime(time_t t)		/* I - Time value */
-+{
-+  struct tm	*date;			/* Date/time value */
-+  static time_t	last_time = -1;		/* Last time value */
-+  static char	s[1024];		/* Date/time string */
-+  static const char * const months[12] =/* Months */
-+		{
-+		  "Jan",
-+		  "Feb",
-+		  "Mar",
-+		  "Apr",
-+		  "May",
-+		  "Jun",
-+		  "Jul",
-+		  "Aug",
-+		  "Sep",
-+		  "Oct",
-+		  "Nov",
-+		  "Dec"
-+		};
-+
-+
-+  if (t != last_time)
-+  {
-+    last_time = t;
-+
-+   /*
-+    * Get the date and time from the UNIX time value, and then format it
-+    * into a string.  Note that we *can't* use the strftime() function since
-+    * it is localized and will seriously confuse automatic programs if the
-+    * month names are in the wrong language!
-+    *
-+    * Also, we use the "timezone" variable that contains the current timezone
-+    * offset from GMT in seconds so that we are reporting local time in the
-+    * log files.  If you want GMT, set the TZ environment variable accordingly
-+    * before starting the scheduler.
-+    *
-+    * (*BSD and Darwin store the timezone offset in the tm structure)
-+    */
-+
-+    date = localtime(&t);
-+
-+    snprintf(s, sizeof(s), "[%02d/%s/%04d:%02d:%02d:%02d %+03ld%02ld]",
-+	     date->tm_mday, months[date->tm_mon], 1900 + date->tm_year,
-+	     date->tm_hour, date->tm_min, date->tm_sec,
-+#ifdef HAVE_TM_GMTOFF
-+             date->tm_gmtoff / 3600, (date->tm_gmtoff / 60) % 60);
-+#else
-+             timezone / 3600, (timezone / 60) % 60);
-+#endif /* HAVE_TM_GMTOFF */
-+  }
-+
-+  return (s);
-+}
-+
-+
-+/*
-+ * 'cupsdLogMessage()' - Log a message to the error log file.
-+ */
-+
-+int					/* O - 1 on success, 0 on error */
-+cupsdLogMessage(int        level,	/* I - Log level */
-+                const char *message,	/* I - printf-style message string */
-+	        ...)			/* I - Additional args as needed */
-+{
-+  int			len;		/* Length of message */
-+  va_list		ap;		/* Argument pointer */
-+  static const char	levels[] =	/* Log levels... */
-+		{
-+		  ' ',
-+		  'X',
-+		  'A',
-+		  'C',
-+		  'E',
-+		  'W',
-+		  'N',
-+		  'I',
-+		  'D',
-+		  'd'
-+		};
-+#ifdef HAVE_VSYSLOG
-+  static const int syslevels[] =	/* SYSLOG levels... */
-+		{
-+		  0,
-+		  LOG_EMERG,
-+		  LOG_ALERT,
-+		  LOG_CRIT,
-+		  LOG_ERR,
-+		  LOG_WARNING,
-+		  LOG_NOTICE,
-+		  LOG_INFO,
-+		  LOG_DEBUG,
-+		  LOG_DEBUG
-+		};
-+#endif /* HAVE_VSYSLOG */
-+  static int	linesize = 0;		/* Size of line for output file */
-+  static char	*line = NULL;		/* Line for output file */
-+
-+
-+ /*
-+  * See if we want to log this message...
-+  */
-+
-+  if (level > LogLevel || !ErrorLog)
-+    return (1);
-+
-+#ifdef HAVE_VSYSLOG
-+ /*
-+  * See if we are logging errors via syslog...
-+  */
-+
-+  if (!strcmp(ErrorLog, "syslog"))
-+  {
-+    va_start(ap, message);
-+    vsyslog(syslevels[level], message, ap);
-+    va_end(ap);
-+
-+    return (1);
-+  }
-+#endif /* HAVE_VSYSLOG */
-+
-+ /*
-+  * Not using syslog; check the log file...
-+  */
-+
-+  if (!check_log_file(&ErrorFile, ErrorLog))
-+    return (0);
-+
-+ /*
-+  * Print the log level and date/time...
-+  */
-+
-+  cupsFilePrintf(ErrorFile, "%c %s ", levels[level], cupsdGetDateTime(time(NULL)));
-+
-+ /*
-+  * Allocate the line buffer as needed...
-+  */
-+
-+  if (!linesize)
-+  {
-+    linesize = 8192;
-+    line     = malloc(linesize);
-+
-+    if (!line)
-+    {
-+      cupsFilePrintf(ErrorFile,
-+                     "ERROR: Unable to allocate memory for line - %s\n",
-+                     strerror(errno));
-+      cupsFileFlush(ErrorFile);
-+
-+      return (0);
-+    }
-+  }
-+
-+ /*
-+  * Format the log message...
-+  */
-+
-+  va_start(ap, message);
-+  len = vsnprintf(line, linesize, message, ap);
-+  va_end(ap);
-+
-+ /*
-+  * Resize the buffer as needed...
-+  */
-+
-+  if (len >= linesize)
-+  {
-+    len ++;
-+
-+    if (len < 8192)
-+      len = 8192;
-+    else if (len > 65536)
-+      len = 65536;
-+
-+    line = realloc(line, len);
-+
-+    if (line)
-+      linesize = len;
-+    else
-+    {
-+      cupsFilePrintf(ErrorFile,
-+                     "ERROR: Unable to allocate memory for line - %s\n",
-+                     strerror(errno));
-+      cupsFileFlush(ErrorFile);
-+
-+      return (0);
-+    }
-+
-+    va_start(ap, message);
-+    len = vsnprintf(line, linesize, message, ap);
-+    va_end(ap);
-+  }
-+
-+  if (len >= linesize)
-+    len = linesize - 1;
-+
-+ /*
-+  * Then the log message...
-+  */
-+
-+  cupsFilePuts(ErrorFile, line);
-+
-+ /*
-+  * Then a newline...
-+  */
-+
-+  if (len > 0 && line[len - 1] != '\n')
-+    cupsFilePutChar(ErrorFile, '\n');
-+
-+ /*
-+  * Flush the line to the file and return...
-+  */
-+
-+  cupsFileFlush(ErrorFile);
-+
-+  return (1);
-+}
-+
-+
-+/*
-+ * 'cupsdLogPage()' - Log a page to the page log file.
-+ */
-+
-+int					/* O - 1 on success, 0 on error */
-+cupsdLogPage(cupsd_job_t *job,		/* I - Job being printed */
-+             const char  *page)		/* I - Page being printed */
-+{
-+  ipp_attribute_t *billing,		/* job-billing attribute */
-+                  *hostname;		/* job-originating-host-name attribute */
-+
-+
-+  billing  = ippFindAttribute(job->attrs, "job-billing", IPP_TAG_ZERO);
-+  hostname = ippFindAttribute(job->attrs, "job-originating-host-name",
-+                              IPP_TAG_ZERO);
-+
-+#ifdef HAVE_VSYSLOG
-+ /*
-+  * See if we are logging pages via syslog...
-+  */
-+
-+  if (!strcmp(PageLog, "syslog"))
-+  {
-+    syslog(LOG_INFO, "PAGE %s %s %d %s %s %s", job->printer->name,
-+           job->username ? job->username : "-",
-+           job->id, page, billing ? billing->values[0].string.text : "-",
-+           hostname->values[0].string.text);
-+
-+    return (1);
-+  }
-+#endif /* HAVE_VSYSLOG */
-+
-+ /*
-+  * Not using syslog; check the log file...
-+  */
-+
-+  if (!check_log_file(&PageFile, PageLog))
-+    return (0);
-+
-+ /*
-+  * Print a page log entry of the form:
-+  *
-+  *    printer job-id user [DD/MON/YYYY:HH:MM:SS +TTTT] page num-copies \
-+  *        billing hostname
-+  */
-+
-+  cupsFilePrintf(PageFile, "%s %s %d %s %s %s %s\n", job->printer->name,
-+        	 job->username ? job->username : "-",
-+        	 job->id, cupsdGetDateTime(time(NULL)), page,
-+		 billing ? billing->values[0].string.text : "-",
-+        	 hostname->values[0].string.text);
-+  cupsFileFlush(PageFile);
-+
-+  return (1);
-+}
-+
-+
-+/*
-+ * 'cupsdLogRequest()' - Log an HTTP request in Common Log Format.
-+ */
-+
-+int					/* O - 1 on success, 0 on error */
-+cupsdLogRequest(cupsd_client_t *con,	/* I - Request to log */
-+                http_status_t  code)	/* I - Response code */
-+{
-+  static const char * const states[] =	/* HTTP client states... */
-+		{
-+		  "WAITING",
-+		  "OPTIONS",
-+		  "GET",
-+		  "GET",
-+		  "HEAD",
-+		  "POST",
-+		  "POST",
-+		  "POST",
-+		  "PUT",
-+		  "PUT",
-+		  "DELETE",
-+		  "TRACE",
-+		  "CLOSE",
-+		  "STATUS"
-+		};
-+
-+  /* Do not flood the log with CUPS-Get-Printers requests */
-+  if (con->request && code == HTTP_OK && (
-+	con->request->request.op.operation_id == CUPS_GET_PRINTERS ||
-+	con->request->request.op.operation_id == CUPS_GET_DEFAULT ||
-+	con->request->request.op.operation_id == IPP_GET_PRINTER_ATTRIBUTES))
-+      return (1);
-+
-+#ifdef HAVE_VSYSLOG
-+ /*
-+  * See if we are logging accesses via syslog...
-+  */
-+
-+  if (!strcmp(AccessLog, "syslog"))
-+  {
-+    syslog(LOG_INFO,
-+           "REQUEST %s - %s \"%s %s HTTP/%d.%d\" %d " CUPS_LLFMT " %s %s\n",
-+           con->http.hostname, con->username[0] != '\0' ? con->username : "-",
-+	   states[con->operation], con->uri,
-+	   con->http.version / 100, con->http.version % 100,
-+	   code, CUPS_LLCAST con->bytes,
-+	   con->request ?
-+	       ippOpString(con->request->request.op.operation_id) : "-",
-+	   con->response ?
-+	       ippErrorString(con->response->request.status.status_code) : "-");
-+
-+    return (1);
-+  }
-+#endif /* HAVE_VSYSLOG */
-+
-+ /*
-+  * Not using syslog; check the log file...
-+  */
-+
-+  if (!check_log_file(&AccessFile, AccessLog))
-+    return (0);
-+
-+ /*
-+  * Write a log of the request in "common log format"...
-+  */
-+
-+  cupsFilePrintf(AccessFile,
-+                 "%s - %s %s \"%s %s HTTP/%d.%d\" %d " CUPS_LLFMT " %s %s\n",
-+        	 con->http.hostname, con->username[0] != '\0' ? con->username : "-",
-+		 cupsdGetDateTime(con->start), states[con->operation], con->uri,
-+		 con->http.version / 100, con->http.version % 100,
-+		 code, CUPS_LLCAST con->bytes,
-+		 con->request ?
-+		     ippOpString(con->request->request.op.operation_id) : "-",
-+		 con->response ?
-+		     ippErrorString(con->response->request.status.status_code) :
-+		     "-");
-+
-+  cupsFileFlush(AccessFile);
-+
-+  return (1);
-+}
-+
-+
-+/*
-+ * 'check_log_file()' - Open/rotate a log file if it needs it.
-+ */
-+
-+static int				/* O  - 1 if log file open */
-+check_log_file(cups_file_t **lf,	/* IO - Log file */
-+	       const char  *logname)	/* I  - Log filename */
-+{
-+  char	backname[1024],			/* Backup log filename */
-+	filename[1024],			/* Formatted log filename */
-+	*ptr;				/* Pointer into filename */
-+
-+
-+ /*
-+  * See if we have a log file to check...
-+  */
-+
-+  if (!lf || !logname || !logname[0])
-+    return (1);
-+
-+ /*
-+  * Format the filename as needed...
-+  */
-+
-+  if (!*lf ||
-+      (strncmp(logname, "/dev/", 5) && cupsFileTell(*lf) > MaxLogSize &&
-+       MaxLogSize > 0))
-+  {
-+   /*
-+    * Handle format strings...
-+    */
-+
-+    filename[sizeof(filename) - 1] = '\0';
-+
-+    if (logname[0] != '/')
-+    {
-+      strlcpy(filename, ServerRoot, sizeof(filename));
-+      strlcat(filename, "/", sizeof(filename));
-+    }
-+    else
-+      filename[0] = '\0';
-+
-+    for (ptr = filename + strlen(filename);
-+         *logname && ptr < (filename + sizeof(filename) - 1);
-+	 logname ++)
-+      if (*logname == '%')
-+      {
-+       /*
-+        * Format spec...
-+	*/
-+
-+        logname ++;
-+	if (*logname == 's')
-+	{
-+	 /*
-+	  * Insert the server name...
-+	  */
-+
-+	  strlcpy(ptr, ServerName, sizeof(filename) - (ptr - filename));
-+	  ptr += strlen(ptr);
-+	}
-+        else
-+	{
-+	 /*
-+	  * Otherwise just insert the character...
-+	  */
-+
-+	  *ptr++ = *logname;
-+	}
-+      }
-+      else
-+	*ptr++ = *logname;
-+
-+    *ptr = '\0';
-+  }
-+
-+ /*
-+  * See if the log file is open...
-+  */
-+
-+  if (!*lf)
-+  {
-+   /*
-+    * Nope, open the log file...
-+    */
-+
-+    if ((*lf = cupsFileOpen(filename, "a")) == NULL)
-+    {
-+      syslog(LOG_ERR, "Unable to open log file \"%s\" - %s", filename,
-+             strerror(errno));
-+
-+      return (0);
-+    }
-+
-+    if (strncmp(filename, "/dev/", 5))
-+    {
-+     /*
-+      * Change ownership and permissions of non-device logs...
-+      */
-+
-+      fchown(cupsFileNumber(*lf), RunUser, Group);
-+      fchmod(cupsFileNumber(*lf), LogFilePerm);
-+    }
-+  }
-+
-+ /*
-+  * Do we need to rotate the log?
-+  */
-+
-+  if (strncmp(logname, "/dev/", 5) && cupsFileTell(*lf) > MaxLogSize &&
-+      MaxLogSize > 0)
-+  {
-+   /*
-+    * Rotate log file...
-+    */
-+
-+    cupsFileClose(*lf);
-+
-+    strcpy(backname, filename);
-+    strlcat(backname, ".O", sizeof(backname));
-+
-+    unlink(backname);
-+    rename(filename, backname);
-+
-+    if ((*lf = cupsFileOpen(filename, "a")) == NULL)
-+    {
-+      syslog(LOG_ERR, "Unable to open log file \"%s\" - %s", filename,
-+             strerror(errno));
-+
-+      return (0);
-+    }
-+
-+   /*
-+    * Change ownership and permissions of non-device logs...
-+    */
-+
-+    fchown(cupsFileNumber(*lf), RunUser, Group);
-+    fchmod(cupsFileNumber(*lf), LogFilePerm);
-+  }
-+
-+  return (1);
-+}
-+
-+
-+/*
-+ * End of "$Id: log.c 6027 2006-10-11 21:04:58Z mike $".
-+ */
 diff -urNad cupsys-1.2.8~/scheduler/printers.c cupsys-1.2.8/scheduler/printers.c
 --- cupsys-1.2.8~/scheduler/printers.c	2006-09-19 21:11:08.000000000 +0100
-+++ cupsys-1.2.8/scheduler/printers.c	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/scheduler/printers.c	2007-03-14 15:53:31.000000000 +0000
 @@ -1286,6 +1286,7 @@
    time_t		curtime;	/* Current time */
    struct tm		*curdate;	/* Current date */
@@ -13005,7 +3271,7 @@
  
 diff -urNad cupsys-1.2.8~/scheduler/testlpd.c cupsys-1.2.8/scheduler/testlpd.c
 --- cupsys-1.2.8~/scheduler/testlpd.c	2006-08-23 20:39:39.000000000 +0100
-+++ cupsys-1.2.8/scheduler/testlpd.c	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/scheduler/testlpd.c	2007-03-14 15:53:31.000000000 +0000
 @@ -184,6 +184,11 @@
      status = status_long(cupslpd_stdin[1], cupslpd_stdout[0], dest, opargs);
    else if (!strcmp(op, "status-short"))
@@ -13049,7 +3315,7 @@
    if ((status = do_command(outfd, infd, command)) != 0)
 diff -urNad cupsys-1.2.8~/systemv/cupstestppd.c cupsys-1.2.8/systemv/cupstestppd.c
 --- cupsys-1.2.8~/systemv/cupstestppd.c	2006-09-05 21:45:47.000000000 +0100
-+++ cupsys-1.2.8/systemv/cupstestppd.c	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/systemv/cupstestppd.c	2007-03-14 15:53:31.000000000 +0000
 @@ -3,7 +3,7 @@
   *
   *   PPD test program for the Common UNIX Printing System (CUPS).
@@ -13297,7 +3563,7 @@
   */
 diff -urNad cupsys-1.2.8~/templates/fr/add-class.tmpl cupsys-1.2.8/templates/fr/add-class.tmpl
 --- cupsys-1.2.8~/templates/fr/add-class.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/add-class.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/add-class.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -31,36 +31,3 @@
  </TABLE>
  
@@ -13337,7 +3603,7 @@
 -</FORM>
 diff -urNad cupsys-1.2.8~/templates/fr/add-printer.tmpl cupsys-1.2.8/templates/fr/add-printer.tmpl
 --- cupsys-1.2.8~/templates/fr/add-printer.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/add-printer.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/add-printer.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,50 +1,23 @@
  <FORM METHOD="POST" ACTION="/admin">
  <INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
@@ -13395,7 +3661,7 @@
  <TR>
 diff -urNad cupsys-1.2.8~/templates/fr/admin.tmpl cupsys-1.2.8/templates/fr/admin.tmpl
 --- cupsys-1.2.8~/templates/fr/admin.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/admin.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/admin.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,88 +1,5 @@
  <TABLE CELLPADDING="0" CELLSPACING="0" WIDTH="100%" SUMMARY="Tâches d'administration">
 -<TR><TD VALIGN="TOP" NOWRAP>
@@ -13505,7 +3771,7 @@
  <INPUT TYPE="CHECKBOX" NAME="USER_CANCEL_ANY" {?user_cancel_any}> Autoriser les
 diff -urNad cupsys-1.2.8~/templates/fr/choose-device.tmpl cupsys-1.2.8/templates/fr/choose-device.tmpl
 --- cupsys-1.2.8~/templates/fr/choose-device.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/choose-device.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/choose-device.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -24,29 +24,3 @@
  </TABLE>
  
@@ -13538,7 +3804,7 @@
 -</FORM>
 diff -urNad cupsys-1.2.8~/templates/fr/choose-make.tmpl cupsys-1.2.8/templates/fr/choose-make.tmpl
 --- cupsys-1.2.8~/templates/fr/choose-make.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/choose-make.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/choose-make.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -40,45 +40,3 @@
  </TABLE>
  
@@ -13587,7 +3853,7 @@
 -</FORM>
 diff -urNad cupsys-1.2.8~/templates/fr/choose-model.tmpl cupsys-1.2.8/templates/fr/choose-model.tmpl
 --- cupsys-1.2.8~/templates/fr/choose-model.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/choose-model.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/choose-model.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -32,37 +32,3 @@
  </TABLE>
  
@@ -13628,7 +3894,7 @@
 -</FORM>
 diff -urNad cupsys-1.2.8~/templates/fr/choose-serial.tmpl cupsys-1.2.8/templates/fr/choose-serial.tmpl
 --- cupsys-1.2.8~/templates/fr/choose-serial.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/choose-serial.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/choose-serial.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -45,50 +45,3 @@
  </TABLE>
  
@@ -13682,7 +3948,7 @@
 -</FORM>
 diff -urNad cupsys-1.2.8~/templates/fr/choose-uri.tmpl cupsys-1.2.8/templates/fr/choose-uri.tmpl
 --- cupsys-1.2.8~/templates/fr/choose-uri.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/choose-uri.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/choose-uri.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -40,45 +40,3 @@
  </TABLE>
  
@@ -13731,13 +3997,13 @@
 -</FORM>
 diff -urNad cupsys-1.2.8~/templates/fr/class-added.tmpl cupsys-1.2.8/templates/fr/class-added.tmpl
 --- cupsys-1.2.8~/templates/fr/class-added.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/class-added.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/class-added.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,2 +1 @@
  <P>La classe <A HREF="/classes/{printer_name}">{printer_name}</A> a bien été ajoutée.
 -<P>La classe <A HREF="/classes/{printer_name}">{printer_name}</A> a bien été ajoutée.
 diff -urNad cupsys-1.2.8~/templates/fr/class-confirm.tmpl cupsys-1.2.8/templates/fr/class-confirm.tmpl
 --- cupsys-1.2.8~/templates/fr/class-confirm.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/class-confirm.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/class-confirm.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -5,10 +5,3 @@
  HREF="/admin?op=delete-class&printer_name={printer_name}&confirm=yes"><IMG
  SRC="/images/button-delete-class.gif" ALT="Supprimer la classe"
@@ -13751,31 +4017,31 @@
 -CLASS="button"></A></P>
 diff -urNad cupsys-1.2.8~/templates/fr/class-deleted.tmpl cupsys-1.2.8/templates/fr/class-deleted.tmpl
 --- cupsys-1.2.8~/templates/fr/class-deleted.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/class-deleted.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/class-deleted.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,2 +1 @@
  <P>La classe {printer_name} a bien été supprimée.
 -<P>La classe {printer_name} a bien été supprimée.
 diff -urNad cupsys-1.2.8~/templates/fr/class-jobs-header.tmpl cupsys-1.2.8/templates/fr/class-jobs-header.tmpl
 --- cupsys-1.2.8~/templates/fr/class-jobs-header.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/class-jobs-header.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/class-jobs-header.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,2 +1 @@
  <H3 CLASS="title">Tâches d'impression</H3>
 -<H3 CLASS="title">Tâches d'impression</H3>
 diff -urNad cupsys-1.2.8~/templates/fr/class-modified.tmpl cupsys-1.2.8/templates/fr/class-modified.tmpl
 --- cupsys-1.2.8~/templates/fr/class-modified.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/class-modified.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/class-modified.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,2 +1 @@
  <P>La classe <A HREF="/classes/{printer_name}">{printer_name}</A> a bien été modifiée.
 -<P>La classe <A HREF="/classes/{printer_name}">{printer_name}</A> a bien été modifiée.
 diff -urNad cupsys-1.2.8~/templates/fr/classes-header.tmpl cupsys-1.2.8/templates/fr/classes-header.tmpl
 --- cupsys-1.2.8~/templates/fr/classes-header.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/classes-header.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/classes-header.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,2 +1 @@
  <P ALIGN="CENTER">{total=0?Aucune classe:Affichage de {#printer_name} classe{#printer_name=1?:s} sur {total}}.</P>
 -<P ALIGN="CENTER">{total=0?Aucune classe:Affichage de {#printer_name} classe{#printer_name=1?:s} sur {total}}.</P>
 diff -urNad cupsys-1.2.8~/templates/fr/classes.tmpl cupsys-1.2.8/templates/fr/classes.tmpl
 --- cupsys-1.2.8~/templates/fr/classes.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/classes.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/classes.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -52,57 +52,3 @@
  </TR>
  </TABLE>
@@ -13836,7 +4102,7 @@
 -}}
 diff -urNad cupsys-1.2.8~/templates/fr/edit-config.tmpl.in cupsys-1.2.8/templates/fr/edit-config.tmpl.in
 --- cupsys-1.2.8~/templates/fr/edit-config.tmpl.in	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/edit-config.tmpl.in	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/edit-config.tmpl.in	2007-03-14 15:53:31.000000000 +0000
 @@ -9,6 +9,7 @@
  "\\n" +
  "# Groupe des utilisateurs UNIX pour les administrateurs CUPS...\\n" +
@@ -13947,7 +4213,7 @@
  "# S'authentifier par défaut via les comptes UNIX...\\n" +
 diff -urNad cupsys-1.2.8~/templates/fr/error-op.tmpl cupsys-1.2.8/templates/fr/error-op.tmpl
 --- cupsys-1.2.8~/templates/fr/error-op.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/error-op.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/error-op.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,6 +1,3 @@
  <P>Erreur :</P>
  
@@ -13957,7 +4223,7 @@
 -<BLOCKQUOTE>Opération inconnue : "{op}"!</BLOCKQUOTE>
 diff -urNad cupsys-1.2.8~/templates/fr/error.tmpl cupsys-1.2.8/templates/fr/error.tmpl
 --- cupsys-1.2.8~/templates/fr/error.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/error.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/error.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,6 +1,3 @@
  <P>{?message?{message}:Erreur :}</P>
  
@@ -13967,7 +4233,7 @@
 -<BLOCKQUOTE>{error}</BLOCKQUOTE>
 diff -urNad cupsys-1.2.8~/templates/fr/header.tmpl.in cupsys-1.2.8/templates/fr/header.tmpl.in
 --- cupsys-1.2.8~/templates/fr/header.tmpl.in	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/header.tmpl.in	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/header.tmpl.in	2007-03-14 15:53:31.000000000 +0000
 @@ -61,66 +61,3 @@
  <TR CLASS="page">
  <TD WIDTH="15">&nbsp;</TD>
@@ -14037,7 +4303,7 @@
 -<TD COLSPAN="2" WIDTH="100%" STYLE="height: 100%;" VALIGN="TOP" CLASS="page">
 diff -urNad cupsys-1.2.8~/templates/fr/help-header.tmpl cupsys-1.2.8/templates/fr/help-header.tmpl
 --- cupsys-1.2.8~/templates/fr/help-header.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/help-header.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/help-header.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -50,55 +50,3 @@
  utilisateurs, des réponses aux questions fréquentes, et un formulaire pour
  soumettre des rapports de <I>bug</I> ou des demandes pour de nouvelles
@@ -14096,7 +4362,7 @@
 -fonctionnalités.</P>}
 diff -urNad cupsys-1.2.8~/templates/fr/help-printable.tmpl cupsys-1.2.8/templates/fr/help-printable.tmpl
 --- cupsys-1.2.8~/templates/fr/help-printable.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/help-printable.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/help-printable.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -9,14 +9,3 @@
  <BODY>
  
@@ -14114,19 +4380,19 @@
 -<H1>{HELPTITLE}</H1>
 diff -urNad cupsys-1.2.8~/templates/fr/job-cancel.tmpl cupsys-1.2.8/templates/fr/job-cancel.tmpl
 --- cupsys-1.2.8~/templates/fr/job-cancel.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/job-cancel.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/job-cancel.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,2 +1 @@
  <P><A HREF="{job_printer_uri}">La tâche n°{job_id}</A> a été annulée.
 -<P><A HREF="{job_printer_uri}">La tâche n°{job_id}</A> a été annulée.
 diff -urNad cupsys-1.2.8~/templates/fr/job-hold.tmpl cupsys-1.2.8/templates/fr/job-hold.tmpl
 --- cupsys-1.2.8~/templates/fr/job-hold.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/job-hold.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/job-hold.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,2 +1 @@
  <P><A HREF="{job_printer_uri}">La tâche n°{job_id}</A> est retenue en attente.
 -<P><A HREF="{job_printer_uri}">La tâche n°{job_id}</A> est retenue en attente.
 diff -urNad cupsys-1.2.8~/templates/fr/job-move.tmpl cupsys-1.2.8/templates/fr/job-move.tmpl
 --- cupsys-1.2.8~/templates/fr/job-move.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/job-move.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/job-move.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -20,25 +20,3 @@
  </TABLE>
  
@@ -14155,7 +4421,7 @@
 -</FORM>
 diff -urNad cupsys-1.2.8~/templates/fr/job-moved.tmpl cupsys-1.2.8/templates/fr/job-moved.tmpl
 --- cupsys-1.2.8~/templates/fr/job-moved.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/job-moved.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/job-moved.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,4 +1,2 @@
  <P>{job_id?<A HREF="/jobs/{job_id}">La tâche n°{job_id}</A>:Toutes les tâches}
  ont été transférées vers <A HREF="{job_printer_uri}">{job_printer_name}</A>.</P>
@@ -14163,19 +4429,19 @@
 -ont été transférées vers <A HREF="{job_printer_uri}">{job_printer_name}</A>.</P>
 diff -urNad cupsys-1.2.8~/templates/fr/job-release.tmpl cupsys-1.2.8/templates/fr/job-release.tmpl
 --- cupsys-1.2.8~/templates/fr/job-release.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/job-release.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/job-release.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,2 +1 @@
  <P><A HREF="{job_printer_uri}">La tâche n°{job_id}</A> a été libérée pour l'impression.
 -<P><A HREF="{job_printer_uri}">La tâche n°{job_id}</A> a été libérée pour l'impression.
 diff -urNad cupsys-1.2.8~/templates/fr/job-restart.tmpl cupsys-1.2.8/templates/fr/job-restart.tmpl
 --- cupsys-1.2.8~/templates/fr/job-restart.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/job-restart.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/job-restart.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,2 +1 @@
  <P><A HREF="{job_printer_uri}">La tâche n°{job_id}</A> a été redémarrée.
 -<P><A HREF="{job_printer_uri}">La tâche n°{job_id}</A> a été redémarrée.
 diff -urNad cupsys-1.2.8~/templates/fr/jobs-header.tmpl cupsys-1.2.8/templates/fr/jobs-header.tmpl
 --- cupsys-1.2.8~/templates/fr/jobs-header.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/jobs-header.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/jobs-header.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -14,19 +14,3 @@
  
  <P ALIGN="CENTER">{total=0?Aucune tâche:Affichage de {#job_id}
@@ -14198,7 +4464,7 @@
 -tâche{#job_id=1?:s} {?which_jobs=?en cours:{which_jobs=all?:terminée{#job_id=1?:s}}} sur {total}}.</P>
 diff -urNad cupsys-1.2.8~/templates/fr/jobs.tmpl cupsys-1.2.8/templates/fr/jobs.tmpl
 --- cupsys-1.2.8~/templates/fr/jobs.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/jobs.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/jobs.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -40,45 +40,3 @@
  }
  </TABLE>
@@ -14247,7 +4513,7 @@
 -}
 diff -urNad cupsys-1.2.8~/templates/fr/maintenance.tmpl cupsys-1.2.8/templates/fr/maintenance.tmpl
 --- cupsys-1.2.8~/templates/fr/maintenance.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/maintenance.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/maintenance.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,4 +1,2 @@
  <P>Les commandes de maintenance ont été envoyées ; l'identifiant de tâche est <A
  HREF="/printers/{printer_name}"> {printer_name}-{job_id}</A>.</P>
@@ -14255,7 +4521,7 @@
 -HREF="/printers/{printer_name}"> {printer_name}-{job_id}</A>.</P>
 diff -urNad cupsys-1.2.8~/templates/fr/modify-class.tmpl cupsys-1.2.8/templates/fr/modify-class.tmpl
 --- cupsys-1.2.8~/templates/fr/modify-class.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/modify-class.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/modify-class.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -32,37 +32,3 @@
  </TABLE>
  
@@ -14296,7 +4562,7 @@
 -</FORM>
 diff -urNad cupsys-1.2.8~/templates/fr/modify-printer.tmpl cupsys-1.2.8/templates/fr/modify-printer.tmpl
 --- cupsys-1.2.8~/templates/fr/modify-printer.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/modify-printer.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/modify-printer.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -27,32 +27,3 @@
  </TABLE>
  
@@ -14332,13 +4598,13 @@
 -</FORM>
 diff -urNad cupsys-1.2.8~/templates/fr/norestart.tmpl cupsys-1.2.8/templates/fr/norestart.tmpl
 --- cupsys-1.2.8~/templates/fr/norestart.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/norestart.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/norestart.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,2 +1 @@
  <p>Le serveur n'a pas été redémarré parce que la configuration n'a pas été modifiée...</p>
 -<p>Le serveur n'a pas été redémarré parce que la configuration n'a pas été modifiée...</p>
 diff -urNad cupsys-1.2.8~/templates/fr/option-boolean.tmpl cupsys-1.2.8/templates/fr/option-boolean.tmpl
 --- cupsys-1.2.8~/templates/fr/option-boolean.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/option-boolean.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/option-boolean.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -5,10 +5,3 @@
  {[choices]<INPUT TYPE="RADIO" NAME="{keyword}" {choices={defchoice}?CHECKED:} VALUE="{choices}">{text}}
  </TD>
@@ -14352,7 +4618,7 @@
 -</TR>
 diff -urNad cupsys-1.2.8~/templates/fr/option-conflict.tmpl cupsys-1.2.8/templates/fr/option-conflict.tmpl
 --- cupsys-1.2.8~/templates/fr/option-conflict.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/option-conflict.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/option-conflict.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -5,10 +5,3 @@
  }</UL>
  
@@ -14366,7 +4632,7 @@
 -<P>Veuillez modifier une ou plusieurs des ces options pour résoudre les conflits.</P>
 diff -urNad cupsys-1.2.8~/templates/fr/option-header.tmpl cupsys-1.2.8/templates/fr/option-header.tmpl
 --- cupsys-1.2.8~/templates/fr/option-header.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/option-header.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/option-header.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,6 +1,3 @@
  <H2 CLASS="title">{printer_name} : {group}</H2>
  
@@ -14376,7 +4642,7 @@
 -<TABLE>
 diff -urNad cupsys-1.2.8~/templates/fr/option-pickmany.tmpl cupsys-1.2.8/templates/fr/option-pickmany.tmpl
 --- cupsys-1.2.8~/templates/fr/option-pickmany.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/option-pickmany.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/option-pickmany.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -5,10 +5,3 @@
  {[choices]<OPTION {choices={defchoice}?SELECTED:} VALUE="{choices}">{text}}
  </SELECT></TD>
@@ -14390,7 +4656,7 @@
 -</TR>
 diff -urNad cupsys-1.2.8~/templates/fr/option-pickone.tmpl cupsys-1.2.8/templates/fr/option-pickone.tmpl
 --- cupsys-1.2.8~/templates/fr/option-pickone.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/option-pickone.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/option-pickone.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -5,10 +5,3 @@
  {[choices]<OPTION {choices={defchoice}?SELECTED:} VALUE="{choices}">{text}}
  </SELECT></TD>
@@ -14404,7 +4670,7 @@
 -</TR>
 diff -urNad cupsys-1.2.8~/templates/fr/option-trailer.tmpl cupsys-1.2.8/templates/fr/option-trailer.tmpl
 --- cupsys-1.2.8~/templates/fr/option-trailer.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/option-trailer.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/option-trailer.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -4,9 +4,3 @@
  ALT="Définir les options de l'imprimante"></TD>
  </TR>
@@ -14417,7 +4683,7 @@
 -</TABLE>
 diff -urNad cupsys-1.2.8~/templates/fr/pager.tmpl cupsys-1.2.8/templates/fr/pager.tmpl
 --- cupsys-1.2.8~/templates/fr/pager.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/pager.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/pager.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -9,14 +9,3 @@
          SRC="/images/button-show-next.gif" ALT="Montrer les suivantes" CLASS="button"></A>:&nbsp;}</TD>
  </TR>
@@ -14435,7 +4701,7 @@
 -</TABLE>
 diff -urNad cupsys-1.2.8~/templates/fr/printer-accept.tmpl cupsys-1.2.8/templates/fr/printer-accept.tmpl
 --- cupsys-1.2.8~/templates/fr/printer-accept.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/printer-accept.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/printer-accept.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,6 +1,3 @@
  <P>{is_class?Class:Printer} <A
  HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
@@ -14445,19 +4711,19 @@
 -accepte désormais les tâches d'impression.</P>
 diff -urNad cupsys-1.2.8~/templates/fr/printer-added.tmpl cupsys-1.2.8/templates/fr/printer-added.tmpl
 --- cupsys-1.2.8~/templates/fr/printer-added.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/printer-added.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/printer-added.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,2 +1 @@
  <P>L'imprimante <A HREF="/printers/{printer_name}">{printer_name}</A> a bien été ajoutée.
 -<P>L'imprimante <A HREF="/printers/{printer_name}">{printer_name}</A> a bien été ajoutée.
 diff -urNad cupsys-1.2.8~/templates/fr/printer-configured.tmpl cupsys-1.2.8/templates/fr/printer-configured.tmpl
 --- cupsys-1.2.8~/templates/fr/printer-configured.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/printer-configured.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/printer-configured.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,2 +1 @@
  <P>L'imprimante <A HREF="/printers/{printer_name}">{printer_name}</A> a bien été configurée.
 -<P>L'imprimante <A HREF="/printers/{printer_name}">{printer_name}</A> a bien été configurée.
 diff -urNad cupsys-1.2.8~/templates/fr/printer-confirm.tmpl cupsys-1.2.8/templates/fr/printer-confirm.tmpl
 --- cupsys-1.2.8~/templates/fr/printer-confirm.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/printer-confirm.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/printer-confirm.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -5,10 +5,3 @@
  HREF="/admin?op=delete-printer&printer_name={printer_name}&confirm=yes"><IMG
  SRC="/images/button-delete-printer.gif" ALT="Supprimer l'imprimante"
@@ -14471,7 +4737,7 @@
 -CLASS="button"></A></P>
 diff -urNad cupsys-1.2.8~/templates/fr/printer-default.tmpl cupsys-1.2.8/templates/fr/printer-default.tmpl
 --- cupsys-1.2.8~/templates/fr/printer-default.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/printer-default.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/printer-default.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -5,10 +5,3 @@
  <BLOCKQUOTE><B>NB:</B> Pour un utilisateur qui a défini un paramètre par défaut
  via la commande <TT>lpoptions</TT>, le paramètre du serveur sera
@@ -14485,25 +4751,25 @@
 -ignoré.</BLOCKQUOTE>
 diff -urNad cupsys-1.2.8~/templates/fr/printer-deleted.tmpl cupsys-1.2.8/templates/fr/printer-deleted.tmpl
 --- cupsys-1.2.8~/templates/fr/printer-deleted.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/printer-deleted.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/printer-deleted.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,2 +1 @@
  <P>L'imprimante {printer_name} a bien été supprimée.
 -<P>L'imprimante {printer_name} a bien été supprimée.
 diff -urNad cupsys-1.2.8~/templates/fr/printer-jobs-header.tmpl cupsys-1.2.8/templates/fr/printer-jobs-header.tmpl
 --- cupsys-1.2.8~/templates/fr/printer-jobs-header.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/printer-jobs-header.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/printer-jobs-header.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,2 +1 @@
  <H3 CLASS="title">Tâches d'impression</H3>
 -<H3 CLASS="title">Tâches d'impression</H3>
 diff -urNad cupsys-1.2.8~/templates/fr/printer-modified.tmpl cupsys-1.2.8/templates/fr/printer-modified.tmpl
 --- cupsys-1.2.8~/templates/fr/printer-modified.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/printer-modified.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/printer-modified.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,2 +1 @@
  <P>L'imprimante <A HREF="/printers/{printer_name}">{printer_name}</A> a bien été modifiée.
 -<P>L'imprimante <A HREF="/printers/{printer_name}">{printer_name}</A> a bien été modifiée.
 diff -urNad cupsys-1.2.8~/templates/fr/printer-purge.tmpl cupsys-1.2.8/templates/fr/printer-purge.tmpl
 --- cupsys-1.2.8~/templates/fr/printer-purge.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/printer-purge.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/printer-purge.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,6 +1,3 @@
  <P>{is_class?La classe:L'imprimante} <A
  HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
@@ -14513,7 +4779,7 @@
 -a été nettoyée de toute tâche... d'impression !</P>
 diff -urNad cupsys-1.2.8~/templates/fr/printer-reject.tmpl cupsys-1.2.8/templates/fr/printer-reject.tmpl
 --- cupsys-1.2.8~/templates/fr/printer-reject.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/printer-reject.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/printer-reject.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,6 +1,3 @@
  <P>{is_class?La classe:L'imprimante} <A
  HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
@@ -14523,7 +4789,7 @@
 -n'accepte plus les tâches d'impression.</P>
 diff -urNad cupsys-1.2.8~/templates/fr/printer-start.tmpl cupsys-1.2.8/templates/fr/printer-start.tmpl
 --- cupsys-1.2.8~/templates/fr/printer-start.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/printer-start.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/printer-start.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,6 +1,3 @@
  <P>{is_class?La classe:L'imprimante} <A
  HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
@@ -14533,7 +4799,7 @@
 -a été démarrée.</P>
 diff -urNad cupsys-1.2.8~/templates/fr/printer-stop.tmpl cupsys-1.2.8/templates/fr/printer-stop.tmpl
 --- cupsys-1.2.8~/templates/fr/printer-stop.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/printer-stop.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/printer-stop.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,6 +1,3 @@
  <P>{is_class?La classe:L'imprimante} <A
  HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
@@ -14543,13 +4809,13 @@
 -a été arrêtée.</P>
 diff -urNad cupsys-1.2.8~/templates/fr/printers-header.tmpl cupsys-1.2.8/templates/fr/printers-header.tmpl
 --- cupsys-1.2.8~/templates/fr/printers-header.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/printers-header.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/printers-header.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,2 +1 @@
  <P ALIGN="CENTER">{total=0?Aucune imprimante:Affichage de {#printer_name} imprimante{#printer_name=1?:s}} sur {total}.</P>
 -<P ALIGN="CENTER">{total=0?Aucune imprimante:Affichage de {#printer_name} imprimante{#printer_name=1?:s}} sur {total}.</P>
 diff -urNad cupsys-1.2.8~/templates/fr/printers.tmpl cupsys-1.2.8/templates/fr/printers.tmpl
 --- cupsys-1.2.8~/templates/fr/printers.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/printers.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/printers.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -64,69 +64,3 @@
  </TR>
  </TABLE>
@@ -14622,13 +4888,13 @@
 -}}
 diff -urNad cupsys-1.2.8~/templates/fr/restart.tmpl cupsys-1.2.8/templates/fr/restart.tmpl
 --- cupsys-1.2.8~/templates/fr/restart.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/restart.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/restart.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,2 +1 @@
  <p>Attendez s'il vous plaît, que le serveur redémarre...</p>
 -<p>Attendez s'il vous plaît, que le serveur redémarre...</p>
 diff -urNad cupsys-1.2.8~/templates/fr/samba-export.tmpl cupsys-1.2.8/templates/fr/samba-export.tmpl
 --- cupsys-1.2.8~/templates/fr/samba-export.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/samba-export.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/samba-export.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -51,56 +51,3 @@
  </TABLE>
  
@@ -14688,13 +4954,13 @@
 -</FORM>
 diff -urNad cupsys-1.2.8~/templates/fr/samba-exported.tmpl cupsys-1.2.8/templates/fr/samba-exported.tmpl
 --- cupsys-1.2.8~/templates/fr/samba-exported.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/samba-exported.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/samba-exported.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,2 +1 @@
  <P>Les imprimantes ont bien été exportées vers SAMBA.</P>
 -<P>Les imprimantes ont bien été exportées vers SAMBA.</P>
 diff -urNad cupsys-1.2.8~/templates/fr/search.tmpl cupsys-1.2.8/templates/fr/search.tmpl
 --- cupsys-1.2.8~/templates/fr/search.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/search.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/search.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -11,16 +11,3 @@
  SRC="/images/button-clear.gif" ALT="Nettoyer" CLASS="button"></A></P>
  
@@ -14714,7 +4980,7 @@
 -</FORM>
 diff -urNad cupsys-1.2.8~/templates/fr/set-printer-options-header.tmpl cupsys-1.2.8/templates/fr/set-printer-options-header.tmpl
 --- cupsys-1.2.8~/templates/fr/set-printer-options-header.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/set-printer-options-header.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/set-printer-options-header.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,6 +1,3 @@
  <FORM METHOD="POST" ACTION="/admin">
  <INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
@@ -14724,13 +4990,13 @@
 -<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
 diff -urNad cupsys-1.2.8~/templates/fr/set-printer-options-trailer.tmpl cupsys-1.2.8/templates/fr/set-printer-options-trailer.tmpl
 --- cupsys-1.2.8~/templates/fr/set-printer-options-trailer.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/set-printer-options-trailer.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/set-printer-options-trailer.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,2 +1 @@
  </FORM>
 -</FORM>
 diff -urNad cupsys-1.2.8~/templates/fr/test-page.tmpl cupsys-1.2.8/templates/fr/test-page.tmpl
 --- cupsys-1.2.8~/templates/fr/test-page.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/test-page.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/test-page.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -1,4 +1,2 @@
  <P>La page de test a été envoyée ; l'identifiant de la tâche est <A HREF="/{SECTION}/{printer_name}">
  {printer_name}-{job_id}</A>.</P>
@@ -14738,7 +5004,7 @@
 -{printer_name}-{job_id}</A>.</P>
 diff -urNad cupsys-1.2.8~/templates/fr/trailer.tmpl cupsys-1.2.8/templates/fr/trailer.tmpl
 --- cupsys-1.2.8~/templates/fr/trailer.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/trailer.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/trailer.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -19,24 +19,3 @@
  </TABLE>
  </BODY>
@@ -14766,7 +5032,7 @@
 -</HTML>
 diff -urNad cupsys-1.2.8~/templates/fr/users.tmpl cupsys-1.2.8/templates/fr/users.tmpl
 --- cupsys-1.2.8~/templates/fr/users.tmpl	2007-02-05 20:25:50.000000000 +0000
-+++ cupsys-1.2.8/templates/fr/users.tmpl	2007-03-13 15:02:07.000000000 +0000
++++ cupsys-1.2.8/templates/fr/users.tmpl	2007-03-14 15:53:31.000000000 +0000
 @@ -24,29 +24,3 @@
  </TABLE>
  



More information about the Pkg-cups-devel mailing list