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

Martin Pitt mpitt at alioth.debian.org
Wed Mar 14 09:25:29 CET 2007


Author: mpitt
Date: Wed Mar 14 08:25:28 2007
New Revision: 440

Added:
   cupsys/branches/cups-1.2-ubuntu/debian/patches/98_search_mime_files_in_usr_share.dpatch
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/00list
   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: Assure that special permissions of lpd backend
  are always correctly set for the link in /usr/lib/cups/backend (closes:
  LP#91382).
* 98_search_mime_files_in_usr_share.dpatch: Let CUPS also search for
  *.types and *.convs files in /usr/share/cups/mime. This way packages can
  provide *.types and *.convs files which do not get considered as conffiles
  (All files in /etc get considered as conffiles, closes: LP#36532).
* 96_more-bug-fixes-between-cups-1.2.8-1.2.9.dpatch: Keep up with upstream
  bug fixes:
   o cupsd crash in get_jobs: In get_jobs when my-jobs is set, we compare 
     the job username before it is loaded (upstream STR #2288).
   o Fixed messed-up french translation (upstream STR #2287).
   o The scheduler's openssl certificate generation code was
     broken on some platforms (upstream STR #2282).
   o The scheduler's log rotation check for devices was
     broken (upstream STR #2278).
   o The LPD mini-daemon did not handle the document-format
     option correctly (upstream STR #2266).

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	Wed Mar 14 08:25:28 2007
@@ -1,3 +1,26 @@
+cupsys (1.2.8-0ubuntu5) feisty; urgency=low
+
+  * debian/cupsys.postinst: Assure that special permissions of lpd backend
+    are always correctly set for the link in /usr/lib/cups/backend (closes:
+    LP#91382).
+  * 98_search_mime_files_in_usr_share.dpatch: Let CUPS also search for
+    *.types and *.convs files in /usr/share/cups/mime. This way packages can
+    provide *.types and *.convs files which do not get considered as conffiles
+    (All files in /etc get considered as conffiles, closes: LP#36532).
+  * 96_more-bug-fixes-between-cups-1.2.8-1.2.9.dpatch: Keep up with upstream
+    bug fixes:
+     o cupsd crash in get_jobs: In get_jobs when my-jobs is set, we compare 
+       the job username before it is loaded (upstream STR #2288).
+     o Fixed messed-up french translation (upstream STR #2287).
+     o The scheduler's openssl certificate generation code was
+       broken on some platforms (upstream STR #2282).
+     o The scheduler's log rotation check for devices was
+       broken (upstream STR #2278).
+     o The LPD mini-daemon did not handle the document-format
+       option correctly (upstream STR #2266).
+
+ -- Till Kamppeter <till.kamppeter at gmail.com>  Mon, 12 Mar 2007 15:22:06 +0000
+
 cupsys (1.2.8-0ubuntu4) feisty; urgency=low
 
   * debian/cupsys.postinst: (De)activate backends also if the user initially

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	Wed Mar 14 08:25:28 2007
@@ -140,6 +140,14 @@
 	    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/
+	if [ -e /usr/lib/cups/backend/lpd ]; then
+	    chown root:lp /usr/lib/cups/backend/lpd
+	    chmod 4754 /usr/lib/cups/backend/lpd
+	fi
+
 	# In cupsys 1.2.8-0ubuntu3 the defaults for the active backends
 	# changed. snmp, scsi, and serial got added. So activate these
 	# backends.

Modified: cupsys/branches/cups-1.2-ubuntu/debian/patches/00list
==============================================================================
--- cupsys/branches/cups-1.2-ubuntu/debian/patches/00list	(original)
+++ cupsys/branches/cups-1.2-ubuntu/debian/patches/00list	Wed Mar 14 08:25:28 2007
@@ -37,6 +37,7 @@
 92_texttops-prettyprint-crash.dpatch
 94_doc-port-in-client-conf.dpatch
 96_more-bug-fixes-between-cups-1.2.8-1.2.9.dpatch
+98_search_mime_files_in_usr_share.dpatch
 ubuntu-disable-browsing.dpatch
 ubuntu-external-pam-helper.dpatch
 ubuntu-default-error-policy-retry-job.dpatch

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	Wed Mar 14 08:25:28 2007
@@ -5,9 +5,26 @@
 ## DP: No description.
 
 @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
+@@ -30,11 +30,11 @@
+ if test x$enable_largefile != xno; then
+ 	LARGEFILE="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE"
+ 
+-	if test $ac_cv_sys_large_files = 1; then
++	if test x$ac_cv_sys_large_files = x1; then
+ 		LARGEFILE="$LARGEFILE -D_LARGE_FILES"
+ 	fi
+ 
+-	if test $ac_cv_sys_file_offset_bits = 64; then
++	if test x$ac_cv_sys_file_offset_bits = x64; then
+ 		LARGEFILE="$LARGEFILE -D_FILE_OFFSET_BITS=64"
+ 	fi
+ 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-11 17:45:03.000000000 +0000
++++ cupsys-1.2.8/cups/file.c	2007-03-13 15:02:07.000000000 +0000
 @@ -508,7 +508,7 @@
    */
  
@@ -50,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-11 17:45:03.000000000 +0000
++++ cupsys-1.2.8/cups/options.c	2007-03-13 15:02:07.000000000 +0000
 @@ -3,7 +3,7 @@
   *
   *   Option routines for the Common UNIX Printing System (CUPS).
@@ -80,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-11 17:45:03.000000000 +0000
++++ cupsys-1.2.8/filter/pstops.c	2007-03-13 15:02:07.000000000 +0000
 @@ -937,14 +937,21 @@
          ppdEmitJCL(ppd, stdout, doc->job_id, doc->user, doc->title);
  
@@ -106,118 +123,12835 @@
        * Then copy all of the pages...
        */
  
-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-11 17:45:03.000000000 +0000
-@@ -279,9 +279,16 @@
- 
-   globalParams = new GlobalParams(buffer);
- 
--  globalParams->setPSPaperWidth(width);
--  globalParams->setPSPaperHeight(length);
--  globalParams->setPSImageableArea(left, bottom, right, top);
-+  if (fit || globalParams->getPSPaperWidth() > 0)
-+  {
-+    // Only set paper size and area if we are fitting to the job's
-+    // page size or the pdftops.conf file does not contain
-+    // "psPaperSize match"...
-+    globalParams->setPSPaperWidth(width);
-+    globalParams->setPSPaperHeight(length);
-+    globalParams->setPSImageableArea(left, bottom, right, top);
-+  }
+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
+@@ -2843,2848 +2843,3 @@
+ #
+ # End of "$Id$".
+ #
+-#
+-# "$Id$"
+-#
+-#   Message catalog template for the Common UNIX Printing System (CUPS).
+-#
+-#   Copyright 2005-2006 by Easy Software Products.
+-#
+-#   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
+-#
+-#
+-# NDT: I did not translate the messages used in conformance, DSC and PPD tests,
+-#      because they are destined to developers only, as far as I understand.
+-#
+-
+-msgid ""
+-msgstr ""
+-"Project-Id-Version: CUPS 1.2\n"
+-"Report-Msgid-Bugs-To: http://www.cups.org/str.php\n"
+-"POT-Creation-Date: 2006-05-21 10:08-0400\n"
+-"PO-Revision-Date: 2007-01-25 19:55+0200\n"
+-"Last-Translator: Philippe Combes <Philippe.Combes at ens-lyon.fr>\n"
+-"Language-Team: Français\n"
+-"Content-Type: text/plain; charset=utf-8\n"
+-"Content-Transfer-Encoding: 8bit\n"
+-
+-msgid "Options Installed"
+-msgstr "Options Installées"
+-
+-msgid "Class"
+-msgstr "Classe"
+-
+-msgid "Printer"
+-msgstr "Imprimante"
+-
+-msgid "Extra"
+-msgstr "Supplémentaire"
+-
+-msgid "General"
+-msgstr "Généralités"
+-
+-msgid "Media Size"
+-msgstr "Taille du support"
+-
+-msgid "Media Type"
+-msgstr "Type de support"
+-
+-msgid "Media Source"
+-msgstr "Source du support"
+-
+-msgid "Output Mode"
+-msgstr "Mode de sortie"
+-
+-msgid "Resolution"
+-msgstr "Résolution"
+-
+-msgid "Variable"
+-msgstr "Variable"
+-
+-msgid "Yes"
+-msgstr "Oui"
+-
+-msgid "No"
+-msgstr "Non"
+-
+-msgid "Auto"
+-msgstr "Auto"
+-
+-msgid "Enter your username and password or the root username and password to access this page."
+-msgstr "Entrez votre nom d'utilisateur et votre mot de passe UNIX ou bien identifiez-vous en tant que « root » pour accéder à cette page."
+-
+-msgid "You must use a https: URL to access this page."
+-msgstr "Vous devez utiliser une URL https: pour accéder à cette page."
+-
+-#, c-format
+-msgid "Bad request version number %d.%d!"
+-msgstr "La requête a un numéro de version erroné : %d.%d !"
+-
+-msgid "No attributes in request!"
+-msgstr "Aucun attribut dans la requête !"
+-
+-#, c-format
+-msgid "Attribute groups are out of order (%x < %x)!"
+-msgstr "Les groupes d'attributs ne sont pas dans le bon ordre (%x < %x) !"
+-
+-msgid "Missing required attributes!"
+-msgstr "Il manque des attributs indispensables !"
+-
+-#, c-format
+-msgid "%s not supported!"
+-msgstr "%s: opération non gérée !"
+-
+-msgid "The printer or class was not found."
+-msgstr "L'imprimante ou la classe n'a pas été trouvée."
+-
+-msgid "The printer-uri must be of the form \"ipp://HOSTNAME/classes/CLASSNAME\"."
+-msgstr "L'URI de l'imprimante doit suivre le format « ipp://NOM_MACHINE/classes/NOM_CLASSE »."
+-
+-#, c-format
+-msgid "The printer-uri \"%s\" contains invalid characters."
+-msgstr "L'URI de l'imprimante « %s » contient des caractères ."
+-
+-#, c-format
+-msgid "A printer named \"%s\" already exists!"
+-msgstr "Il existe déjà une imprimante appelée « %s » !"
+-
+-#, c-format
+-msgid "Attempt to set %s printer-state to bad value %d!"
+-msgstr "Tentative de donner une valeur erronée au paramètre « printer-state » : %d !"
+-
+-#, c-format
+-msgid "add_class: Unknown printer-op-policy \"%s\"."
+-msgstr "add_class: L'attribut « printer-op-policy » a une valeur non comprise : « %s »."
+-
+-#, c-format
+-msgid "add_class: Unknown printer-error-policy \"%s\"."
+-msgstr "add_class: L'attribut « printer-error-policy » a une valeur non comprise : « %s »."
+-
+-msgid "Unable to allocate memory for file types!"
+-msgstr "Impossible d'allouer de la mémoire pour les types de fichiers !"
+-
+-#, c-format
+-msgid "Character set \"%s\" not supported!"
+-msgstr "Jeu de caractères « %s » non géré !"
+-
+-#, c-format
+-msgid "Language \"%s\" not supported!"
+-msgstr "Langue « %s » non gérée !"
+-
+-#, c-format
+-msgid "The notify-user-data value is too large (%d > 63 octets)!"
+-msgstr "La valeur de l'attribut « notify-user-data » est trop grande ( %d > 63 octets ) !"
+-
+-msgid "The notify-lease-duration attribute cannot be used with job subscriptions."
+-msgstr "L'attribut « notify-lease-duration » ne peut pas être utilisé dans une souscription de tâche."
+-
+-msgid "The printer-uri must be of the form \"ipp://HOSTNAME/printers/PRINTERNAME\"."
+-msgstr "L'URI de l'imprimante doit suivre le format « ipp://NOM_MACHINE/printers/NOM_CLASSE »."
+-
+-#, c-format
+-msgid "A class named \"%s\" already exists!"
+-msgstr ""Il existe déjà une classe appelée « %s » !"
+-
+-#, c-format
+-msgid "File device URIs have been disabled! To enable, see the FileDevice directive in \"%s/cupsd.conf\"."
+-msgstr "L'impression dans un fichier a été désactivée ! Pour l'activer, cf. la directive « FileDevice » dans « %s/cupsd.conf »."
+-
+-#, c-format
+-msgid "Bad device-uri \"%s\"!"
+-msgstr "Valeur erronée pour le paramètre « device-uri » : « %s » !"
+-
+-#, c-format
+-msgid "Bad port-monitor \"%s\"!"
+-msgstr "Valeur erronée pour le paramètre « port-monitor » : « %s » !"
+-
+-#, c-format
+-msgid "Bad printer-state value %d!"
+-msgstr "Valeur erronée pour le paramètre « printer-state » : « %s » !"
+-
+-#, c-format
+-msgid "Unknown printer-op-policy \"%s\"."
+-msgstr "L'attribut « printer-op-policy » a une valeur non comprise : « %s »."
+-
+-#, c-format
+-msgid "Unknown printer-error-policy \"%s\"."
+-msgstr "L'attribut « printer-error-policy » a une valeur non comprise : « %s »."
+-
+-#, c-format
+-msgid "Unable to copy interface script - %s!"
+-msgstr "Impossible de copier le « script » d'interface - « %s » !"
+-
+-#, c-format
+-msgid "Unable to copy PPD file - %s!"
+-msgstr "Impossible de copier le fichier PPD - « %s » !"
+-
+-msgid "Unable to copy PPD file!"
+-msgstr "Impossible de copier le fichier PPD !"
+-
+-msgid "Got a printer-uri attribute but no job-id!"
+-msgstr "Attribut « printer-uri » trouvé mais pas de « job-id »"
+-
+-#, c-format
+-msgid "Bad job-uri attribute \"%s\"!"
+-msgstr "Valeur erronée pour l'attribut « job-uri » : « %s » !"
+-
+-#, c-format
+-msgid "Job #%d doesn't exist!"
+-msgstr "La tâche n°%d n'existe pas !"
+-
+-#, c-format
+-msgid "Job #%d is not held for authentication!"
+-msgstr "La tâche n°%d n'est pas en attente d'authentification !"
+-
+-#, c-format
+-msgid "You are not authorized to authenticate job #%d owned by \"%s\"!"
+-msgstr "Vous n'avez pas l'autorisation d'authentifier la tâche n°%d appartenant à « %s » !"
+-
+-msgid "The printer-uri attribute is required!"
+-msgstr "L'attribut « printer-uri » est indispensable !"
+-
+-msgid "Missing requesting-user-name attribute!"
+-msgstr "Il manque l'attribut « requesting-user-name » !"
+-
+-#, c-format
+-msgid "The printer-uri \"%s\" is not valid."
+-msgstr "L'attribut « printer-uri » est incorrect : « %s »."
+-
+-#, c-format
+-msgid "No active jobs on %s!"
+-msgstr "Il n'y a pas de tâche en cours sur « %s » !"
+-
+-#, c-format
+-msgid "You are not authorized to delete job #%d owned by \"%s\"!"
+-msgstr "Vous n'avez pas l'autorisation de supprimer la tâche n°%d appartenant à « %s » !"
+-
+-#, c-format
+-msgid "Job #%d is already %s - can't cancel."
+-msgstr "La tâche n°%d est déjà « %s » - impossible de l'annuler."
+-
+-msgid "The printer or class is not shared!"
+-msgstr "L'imprimante ou la classe n'est pas partagée !"
+-
+-#, c-format
+-msgid "Destination \"%s\" is not accepting jobs."
+-msgstr "La destination « %s » n'accepte aucune tâche."
+-
+-#, c-format
+-msgid "Bad copies value %d."
+-msgstr "Nombre de copies erroné : %d."
+-
+-#, c-format
+-msgid "Bad page-ranges values %d-%d."
+-msgstr "Intervalle de pages erroné : %d-%d."
+-
+-msgid "Too many active jobs."
+-msgstr "Trop de tâches en cours."
+-
+-msgid "Quota limit reached."
+-msgstr "Quota atteint."
+-
+-#, c-format
+-msgid "Unable to add job for destination \"%s\"!"
+-msgstr "Impossible d'ajouter une tâche pour la destination « %s » !"
+-
+-msgid "No subscription attributes in request!"
+-msgstr "Pas d'attribut de souscription dans la requête !"
+-
+-msgid "notify-events not specified!"
+-msgstr "Attribut « notify-events » non renseigné !"
+-
+-#, c-format
+-msgid "Job %d not found!"
+-msgstr "La tâche n°%d n'a pas été trouvée !"
+-
+-msgid "No default printer"
+-msgstr "Pas d'imprimante par défaut"
+-
+-msgid "cups-deviced failed to execute."
+-msgstr "L'exécution de « cups-deviced » a échouée."
+-
+-msgid "cups-driverd failed to execute."
+-msgstr "L'exécution de « cups-driverd » a échouée."
+-
+-msgid "No destinations added."
+-msgstr "Aucune destination ajoutée."
+-
+-#, c-format
+-msgid "notify-subscription-id %d no good!"
+-msgstr "Valeur erronée pour l'attribut « notify-subscription-id » : %d !"
+-
+-#, c-format
+-msgid "Job #%s does not exist!"
+-msgstr "La tâche n°%s n'existe pas !"
+-
+-#, c-format
+-msgid "Job #%d does not exist!"
+-msgstr "La tâche n°%d n'existe pas !"
+-
+-msgid "No subscriptions found."
+-msgstr "Aucune souscription trouvée."
+-
+-#, c-format
+-msgid "Not authorized to hold job #%d owned by \"%s\"!"
+-msgstr "Vous n'avez pas l'autorisation de retenir la tâche n°%d appartenant à « %s » !"
+-
+-#, c-format
+-msgid "Job #%d is finished and cannot be altered!"
+-msgstr "La tâche n°%d est terminée et ne peut plus être modifiée !"
+-
+-#, c-format
+-msgid "You are not authorized to move job #%d owned by \"%s\"!"
+-msgstr "Vous n'avez pas l'autorisation de transférer la tâche n°%d appartenant à « %s » !"
+-
+-msgid "job-printer-uri attribute missing!"
+-msgstr "Il manque l'attribut « job-printer-uri » !"
+-
+-#, c-format
+-msgid "Unsupported compression \"%s\"!"
+-msgstr "La compression « %s » n'est pas gérée !"
+-
+-msgid "No file!?!"
+-msgstr "Pas de fichier !?!"
+-
+-#, c-format
+-msgid "Could not scan type \"%s\"!"
+-msgstr "Impossible de comprendre le format « %s » !"
+-
+-#, c-format
+-msgid "Unsupported format '%s/%s'!"
+-msgstr "Le format « %s » n'est pas géré !"
+-
+-msgid "Printer not shared!"
+-msgstr "L'imprimante n'est pas partagée !"
+-
+-#, c-format
+-msgid "Too many jobs - %d jobs, max jobs is %d."
+-msgstr "Trop de tâches - %d tâches pour un maximum de %d."
+-
+-#, c-format
+-msgid "Job #%d is not held!"
+-msgstr "La tâche n°%d n'est pas retenue !"
+-
+-#, c-format
+-msgid "You are not authorized to release job id %d owned by \"%s\"!"
+-msgstr "Vous n'avez pas l'autorisation de libérer la tâche n°%d appartenant à « %s » !"
+-
+-#, c-format
+-msgid "Job #%d is not complete!"
+-msgstr "La tâche n°%d n'est pas terminée !"
+-
+-#, c-format
+-msgid "Job #%d cannot be restarted - no files!"
+-msgstr "La tâche n°%d ne peut être redémarrée - aucun fichier !"
+-
+-#, c-format
+-msgid "You are not authorized to restart job id %d owned by \"%s\"!"
+-msgstr "Vous n'avez pas l'autorisation de redémarrer la tâche n°%d appartenant à « %s » !"
+-
+-#, c-format
+-msgid "You are not authorized to send document for job #%d owned by \"%s\"!"
+-msgstr "Vous n'avez pas l'autorisation d'envoyer un document pour la tâche n°%d appartenant à « %s » !"
+-
+-#, c-format
+-msgid "Bad document-format \"%s\"!"
+-msgstr "Format de document erroné : « %s » !"
+-
+-#, c-format
+-msgid "You are not authorized to alter job id %d owned by \"%s\"!"
+-msgstr "Vous n'avez pas l'autorisation de modifier la tâche n°%d appartenant à « %s » !"
+-
+-#, c-format
+-msgid "%s cannot be changed."
+-msgstr "Impossible de modifier « %s »"
+-
+-msgid "Bad job-priority value!"
+-msgstr "Valeur erronée pour l'attribut « job-priority » !"
+-
+-msgid "Job is completed and cannot be changed."
+-msgstr "La tâche est terminée et ne peut être modifiée."
+-
+-msgid "Bad job-state value!"
+-msgstr "Valeur erronée pour l'attribut « job-state » !"
+-
+-msgid "Job state cannot be changed."
+-msgstr "L'état de la tâche ne peut être modifié."
+-
+-#, c-format
+-msgid "Unsupported compression attribute %s!"
+-msgstr "L'attribute de compression %s n'est pas géré !"
+-
+-#, c-format
+-msgid "Unsupported format \"%s\"!"
+-msgstr "Le format « %s » n'est pas géré !"
+-
+-#, c-format
+-msgid "%s is not implemented by the CUPS version of lpc.\n"
+-msgstr "« %s » n'est pas implanté dans la version CUPS de lpc.\n"
+-
+-msgid ""
+-"Commands may be abbreviated.  Commands are:\n"
+-"\n"
+-"exit    help    quit    status  ?\n"
+-msgstr ""
+-"Les commandes peuvent être abrégée. Elles sont:\n"
+-"\n"
+-"exit    help    quit    status  ?\n"
+-
+-msgid "help\t\tget help on commands\n"
+-msgstr "help\t\tobtenir de l'aide sur les commandes\n"
+-
+-msgid "status\t\tshow status of daemon and queue\n"
+-msgstr "status\t\taffiche l'état du démon et de la file\n"
+-
+-msgid "?Invalid help command unknown\n"
+-msgstr "?Commande d'aide inconnue\n"
+-
+-#, c-format
+-msgid "\tprinter is on device '%s' speed -1\n"
+-msgstr "\tl'imprimante est sur le périphérique '%s', vitesse -1\n"
+-
+-msgid "\tqueuing is enabled\n"
+-msgstr "\tla mise en file d'attente est permise\n"
+-
+-msgid "\tqueuing is disabled\n"
+-msgstr "\tla mise en file d'attente est refusée\n"
+-
+-msgid "\tprinting is enabled\n"
+-msgstr "\tl'impression est permise\n"
+-
+-msgid "\tprinting is disabled\n"
+-msgstr "\tl'impression est refusée\n"
+-
+-msgid "\tno entries\n"
+-msgstr "\taucune entrée\n"
+-
+-#, c-format
+-msgid "\t%d entries\n"
+-msgstr "\t%d entrées\n"
+-
+-msgid "\tdaemon present\n"
+-msgstr "\tdémon présent\n"
+-
+-msgid "lpq: Unable to contact server!\n"
+-msgstr "lpq: Impossible de contacter le serveur !\n"
+-
+-#, c-format
+-msgid "%s: Sorry, no encryption support compiled in!\n"
+-msgstr "%s: Désolé, la gestion du cryptage n'a pas été compilée !\n"
+-
+-#, c-format
+-msgid "lpq: Unknown destination \"%s/%s\"!\n"
+-msgstr lpq: Destination « %s/%s » inconnue !\n""
+-
+-#, c-format
+-msgid "lpq: Unknown destination \"%s\"!\n"
+-msgstr "lpq: Destination « %s » inconnue !\n"
+-
+-#, c-format
+-msgid "lp: error - %s environment variable names non-existent destination \"%s\"!\n"
+-msgstr "lp: erreur - la variable d'environnement %s désigne une destination inexistente « %s » !\n"
+-
+-msgid "lpq: error - no default destination available.\n"
+-msgstr "lpq: erreur - aucune destination par défaut n'est disponible.\n"
+-
+-#, c-format
+-msgid "lpq: get-jobs failed: %s\n"
+-msgstr "lpq: « get-jobs » a échoué: %s\n"
+-
+-msgid "Rank   Owner      Pri  Job        Files                       Total Size\n"
+-msgstr "Rang   Propr.     Prio Tâche      Fichiers                    Taille totale\n"
+-
+-msgid "Rank    Owner   Job     File(s)                         Total Size\n"
+-msgstr "Rang    Propr.  Tâche  Fichiers                       Taille totale\n"
+-
+-#, c-format
+-msgid "%s: %-33.33s [job %d localhost]\n"
+-msgstr "%s: %-33.33s [tâche %d localhost]\n"
+-
+-#, c-format
+-msgid "        %-39.39s %.0f bytes\n"
+-msgstr "        %-39.39s %.0f octets\n"
+-
+-#, c-format
+-msgid "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"
+-msgstr "%-6s %-10.10s %-4d %-10d %-27.27s %.0f octets\n"
+-
+-#, c-format
+-msgid "%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"
+-msgstr "%-7s %-7.7s %-7d %-31.31s %.0f octets\n"
+-
+-msgid "no entries\n"
+-msgstr "aucune entrée\n"
+-
+-#, c-format
+-msgid "lpq: get-printer-attributes failed: %s\n"
+-msgstr "lpq: get-printer-attributes a échoué : %s\n"
+-
+-#, c-format
+-msgid "%s is ready\n"
+-msgstr "%s est prête\n"
+-
+-#, c-format
+-msgid "%s is ready and printing\n"
+-msgstr "%s est prête et en cours d'impression\n"
+-
+-#, c-format
+-msgid "%s is not ready\n"
+-msgstr "%s n'est pas prête\n"
+-
+-msgid "Usage: lpq [-P dest] [-l] [+interval]\n"
+-msgstr "Utilisation : lpq [-P dest] [-l] [+intervalle]\n"
+-
+-#, c-format
+-msgid "lpr: error - expected value after -%c option!\n"
+-msgstr "lpr: erreur - il faut une valeur après l'option '-%c' !\n"
+-
+-#, c-format
+-msgid "lpr: warning - '%c' format modifier not supported - output may not be correct!\n"
+-msgstr "lpr: attention - le modificateur de format '%c' n'est pas géré - l'affichage pourrait être incorrect !\n"
+-
+-msgid "lpr: error - expected option=value after -o option!\n"
+-msgstr "lpr: erreur - il faut un argument du type option=valeur après l'option '-o' !\n"
+-
+-msgid "lpr: warning - email notification is not currently supported!\n"
+-msgstr "lpr: attention - la notification par courriel n'est pas encore gérée !\n"
+-
+-msgid "lpr: error - expected destination after -P option!\n"
+-msgstr "lpr: erreur - il faut une destination après l'option '-P' !\n"
+-
+-msgid "lpr: error - expected copy count after -# option!\n"
+-msgstr "lpr: erreur - il faut un nombre de copies après l'option '-#' !\n"
+-
+-#, c-format
+-msgid "lpr: error - expected name after -%c option!\n"
+-msgstr "lpr: erreur - il faut un nom après l'option '-%c' !\n"
+-
+-msgid "lpr: error - expected username after -U option!\n"
+-msgstr "lpr: erreur - il faut un nom d'utilisateur après l'option '-U' !\n"
+-
+-#, c-format
+-msgid "lpr: error - unknown option '%c'!\n"
+-msgstr "lpr: erreur - option '%c' inconnue !\n"
+-
+-#, c-format
+-msgid "lpr: error - unable to access \"%s\" - %s\n"
+-msgstr "lpr: erreur - impossible d'accéder à « %s » - %s\n"
+-
+-#, c-format
+-msgid "lpr: error - too many files - \"%s\"\n"
+-msgstr "lpr: erreur - trop de fichiers - « %s »\n"
+-
+-#, c-format
+-msgid "lpr: error - %s environment variable names non-existent destination \"%s\"!\n"
+-msgstr "lpr: erreur - la variable d'environnement %s désigne une destination inexistente « %s » !\n"
+-
+-msgid "lpr: error - no default destination available.\n"
+-msgstr "lpr: erreur - aucune destination par défaut n'est disponible.\n"
+-
+-msgid "lpr: error - scheduler not responding!\n"
+-msgstr "lpr: erreur - l'ordonnanceur ne répond pas !\n"
+-
+-#, c-format
+-msgid "lpr: error - unable to create temporary file \"%s\" - %s\n"
+-msgstr "lpr: erreur - impossible de créer le fichier temporaire « %s » - %s\n"
+-
+-#, c-format
+-msgid "lpr: error - unable to write to temporary file \"%s\" - %s\n"
+-msgstr "lpr: erreur - impossible d'écrire dans le fichier temporaire « %s » - %s\n"
+-
+-msgid "lpr: error - stdin is empty, so no job has been sent.\n"
+-msgstr "lpr: erreur - stdin est vide, donc aucune tâche n'a été envoyée.\n"
+-
+-#, c-format
+-msgid "lpr: error - unable to print file: %s\n"
+-msgstr "lpr: erreur - impossible d'imprimer le fichier : %s\n"
+-
+-msgid "lprm: Unable to contact server!\n"
+-msgstr "lprm: Impossible de contacter le serveur !\n"
+-
+-#, c-format
+-msgid "lprm: Unknown destination \"%s\"!\n"
+-msgstr "lprm: Destination « %s » inconnue !\n"
+-
+-#, c-format
+-msgid "lprm: Unknown option '%c'!\n"
+-msgstr "lprm: Option '%c' inconnue !\n"
+-
+-msgid "lprm: Job or printer not found!\n"
+-msgstr "lprm: La tâche ou l'imprimante n'a pas été trouvée !\n"
+-
+-msgid "lprm: Not authorized to lprm job(s)!\n"
+-msgstr "lprm: Vous n'avez pas l'autorisation de supprimer cette(ces) tâche(s) !\n"
+-
+-#, c-format
+-msgid "lprm: You don't own job ID %d!\n"
+-msgstr lprm: La tâche n°%d ne vous appartient pas !\n""
+-
+-msgid "lprm: Unable to lprm job(s)!\n"
+-msgstr "lprm: Impossible de supprimer cette(ces) tâche(s) !\n"
+-
+-msgid "lprm: Unable to cancel job(s)!\n"
+-msgstr "lprm: Impossible d'annuler cette(ces) tâche(s) !\n"
+-
+-#, c-format
+-msgid "%s: Don't know what to do!\n"
+-msgstr "%s: Je ne sais que faire !"
+-
+-#, c-format
+-msgid "%s: Expected server name after -h!\n"
+-msgstr "%s: Il faut un nom de serveur après l'option '-h' !\n"
+-
+-#, c-format
+-msgid "%s: Expected reason text after -r!\n"
+-msgstr "%s: Il faut le texte de la raison après l'option '-r' !\n"
+-
+-#, c-format
+-msgid "%s: Unknown option '%c'!\n"
+-msgstr "%s: Option '%c' inconnue !\n"
+-
+-#, c-format
+-msgid "%s: Unable to connect to server: %s\n"
+-msgstr "%s: Impossible de se connecter au serveur : %s\n"
+-
+-#, c-format
+-msgid "%s: Operation failed: %s\n"
+-msgstr "%s: L'opération a échoué : %s\n"
+-
+-msgid "cancel: Error - expected hostname after '-h' option!\n"
+-msgstr "annulation: erreur - il faut un nom de machine après l'option '-h' !\n"
+-
+-msgid "cancel: Error - expected username after '-u' option!\n"
+-msgstr "annulation: erreur - il faut un nom d'utilisateur après l'option '-u' !\n"
+-
+-#, c-format
+-msgid "cancel: Unknown option '%c'!\n"
+-msgstr "annulation: Option '%c' inconnue !"
+-
+-#, c-format
+-msgid "cancel: Unknown destination \"%s\"!\n"
+-msgstr "annulation: Destination inconnue « %s » !"
+-
+-msgid "cancel: Unable to contact server!\n"
+-msgstr "annulation: Impossible de contacter le serveur !\n"
+-
+-#, c-format
+-msgid "cancel: %s failed: %s\n"
+-msgstr "annulation: %s a échoué :%s\n"
+-
+-#, c-format
+-msgid "cupsaddsmb: Missing value on line %d!\n"
+-msgstr "cupsaddsmb: Il manque une valeur à la ligne n°%d !\n"
+-
+-#, c-format
+-msgid "cupsaddsmb: Missing double quote on line %d!\n"
+-msgstr "cupsaddsmb: Il manque un \" à la ligne n°%d !\n"
+-
+-#, c-format
+-msgid "cupsaddsmb: Bad option + choice on line %d!\n"
+-msgstr "cupsaddsmb: Option et choix erronés à la ligne n°%d !\n"
+-
+-#, c-format
+-msgid "cupsaddsmb: Unable to connect to server \"%s\" for %s - %s\n"
+-msgstr "cupsaddsmb: Impossible de se connecter au serveur « %s » pour %s - %s\n"
+-
+-#, c-format
+-msgid "cupsaddsmb: No PPD file for printer \"%s\" - skipping!\n"
+-msgstr "cupsaddsmb: Aucun fichier PPD pour l'imprimante « %s » - ignorée !\n"
+-
+-#, c-format
+-msgid "cupsaddsmb: get-printer-attributes failed for \"%s\": %s\n"
+-msgstr "cupsaddsmb: get-printer-attributes a échoué pour « %s » : %s\n"
+-
+-#, c-format
+-msgid "cupsaddsmb: Unable to convert PPD file for %s - %s\n"
+-msgstr "cupsaddsmb: Impossible de convertir le fichier PPD pour %s - %s\n"
+-
+-#, c-format
+-msgid "cupsaddsmb: Unable to copy Windows 2000 printer driver files (%d)!\n"
+-msgstr "cupsaddsmb: Impossible de copier les fichiers du pilote d'impression pour Windows 2000 (%d) !\n"
+-
+-#, c-format
+-msgid "cupsaddsmb: Unable to copy CUPS printer driver files (%d)!\n"
+-msgstr "cupsaddsmb: Impossible de copier les fichiers du pilote d'impression pour CUPS (%d) !\n"
+-
+-#, c-format
+-msgid "cupsaddsmb: Unable to install Windows 2000 printer driver files (%d)!\n"
+-msgstr "cupsaddsmb: Impossible d'installer les fichiers du pilote d'impression pour Windows 2000 (%d) !\n"
+-
+-#, c-format
+-msgid "cupsaddsmb: Unable to copy Windows 9x printer driver files (%d)!\n"
+-msgstr "cupsaddsmb: Impossible de copier les fichiers du pilote d'impression pour Windows 9x (%d) !\n"
+-
+-#, c-format
+-msgid "cupsaddsmb: Unable to install Windows 9x printer driver files (%d)!\n"
+-msgstr "cupsaddsmb: Impossible d'installer les fichiers du pilote d'impression pour Windows 9x (%d) !\n"
+-
+-#, c-format
+-msgid "cupsaddsmb: Unable to set Windows printer driver (%d)!\n"
+-msgstr "cupsaddsmb: Impossible de paramétrer le pilote d'impression pour Windows (%d) !\n"
+-
+-msgid ""
+-"Usage: cupsaddsmb [options] printer1 ... printerN\n"
+-"       cupsaddsmb [options] -a\n"
+-"\n"
+-"Options:\n"
+-"  -H samba-server  Use the named SAMBA server\n"
+-"  -U samba-user    Authenticate using the named SAMBA user\n"
+-"  -a               Export all printers\n"
+-"  -h cups-server   Use the named CUPS server\n"
+-"  -v               Be verbose (show commands)\n"
+-msgstr ""
+-"Utilisation : cupsaddsmb [options] imprimante1 ... imprimanteN\n"
+-"              cupsaddsmb [options] -a\n"
+-"\n"
+-"Options:\n"
+-"  -H serveur-samba      Utiliser le serveur SAMBA désigné\n"
+-"  -U utilisateur-samba  S'authentifier avec l'utilisateur SAMBA désigné\n"
+-"  -a                    Exporter toutes les imprimantes\n"
+-"  -h serveur-CUPS       Utiliser le serveur CUPS désigné\n"
+-"  -v                    Être locace ( afficher les commandes )\n"
+-
+-msgid "cupstestppd: The -q option is incompatible with the -v option.\n"
+-msgstr "cupstestppd: L'option est -q incomptaible avec l'option -v.\n"
+-
+-msgid "cupstestppd: The -v option is incompatible with the -q option.\n"
+-msgstr "cupstestppd: L'option est -v incomptaible avec l'option -q.\n"
+-
+-#, c-format
+-msgid ""
+-" FAIL\n"
+-"      **FAIL**  Unable to open PPD file - %s\n"
+-msgstr ""
+-" FAIL\n"
+-"      **FAIL**  Unable to open PPD file - %s\n"
+-
+-#, c-format
+-msgid ""
+-" FAIL\n"
+-"      **FAIL**  Unable to open PPD file - %s on line %d.\n"
+-msgstr ""
+-" FAIL\n"
+-"      **FAIL**  Unable to open PPD file - %s on line %d.\n"
+-
+-msgid "                REF: Page 42, section 5.2.\n"
+-msgstr "                REF: Page 42, section 5.2.\n"
+-
+-msgid "                REF: Page 20, section 3.4.\n"
+-msgstr "                REF: Page 20, section 3.4.\n"
+-
+-msgid "                REF: Pages 45-46, section 5.2.\n"
+-msgstr "                REF: Pages 45-46, section 5.2.\n"
+-
+-msgid "                REF: Pages 42-45, section 5.2.\n"
+-msgstr "                REF: Pages 42-45, section 5.2.\n"
+-
+-msgid "                REF: Pages 48-49, section 5.2.\n"
+-msgstr "                REF: Pages 48-49, section 5.2.\n"
+-
+-msgid "                REF: Pages 52-54, section 5.2.\n"
+-msgstr "                REF: Pages 52-54, section 5.2.\n"
+-
+-msgid "                REF: Page 15, section 3.2.\n"
+-msgstr "                REF: Page 15, section 3.2.\n"
+-
+-msgid "                REF: Page 15, section 3.1.\n"
+-msgstr "                REF: Page 15, section 3.1.\n"
+-
+-msgid "                REF: Pages 16-17, section 3.2.\n"
+-msgstr "                REF: Pages 16-17, section 3.2.\n"
+-
+-msgid "                REF: Page 19, section 3.3.\n"
+-msgstr "                REF: Page 19, section 3.3.\n"
+-
+-msgid "                REF: Page 27, section 3.5.\n"
+-msgstr "                REF: Page 27, section 3.5.\n"
+-
+-msgid ""
+-"\n"
+-"    DETAILED CONFORMANCE TEST RESULTS\n"
+-msgstr ""
+-"\n"
+-"    DETAILED CONFORMANCE TEST RESULTS\n"
+-
+-#, c-format
+-msgid "        WARN    %s has no corresponding options!\n"
+-msgstr "        WARN    %s has no corresponding options!\n"
+-
+-msgid " FAIL\n"
+-msgstr " FAIL\n"
+-
+-msgid ""
+-"      **FAIL**  REQUIRED DefaultImageableArea\n"
+-"                REF: Page 102, section 5.15.\n"
+-msgstr ""
+-"      **FAIL**  REQUIRED DefaultImageableArea\n"
+-"                REF: Page 102, section 5.15.\n"
+-
+-#, c-format
+-msgid ""
+-"      **FAIL**  BAD DefaultImageableArea %s!\n"
+-"                REF: Page 102, section 5.15.\n"
+-msgstr ""
+-"      **FAIL**  BAD DefaultImageableArea %s!\n"
+-"                REF: Page 102, section 5.15.\n"
+-
+-msgid "        PASS    DefaultImageableArea\n"
+-msgstr "        PASS    DefaultImageableArea\n"
+-
+-msgid ""
+-"      **FAIL**  REQUIRED DefaultPaperDimension\n"
+-"                REF: Page 103, section 5.15.\n"
+-msgstr ""
+-"      **FAIL**  REQUIRED DefaultPaperDimension\n"
+-"                REF: Page 103, section 5.15.\n"
+-
+-#, c-format
+-msgid ""
+-"      **FAIL**  BAD DefaultPaperDimension %s!\n"
+-"                REF: Page 103, section 5.15.\n"
+-msgstr ""
+-"      **FAIL**  BAD DefaultPaperDimension %s!\n"
+-"                REF: Page 103, section 5.15.\n"
+-
+-msgid "        PASS    DefaultPaperDimension\n"
+-msgstr "        PASS    DefaultPaperDimension\n"
+-
+-#, c-format
+-msgid ""
+-"      **FAIL**  BAD Default%s %s\n"
+-"                REF: Page 40, section 4.5.\n"
+-msgstr ""
+-"      **FAIL**  BAD Default%s %s\n"
+-"                REF: Page 40, section 4.5.\n"
+-
+-#, c-format
+-msgid "        PASS    Default%s\n"
+-msgstr "        PASS    Default%s\n"
+-
+-#, c-format
+-msgid ""
+-"      **FAIL**  REQUIRED Default%s\n"
+-"                REF: Page 40, section 4.5.\n"
+-msgstr ""
+-"      **FAIL**  REQUIRED Default%s\n"
+-"                REF: Page 40, section 4.5.\n"
+-
+-msgid "        PASS    FileVersion\n"
+-msgstr "        PASS    FileVersion\n"
+-
+-msgid ""
+-"      **FAIL**  REQUIRED FileVersion\n"
+-"                REF: Page 56, section 5.3.\n"
+-msgstr ""
+-"      **FAIL**  REQUIRED FileVersion\n"
+-"                REF: Page 56, section 5.3.\n"
+-
+-msgid "        PASS    FormatVersion\n"
+-msgstr "        PASS    FormatVersion\n"
+-
+-msgid ""
+-"      **FAIL**  REQUIRED FormatVersion\n"
+-"                REF: Page 56, section 5.3.\n"
+-msgstr ""
+-"      **FAIL**  REQUIRED FormatVersion\n"
+-"                REF: Page 56, section 5.3.\n"
+-
+-msgid "        PASS    LanguageEncoding\n"
+-msgstr "        PASS    LanguageEncoding\n"
+-
+-msgid ""
+-"      **FAIL**  REQUIRED LanguageEncoding\n"
+-"                REF: Pages 56-57, section 5.3.\n"
+-msgstr ""
+-"      **FAIL**  REQUIRED LanguageEncoding\n"
+-"                REF: Pages 56-57, section 5.3.\n"
+-
+-msgid "        PASS    LanguageVersion\n"
+-msgstr "        PASS    LanguageVersion\n"
+-
+-msgid ""
+-"      **FAIL**  REQUIRED LanguageVersion\n"
+-"                REF: Pages 57-58, section 5.3.\n"
+-msgstr ""
+-"      **FAIL**  REQUIRED LanguageVersion\n"
+-"                REF: Pages 57-58, section 5.3.\n"
+-
+-msgid ""
+-"      **FAIL**  BAD Manufacturer (should be \"HP\")\n"
+-"                REF: Page 211, table D.1.\n"
+-msgstr ""
+-"      **FAIL**  BAD Manufacturer (should be \"HP\")\n"
+-"                REF: Page 211, table D.1.\n"
+-
+-msgid "        PASS    Manufacturer\n"
+-msgstr "        PASS    Manufacturer\n"
+-
+-msgid ""
+-"      **FAIL**  REQUIRED Manufacturer\n"
+-"                REF: Pages 58-59, section 5.3.\n"
+-msgstr ""
+-"      **FAIL**  REQUIRED Manufacturer\n"
+-"                REF: Pages 58-59, section 5.3.\n"
+-
+-#, c-format
+-msgid ""
+-"      **FAIL**  BAD ModelName - \"%c\" not allowed in string.\n"
+-"                REF: Pages 59-60, section 5.3.\n"
+-msgstr ""
+-"      **FAIL**  BAD ModelName - \"%c\" not allowed in string.\n"
+-"                REF: Pages 59-60, section 5.3.\n"
+-
+-msgid "        PASS    ModelName\n"
+-msgstr "        PASS    ModelName\n"
+-
+-msgid ""
+-"      **FAIL**  REQUIRED ModelName\n"
+-"                REF: Pages 59-60, section 5.3.\n"
+-msgstr ""
+-"      **FAIL**  REQUIRED ModelName\n"
+-"                REF: Pages 59-60, section 5.3.\n"
+-
+-msgid "        PASS    NickName\n"
+-msgstr "        PASS    NickName\n"
+-
+-msgid ""
+-"      **FAIL**  REQUIRED NickName\n"
+-"                REF: Page 60, section 5.3.\n"
+-msgstr ""
+-"      **FAIL**  REQUIRED NickName\n"
+-"                REF: Page 60, section 5.3.\n"
+-
+-msgid "        PASS    PageSize\n"
+-msgstr "        PASS    PageSize\n"
+-
+-msgid ""
+-"      **FAIL**  REQUIRED PageSize\n"
+-"                REF: Pages 99-100, section 5.14.\n"
+-msgstr ""
+-"      **FAIL**  REQUIRED PageSize\n"
+-"                REF: Pages 99-100, section 5.14.\n"
+-
+-msgid "        PASS    PageRegion\n"
+-msgstr "        PASS    PageRegion\n"
+-
+-msgid ""
+-"      **FAIL**  REQUIRED PageRegion\n"
+-"                REF: Page 100, section 5.14.\n"
+-msgstr ""
+-"      **FAIL**  REQUIRED PageRegion\n"
+-"                REF: Page 100, section 5.14.\n"
+-
+-msgid "        PASS    PCFileName\n"
+-msgstr "        PASS    PCFileName\n"
+-
+-msgid ""
+-"      **FAIL**  REQUIRED PCFileName\n"
+-"                REF: Pages 61-62, section 5.3.\n"
+-msgstr ""
+-"      **FAIL**  REQUIRED PCFileName\n"
+-"                REF: Pages 61-62, section 5.3.\n"
+-
+-msgid ""
+-"      **FAIL**  BAD Product - not \"(string)\".\n"
+-"                REF: Page 62, section 5.3.\n"
+-msgstr ""
+-"      **FAIL**  BAD Product - not \"(string)\".\n"
+-"                REF: Page 62, section 5.3.\n"
+-
+-msgid "        PASS    Product\n"
+-msgstr "        PASS    Product\n"
+-
+-msgid ""
+-"      **FAIL**  REQUIRED Product\n"
+-"                REF: Page 62, section 5.3.\n"
+-msgstr ""
+-"      **FAIL**  REQUIRED Product\n"
+-"                REF: Page 62, section 5.3.\n"
+-
+-msgid ""
+-"      **FAIL**  BAD PSVersion - not \"(string) int\".\n"
+-"                REF: Pages 62-64, section 5.3.\n"
+-msgstr ""
+-"      **FAIL**  BAD PSVersion - not \"(string) int\".\n"
+-"                REF: Pages 62-64, section 5.3.\n"
+-
+-msgid "        PASS    PSVersion\n"
+-msgstr "        PASS    PSVersion\n"
+-
+-msgid ""
+-"      **FAIL**  REQUIRED PSVersion\n"
+-"                REF: Pages 62-64, section 5.3.\n"
+-msgstr ""
+-"      **FAIL**  REQUIRED PSVersion\n"
+-"                REF: Pages 62-64, section 5.3.\n"
+-
+-msgid ""
+-"      **FAIL**  BAD ShortNickName - longer than 31 chars.\n"
+-"                REF: Pages 64-65, section 5.3.\n"
+-msgstr ""
+-"      **FAIL**  BAD ShortNickName - longer than 31 chars.\n"
+-"                REF: Pages 64-65, section 5.3.\n"
+-
+-msgid "        PASS    ShortNickName\n"
+-msgstr "        PASS    ShortNickName\n"
+-
+-msgid ""
+-"      **FAIL**  REQUIRED ShortNickName\n"
+-"                REF: Page 64-65, section 5.3.\n"
+-msgstr ""
+-"      **FAIL**  REQUIRED ShortNickName\n"
+-"                REF: Page 64-65, section 5.3.\n"
+-
+-msgid ""
+-"      **FAIL**  BAD JobPatchFile attribute in file\n"
+-"                REF: Page 24, section 3.4.\n"
+-msgstr ""
+-"      **FAIL**  BAD JobPatchFile attribute in file\n"
+-"                REF: Page 24, section 3.4.\n"
+-
+-msgid ""
+-"      **FAIL**  REQUIRED PageSize\n"
+-"                REF: Page 41, section 5.\n"
+-"                REF: Page 99, section 5.14.\n"
+-msgstr ""
+-"      **FAIL**  REQUIRED PageSize\n"
+-"                REF: Page 41, section 5.\n"\n"
+-"                REF: Page 99, section 5.14.\n"
+-
+-#, c-format
+-msgid ""
+-"      **FAIL**  REQUIRED ImageableArea for PageSize %s\n"
+-"                REF: Page 41, section 5.\n"
+-"                REF: Page 102, section 5.15.\n"
+-msgstr ""
+-"      **FAIL**  REQUIRED ImageableArea for PageSize %s\n"
+-"                REF: Page 41, section 5.\n"
+-"                REF: Page 102, section 5.15.\n"
+-
+-#, c-format
+-msgid ""
+-"      **FAIL**  REQUIRED PaperDimension for PageSize %s\n"
+-"                REF: Page 41, section 5.\n"
+-"                REF: Page 103, section 5.15.\n"
+-msgstr ""
+-"      **FAIL**  REQUIRED PaperDimension for PageSize %s\n"
+-"                REF: Page 41, section 5.\n"
+-"                REF: Page 103, section 5.15.\n"
+-
+-#, c-format
+-msgid ""
+-"      **FAIL**  Bad %s choice %s!\n"
+-"                REF: Page 84, section 5.9\n"
+-msgstr ""
+-"      **FAIL**  Bad %s choice %s!\n"
+-"                REF: Page 84, section 5.9\n"
+-
+-#, c-format
+-msgid ""
+-"      **FAIL**  REQUIRED %s does not define choice None!\n"
+-"                REF: Page 122, section 5.17\n"
+-msgstr ""
+-"      **FAIL**  REQUIRED %s does not define choice None!\n"
+-"                REF: Page 122, section 5.17\n"
+-
+-#, c-format
+-msgid ""
+-"      **FAIL**  Bad %s choice %s!\n"
+-"                REF: Page 122, section 5.17\n"
+-msgstr ""
+-"      **FAIL**  Bad %s choice %s!\n"
+-"                REF: Page 122, section 5.17\n"
+-
+-msgid " PASS\n"
+-msgstr " PASS\n"
+-
+-#, c-format
+-msgid ""
+-"        WARN    Duplex option keyword %s should be named Duplex or JCLDuplex!\n"
+-"                REF: Page 122, section 5.17\n"
+-msgstr ""
+-"        WARN    Duplex option keyword %s should be named Duplex or JCLDuplex!\n"
+-"                REF: Page 122, section 5.17\n"
+-
+-msgid "        WARN    Default choices conflicting!\n"
+-msgstr ""
+-
+-#, c-format
+-msgid ""
+-"        WARN    Obsolete PPD version %.1f!\n"
+-"                REF: Page 42, section 5.2.\n"
+-msgstr ""
+-"        WARN    Obsolete PPD version %.1f!\n"
+-"                REF: Page 42, section 5.2.\n"
+-
+-msgid ""
+-"        WARN    LanguageEncoding required by PPD 4.3 spec.\n"
+-"                REF: Pages 56-57, section 5.3.\n"
+-msgstr ""
+-"        WARN    LanguageEncoding required by PPD 4.3 spec.\n"
+-"                REF: Pages 56-57, section 5.3.\n"
+-
+-msgid ""
+-"        WARN    Manufacturer required by PPD 4.3 spec.\n"
+-"                REF: Pages 58-59, section 5.3.\n"
+-msgstr ""
+-"        WARN    Manufacturer required by PPD 4.3 spec.\n"
+-"                REF: Pages 58-59, section 5.3.\n"
+-
+-msgid ""
+-"        WARN    PCFileName longer than 8.3 in violation of PPD spec.\n"
+-"                REF: Pages 61-62, section 5.3.\n"
+-msgstr ""
+-"        WARN    PCFileName longer than 8.3 in violation of PPD spec.\n"
+-"                REF: Pages 61-62, section 5.3.\n"
+-
+-msgid ""
+-"        WARN    ShortNickName required by PPD 4.3 spec.\n"
+-"                REF: Pages 64-65, section 5.3.\n"
+-msgstr ""
+-"        WARN    ShortNickName required by PPD 4.3 spec.\n"
+-"                REF: Pages 64-65, section 5.3.\n"
+-
+-msgid ""
+-"        WARN    Protocols contains both PJL and BCP; expected TBCP.\n"
+-"                REF: Pages 78-79, section 5.7.\n"
+-msgstr ""
+-"        WARN    Protocols contains both PJL and BCP; expected TBCP.\n"
+-"                REF: Pages 78-79, section 5.7.\n"
+-
+-msgid ""
+-"        WARN    Protocols contains PJL but JCL attributes are not set.\n"
+-"                REF: Pages 78-79, section 5.7.\n"
+-msgstr ""
+-"        WARN    Protocols contains PJL but JCL attributes are not set.\n"
+-"                REF: Pages 78-79, section 5.7.\n"
+-
+-#, c-format
+-msgid ""
+-"        WARN    %s shares a common prefix with %s\n"
+-"                REF: Page 15, section 3.2.\n"
+-msgstr ""
+-"        WARN    %s shares a common prefix with %s\n"
+-"                REF: Page 15, section 3.2.\n"
+-
+-#, c-format
+-msgid "    %d ERROR%s FOUND\n"
+-msgstr "    %d ERROR%s FOUND\n"
+-
+-msgid "    NO ERRORS FOUND\n"
+-msgstr "    NO ERRORS FOUND\n"
+-
+-#, c-format
+-msgid ""
+-"        WARN    \"%s %s\" conflicts with \"%s %s\"\n"
+-"                (constraint=\"%s %s %s %s\")\n"
+-msgstr ""
+-"        WARN    \"%s %s\" conflicts with \"%s %s\"\n"
+-"                (constraint=\"%s %s %s %s\")\n"
+-msgid ""
+-"Usage: cupstestppd [-q] [-r] [-v[v]] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+-"       program | cupstestppd [-q] [-r] [-v[v]] -\n"
+-msgstr ""
+-"Utilisation : cupstestppd [-q] [-r] [-v[v]] fichier1.ppd[.gz] [... fichierN.ppd[.gz]]\n"
+-"              programme | cupstestppd [-q] [-r] [-v[v]] -\n"
+-
+-msgid "lpstat: Need \"completed\" or \"not-completed\" after -W!\n"
+-msgstr "lpstat: Il faut « completed » ou « not-completed » après l'option -W !\n"
+-
+-msgid "lpstat: The -b option requires a destination argument.\n"
+-msgstr "lpstat: Il faut une destination après l'option '-b' !\n"
+-
+-msgid "Error: need hostname after '-h' option!\n"
+-msgstr "Erreur : Il faut un nom d'hôte après l'option '-h' !\n"
+-
+-#, c-format
+-msgid "lpstat: Unknown option '%c'!\n"
+-msgstr "lpstat: Option '%c inconnue !\n"
+-
+-#, c-format
+-msgid "lpstat: Invalid destination name in list \"%s\"!\n"
+-msgstr "lpstat: Nom de destination incorrect dans la liste « %s » !\n"
+-
+-#, c-format
+-msgid "lpstat: Unknown destination \"%s\"!\n"
+-msgstr "lpstat: Destination « %s » inconnue !\n"
+-
+-#, c-format
+-msgid "lpstat: Unable to connect to server %s on port %d: %s\n"
+-msgstr "lpstat: Impossible de se connecter au serveur « %s » sur le port %d : %s\n"
+-
+-#, c-format
+-msgid "lpstat: get-printers failed: %s\n"
+-msgstr "lpstat: get-printers a échoué: %s\n"
+-
+-#, c-format
+-msgid "%s accepting requests since Jan 01 00:00\n"
+-msgstr "%s accepte les requêtes depuis le Jan 01 00:00\n"
+-
+-#, c-format
+-msgid ""
+-"%s not accepting requests since Jan 01 00:00 -\n"
+-"\t%s\n"
+-msgstr ""
+-"%s n'accepte pas les requêtes depuis le Jan 01 00:00 -\n"
+-"\t%s\n"
+-
+-#, c-format
+-msgid "%s/%s accepting requests since Jan 01 00:00\n"
+-msgstr "%s/%s accepte les requêtes depuis le Jan 01 00:00\n"
+-
+-#, c-format
+-msgid ""
+-"%s/%s not accepting requests since Jan 01 00:00 -\n"
+-"\t%s\n"
+-msgstr ""
+-"%s/%s n'accepte pas les requêtes depuis le Jan 01 00:00 -\n"
+-"\t%s\n"
+-
+-#, c-format
+-msgid "lpstat: get-classes failed: %s\n"
+-msgstr "lpstat: get-classes a échoué : %s !\n"
+-
+-#, c-format
+-msgid "members of class %s:\n"
+-msgstr "membres de la classe %s :\n"
+-
+-#, c-format
+-msgid "system default destination: %s/%s\n"
+-msgstr "destination par défaut du système : %s/%s\n"
+-
+-#, c-format
+-msgid "system default destination: %s\n"
+-msgstr "destination par défaut du système : %s\n"
+-
+-#, c-format
+-msgid "lpstat: error - %s environment variable names non-existent destination \"%s\"!\n"
+-msgstr ""
+-"lpstat: erreur - la variable d'environnement désigne une destination\n"
+-"                 inexistente « %s » !\n"
+-
+-msgid "no system default destination\n"
+-msgstr "le système n'a pas de destination par défaut\n"
+-
+-#, c-format
+-msgid "Output for printer %s is sent to remote printer %s on %s\n"
+-msgstr ""
+-"Ce qui est envoyé à l'imprimante %s est redirigé vers l'imprimante\n"
+-"distante %s sur %s\n"
+-
+-#, c-format
+-msgid "Output for printer %s is sent to %s\n"
+-msgstr "Ce qui est envoyé à l'imprimante %s est redirigé vers %s\n"
+-
+-#, c-format
+-msgid "Output for printer %s/%s is sent to remote printer %s on %s\n"
+-msgstr ""
+-"Ce qui est envoyé à l'imprimante %s/%s est redirigé vers l'imprimante\n"
+-"distante %s sur %s\n"
+-
+-#, c-format
+-msgid "Output for printer %s/%s is sent to %s\n"
+-msgstr "Ce qui est envoyé à l'imprimante %s/%s est redirigé vers %s\n"
+-
+-#, c-format
+-msgid "device for %s: %s\n"
+-msgstr "périphérique pour %s : %s\n"
+-
+-#, c-format
+-msgid "device for %s/%s: %s\n"
+-msgstr "périphérique pour %s/%s : %s \n"
+-
+-#, c-format
+-msgid "lpstat: get-jobs failed: %s\n"
+-msgstr "lpstat: get-jobs a échoué : %s !\n"
+-
+-#, c-format
+-msgid "\tqueued for %s\n"
+-msgstr "\tmis en file d'attente pour %s\n"
+-
+-#, c-format
+-msgid "printer %s is idle.  enabled since %s\n"
+-msgstr "l'imprimante %s ne fait rien ; elle est activée depuis le %s\n"
+-
+-#, c-format
+-msgid "printer %s now printing %s-%d.  enabled since %s\n"
+-msgstr "l'imprimante %s est en train d'imprimer %s-%d ; elle est activée depuis le %s\n""
+-
+-#, c-format
+-msgid "printer %s disabled since %s -\n"
+-msgstr "l'imprimante %s est désactivée depuis le %s -\n"
+-
+-msgid "\treason unknown\n"
+-msgstr "\traison inconnue\n"
+-
+-msgid ""
+-"\tForm mounted:\n"
+-"\tContent types: any\n"
+-"\tPrinter types: unknown\n"
+-msgstr ""
+-"\tFormat monté :\n"
+-"\tTypes de contenu : any\n"
+-"\tTypes d'imprimante : unknown\n"
+-
+-#, c-format
+-msgid "\tDescription: %s\n"
+-msgstr "\tDescription : %s\n"
+-
+-msgid "\tAlerts:"
+-msgstr "\tAlertes :"
+-
+-#, c-format
+-msgid "\tLocation: %s\n"
+-msgstr "\tLieu : %s\n"
+-
+-msgid "\tConnection: remote\n"
+-msgstr "\tConnexion : distante\n"
+-
+-#, c-format
+-msgid "\tInterface: %s.ppd\n"
+-msgstr "\tInterface : %s.ppd\n"
+-
+-msgid "\tConnection: direct\n"
+-msgstr "\tConnexion : directe\n"
+-
+-#, c-format
+-msgid "\tInterface: %s/interfaces/%s\n"
+-msgstr "\tInterface : %s/interfaces/%s\n"
+-
+-#, c-format
+-msgid "\tInterface: %s/ppd/%s.ppd\n"
+-msgstr "\tInterface : %s/ppd/%s.ppd\n"
+-
+-msgid "\tOn fault: no alert\n"
+-msgstr "\tEn cas d'erreur : pas d'alerte\n"
+-
+-msgid "\tAfter fault: continue\n"
+-msgstr "\tAprès une erreur : poursuivre\n"
+-
+-msgid "\tUsers allowed:\n"
+-msgstr "\tUtilisateurs autorisés :\n"
+-
+-msgid "\tUsers denied:\n"
+-msgstr "\tUtilisateurs refusés :\n"
+-
+-msgid "\t\t(all)\n"
+-msgstr "\t\t( tous )\n"
+-
+-msgid "\tForms allowed:\n"
+-msgstr "\tFormats autorisés :\n"
+-
+-msgid "\t\t(none)\n"
+-msgstr "\t\t( aucun )\n"
+-
+-msgid "\tBanner required\n"
+-msgstr "\tBannière requise\n"
+-
+-msgid "\tCharset sets:\n"
+-msgstr "\tJeux de caractères :\n"
+-
+-msgid "\tDefault pitch:\n"
+-msgstr "\t« pitch » par défaut :\n"
+-
+-msgid "\tDefault page size:\n"
+-msgstr "\tTaille de papier par défaut :\n"
+-
+-msgid "\tDefault port settings:\n"
+-msgstr "\tParamètres par défaut du port :\n"
+-
+-#, c-format
+-msgid "printer %s/%s is idle.  enabled since %s\n"
+-msgstr "l'imprimante %s/%s ne fait rien ; elle est activée depuis le %s\n"
+-
+-#, c-format
+-msgid "printer %s/%s now printing %s-%d.  enabled since %s\n"
+-msgstr "l'imprimante %s/%s est en train d'imprimer %s-%d ; elle est activée depuis le %s\n""
+-
+-#, c-format
+-msgid "printer %s/%s disabled since %s -\n"
+-msgstr "l'imprimante %s/%s est désactivée depuis le %s -\n"
+-
+-msgid "scheduler is running\n"
+-msgstr "l'ordonnanceur tourne\n"
+-
+-msgid "scheduler is not running\n"
+-msgstr "l'ordonnanceur est arrêté\n"
+-
+-#, c-format
+-msgid "lpadmin: Unable to connect to server: %s\n"
+-msgstr "lpadmin: Impossible de se connecter au serveur « %s » !\n"
+-
+-msgid ""
+-"lpadmin: Unable to add a printer to the class:\n"
+-"         You must specify a printer name first!\n"
+-msgstr ""
+-"lpadmin: Impossible d'ajouter une imprimante à la classe :\n"
+-"         Vous devez d'abord préciser un nom d'imprimante !\n"
+-
+-msgid "lpadmin: Expected class name after '-c' option!\n"
+-msgstr "lpadmin: Il faut un nom de classe après l'option '-c' !\n"
+-
+-msgid "lpadmin: Class name can only contain printable characters!\n"
+-msgstr "lpadmin: Un nom de classe ne peut comporter que des caractères imprimables !\n"
+-
+-msgid "lpadmin: Expected printer name after '-d' option!\n"
+-msgstr "lpadmin: Il faut un nom d'imprimante après l'option '-d' !\n"
+-
+-msgid "lpadmin: Printer name can only contain printable characters!\n"
+-msgstr "lpadmin: Un nom d'imprimante ne peut comporter que des caractères imprimables !\n"
+-
+-msgid "lpadmin: Expected hostname after '-h' option!\n"
+-msgstr "lpadmin: Il faut un nom d'hôte après l'option 'h' !\n"
+-
+-msgid ""
+-"lpadmin: Unable to set the interface script:\n"
+-"         You must specify a printer name first!\n"
+-msgstr ""
+-"lpadmin: Impossible de définir le script d'interface :\n"
+-"         Vous devez d'abord préciser un nom d'imprimante !\n"
+-
+-msgid "lpadmin: Expected interface after '-i' option!\n"
+-msgstr "lpadmin: Il faut une interface après l'option '-i' !\n"
+-
+-msgid ""
+-"lpadmin: Unable to set the interface script or PPD file:\n"
+-"         You must specify a printer name first!\n"
+-msgstr ""
+-"lpadmin: Impossible de définir le script d'interface ou le fichier PPD :\n"
+-"         Vous devez d'abord préciser un nom d'imprimante !\n"
+-
+-msgid "lpadmin: Expected model after '-m' option!\n"
+-msgstr "lpadmin: Il faut un modèle après l'option '-m' !\n"
+-
+-msgid "lpadmin: Expected name=value after '-o' option!\n"
+-msgstr "lpadmin: Il faut un argument du type option=valeur après l'option '-o' !\n"
+-
+-msgid "lpadmin: Expected printer after '-p' option!\n"
+-msgstr "lpadmin: Il faut une imprimante après l'option '-p' !\n"
+-
+-msgid ""
+-"lpadmin: Unable to remove a printer from the class:\n"
+-"         You must specify a printer name first!\n"
+-msgstr ""
+-"lpadmin: Impossible de supprimer une imprimante de la classe :\n"
+-"         Vous devez d'abord préciser un nom d'imprimante !\n"
+-
+-msgid "lpadmin: Expected class after '-r' option!\n"
+-msgstr "lpadmin: Il faut une classe après l'option '-r' !\n"
+-
+-msgid "lpadmin: Expected allow/deny:userlist after '-u' option!\n"
+-msgstr ""
+-"lpadmin: Il faut un argument du type allow/deny:liste_utilisateurs\n"
+-"         après l'option '-u' !\n"
+-
+-#, c-format
+-msgid "lpadmin: Unknown allow/deny option \"%s\"!\n"
+-msgstr "lpadmin: Option allow/deny « %s » inconnue !\n"
+-
+-msgid ""
+-"lpadmin: Unable to set the device URI:\n"
+-"         You must specify a printer name first!\n"
+-msgstr ""
+-"lpadmin: Impossible de définir l'URI du périphérique :\n"
+-"         Vous devez d'abord préciser un nom d'imprimante !\n"
+-
+-msgid "lpadmin: Expected device URI after '-v' option!\n"
+-msgstr "lpadmin: Il faut un URI de périphérique après l'option '-v' !\n"
+-
+-msgid "lpadmin: Expected printer or class after '-x' option!\n"
+-msgstr "lpadmin: Il faut une imprimante ou une classe après l'option '-x' !\n"
+-
+-msgid ""
+-"lpadmin: Unable to set the printer description:\n"
+-"         You must specify a printer name first!\n"
+-msgstr ""
+-"lpadmin: Impossible de définir la description de l'imprimante :\n"
+-"         Vous devez d'abord préciser un nom d'imprimante !\n"
+-
+-msgid "lpadmin: Expected description after '-D' option!\n"
+-msgstr "lpadmin: Il faut une description après l'option '-D' !\n"
+-
+-msgid "lpadmin: Expected file type(s) after '-I' option!\n"
+-msgstr "lpadmin: Il faut un ou plusieurs types de fichier après l'option '-I' !\n"
+-
+-msgid "lpadmin: Warning - content type list ignored!\n"
+-msgstr "lpadmin: Attention - les types de contenu sont ignorés !\n"
+-
+-msgid ""
+-"lpadmin: Unable to set the printer location:\n"
+-"         You must specify a printer name first!\n"
+-msgstr ""
+-"lpadmin: Impossible de définir le lieu de l'imprimante :\n"
+-"         Vous devez d'abord préciser un nom d'imprimante !\n"
+-
+-msgid "lpadmin: Expected location after '-L' option!\n"
+-msgstr "lpadmin: Il faut un lieu après l'option '-L' !\n"
+-
+-msgid ""
+-"lpadmin: Unable to set the PPD file:\n"
+-"         You must specify a printer name first!\n"
+-msgstr ""
+-"lpadmin: Impossible de définir le fichier PPD :\n"
+-"         Vous devez d'abord préciser un nom d'imprimante !\n"
+-
+-msgid "lpadmin: Expected PPD after '-P' option!\n"
+-msgstr "lpadmin: Il faut un fichier PPD après l'option '-P' !\n"
+-
+-#, c-format
+-msgid "lpadmin: Unknown option '%c'!\n"
+-msgstr "lpadmin: Option '%c' inconnue !\n"
+-
+-#, c-format
+-msgid "lpadmin: Unknown argument '%s'!\n"
+-msgstr "lpadmin: Argument « %s » inconnu !\n"
+-
+-msgid ""
+-"lpadmin: Unable to set the printer options:\n"
+-"         You must specify a printer name first!\n"
+-msgstr ""
+-"lpadmin: Impossible de définir les options de l'imprimante :\n"
+-"         Vous devez d'abord préciser un nom d'imprimante !\n"
+-
+-msgid ""
+-"Usage:\n"
+-"\n"
+-"    lpadmin [-h server] -d destination\n"
+-"    lpadmin [-h server] -x destination\n"
+-"    lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+-"                       [-r remove-class] [-v device] [-D description]\n"
+-"                       [-P ppd-file] [-o name=value]\n"
+-"                       [-u allow:user,user] [-u deny:user,user]\n"
+-"\n"
+-msgstr ""
+-"Utilisation :\n"
+-"\n"
+-"    lpadmin [-h serveur] -d destination\n"
+-"    lpadmin [-h serveur] -x destination\n"
+-"    lpadmin [-h serveur] -p imprimante [-c classe] [-i interface] [-m modèle]\n"
+-"                        [-r classe] [-v URI] [-D description]\n"
+-"                        [-P fichier-ppd] [-o option=valeur]\n"
+-"                        [-u allow:util.,util.] [-u deny:util.,util.]\n"
+-"\n"
+-
+-#, c-format
+-msgid "lpadmin: Unable to create temporary file: %s\n"
+-msgstr "lpadmin: Impossible de créer un fichier temporaire : %s\n"
+-
+-#, c-format
+-msgid "lpadmin: Unable to open file \"%s\": %s\n"
+-msgstr "lpadmin: Impossible d'ouvrir le fichier « %s » : %s\n"
+-
+-#, c-format
+-msgid "lpadmin: add-printer (set model) failed: %s\n"
+-msgstr "lpadmin: add-printer ( définition du modèle ) a échoué : %s\n"
+-
+-#, c-format
+-msgid "lpadmin: add-printer (set description) failed: %s\n"
+-msgstr "lpadmin: add-printer ( définition de la description ) a échoué : %s\n"
+-
+-#, c-format
+-msgid "lpadmin: add-printer (set location) failed: %s\n"
+-msgstr "lpadmin: add-printer ( définition du lieu ) a échoué : %s\n"
+-
+-#, c-format
+-msgid "lpadmin: Unable to create temporary file - %s\n"
+-msgstr "lpadmin: Impossible de créer un fichier temporaire : %s\n"
+-
+-#, c-format
+-msgid "lpadmin: Unable to open PPD file \"%s\" - %s\n"
+-msgstr "lpadmin: Impossible d'ouvrir le fichier PPD « %s » : %s\n"
+-
+-#, c-format
+-msgid "lpadmin: %s failed: %s\n"
+-msgstr "lpadmin: %s a échoué : %s\n"
+-
+-msgid "lp: Expected destination after -d option!\n"
+-msgstr "lp: Il faut une destination après l'option '-d' !\n"
+-
+-msgid "lp: Expected form after -f option!\n"
+-msgstr "lp: Il faut un format après l'option '-f' !\n"
+-
+-msgid "lp: Expected hostname after -h option!\n"
+-msgstr "lp: Il faut un nom d'hôte après l'option '-h' !\n"
+-
+-msgid "lp: Expected job ID after -i option!\n"
+-msgstr "lp: Il faut un numéro de tâche après l'option '-i' !\n"
+-
+-msgid "lp: Error - cannot print files and alter jobs simultaneously!\n"
+-msgstr "lp: Erreur - impossible d'imprimer et modifier les tâches en même temps !\n"
+-
+-msgid "lp: Error - bad job ID!\n"
+-msgstr "lp: Erreur - numéro de tâche incorrect !\n"
+-
+-msgid "lp: Expected copies after -n option!\n"
+-msgstr "lp: Il faut un nombre de copies après l'option '-n' !\n"
+-
+-msgid "lp: Expected option string after -o option!\n"
+-msgstr "lp: Il faut une chaîne d'option \"nom=valeur\" après l'option '-o' !\n"
+-
+-#, c-format
+-msgid "lp: Expected priority after -%c option!\n"
+-msgstr "lp: Il faut une priorité après l'option '-%c' !\n"
+-
+-msgid "lp: Priority must be between 1 and 100.\n"
+-msgstr "lp: La priorité doit être comprise entre 1 et 100.\n"
+-
+-msgid "lp: Expected title after -t option!\n"
+-msgstr "lp: Il faut un titre après l'option '-t' !\n"
+-
+-msgid "lp: Expected mode list after -y option!\n"
+-msgstr "lp: Il faut une liste de modes après l'option '-y' !\n"
+-
+-msgid "lp: Warning - mode option ignored!\n"
+-msgstr "lp: Attention - l'option « mode » est ignorée !\n"
+-
+-msgid "lp: Expected hold name after -H option!\n"
+-msgstr "lp: Il faut un code de retenue après l'option '-H' !\n"
+-
+-msgid "lp: Need job ID (-i) before \"-H restart\"!\n"
+-msgstr "lp: Il faut un numéro de tâche ( '-i' ) avant '-H restart' !\n"
+-
+-msgid "lp: Expected page list after -P option!\n"
+-msgstr "lp: Il faut une liste de pages après l'option '-P' !\n"
+-
+-msgid "lp: Expected character set after -S option!\n"
+-msgstr "lp: Il faut un jeu de caractères après l'option '-S' !\n"
+-
+-msgid "lp: Warning - character set option ignored!\n"
+-msgstr "lp: Attention - l'option « jeu de caractères » est ignorée !\n"
+-
+-msgid "lp: Expected content type after -T option!\n"
+-msgstr "lp: Il faut un type de contenu après l'option '-T' !\n"
+-
+-msgid "lp: Warning - content type option ignored!\n"
+-msgstr "lp: Attention - l'option « type de contenu » est ignorée !\n"
+-
+-#, c-format
+-msgid "lp: Unknown option '%c'!\n"
+-msgstr "lp: Option '%c' inconnue !\n"
+-
+-msgid "lp: Error - cannot print from stdin if files or a job ID are provided!\n"
+-msgstr ""
+-"lp: Erreur - impossible d'imprimer depuis l'entrée standard si un fichier\n"
+-"             ou un numéro de tâche est spécifié !\n"
+-
+-#, c-format
+-msgid "lp: Unable to access \"%s\" - %s\n"
+-msgstr "lp: Impossible d'accéder à « %s » - %s\n"
+-
+-#, c-format
+-msgid "lp: Too many files - \"%s\"\n"
+-msgstr "lp: Trop de fichiers - « %s »\n"
+-
+-msgid "lp: error - no default destination available.\n"
+-msgstr "lp: Erreur - aucune destination par défaut n'est disponible.\n"
+-
+-msgid "lp: error - scheduler not responding!\n"
+-msgstr "lp: Erreur - l'odonnanceur ne répond pas !\n"
+-
+-#, c-format
+-msgid "lp: Error - unable to create temporary file \"%s\" - %s\n"
+-msgstr "lp: Erreur - impossible de créer le fichier temporaire « %s » - %s\n"
+-
+-#, c-format
+-msgid "lp: error - unable to write to temporary file \"%s\" - %s\n"
+-msgstr "lp: Erreur - impossible d'écrire dans le fichier temporaire « %s » - %s\n"
+-
+-msgid "lp: stdin is empty, so no job has been sent.\n"
+-msgstr "lp: l'entrée standard est vide, donc aucune tâche n'a été envoyée.\n"
+-
+-#, c-format
+-msgid "lp: unable to print file: %s\n"
+-msgstr "lp: impossible d'imprimer le fichier - %s\n"
+-
+-#, c-format
+-msgid "request id is %s-%d (%d file(s))\n"
+-msgstr "l'identifiant de requête est %s-%d ( %d fichier(s) )\n"
+-
+-#, c-format
+-msgid "lp: restart-job failed: %s\n"
+-msgstr "lp: restart-job a échoué : %s\n"
+-
+-#, c-format
+-msgid "lp: set-job-attributes failed: %s\n"
+-msgstr "lp: set-job-attributes a échoué : %s\n"
+-
+-#, c-format
+-msgid "lpinfo: Unable to connect to server: %s\n"
+-msgstr "lpinfo: Impossible de se connecter au serveur : %s\n"
+-
+-#, c-format
+-msgid "lpinfo: Unknown option '%c'!\n"
+-msgstr "lpinfo: Option '%c' inconnue !\n"
+-
+-#, c-format
+-msgid "lpinfo: Unknown argument '%s'!\n"
+-msgstr "lpinfo: Argument '%s' inconnu !\n"
+-
+-#, c-format
+-msgid "lpinfo: cups-get-devices failed: %s\n"
+-msgstr "lpinfo: cups-get-devices a échoué : %s\n"
+-
+-#, c-format
+-msgid ""
+-"Device: uri = %s\n"
+-"        class = %s\n"
+-"        info = %s\n"
+-"        make-and-model = %s\n"
+-msgstr ""
+-"Matériel :   URI = %s\n"
+-"          classe = %s\n"
+-"            info = %s\n"
+-"   marque/modèle = %s\n"
+-
+-#, c-format
+-msgid "lpinfo: cups-get-ppds failed: %s\n"
+-msgstr "lpinfo: cups-get-ppds a échoué : %s\n"
+-
+-#, c-format
+-msgid ""
+-"Model:  name = %s\n"
+-"        natural_language = %s\n"
+-"        make-and-model = %s\n"
+-msgstr ""
+-"Modèle :        nom = %s\n"
+-"   langue naturelle = %s\n"
+-"      marque/modèle = %s\n"
+-
+-#, c-format
+-msgid "lpmove: Unknown option '%c'!\n"
+-msgstr "lpmove: Option '%c' inconnue !\n"
+-
+-#, c-format
+-msgid "lpmove: Unknown argument '%s'!\n"
+-msgstr "lpmove: Argument '%s' inconnu !\n"
+-
+-msgid "Usage: lpmove job dest\n"
+-msgstr "Utilisation : lpmove tâche destination\n"
+-
+-#, c-format
+-msgid "lpmove: Unable to connect to server: %s\n"
+-msgstr "lpmove: Impossible de se connecter au serveur : %s\n"
+-
+-#, c-format
+-msgid "lpmove: move-job failed: %s\n"
+-msgstr "lpmove: move-job a échoué : %s\n""
+-
+-msgid "lpoptions: Unknown printer or class!\n"
+-msgstr "lpoptions: Imprimante ou classe inconnue !\n"
+-
+-msgid "lpoptions: No printers!?!\n"
+-msgstr "lpoptions: Pas d'imprimante !?!\n"
+-
+-#, c-format
+-msgid "lpoptions: Unable to add printer or instance: %s\n"
+-msgstr "lpoptions: Impossible d'ajouter l'imprimante ou l'instance : %s\n"
+-
+-#, c-format
+-msgid "lpoptions: Destination %s has no PPD file!\n"
+-msgstr "lpoptions: La destination %s n'a pas de fichier PPD !\n"
+-
+-#, c-format
+-msgid "lpoptions: Unable to open PPD file for %s!\n"
+-msgstr "lpoptions: Impossible d'ouvrir le fichier PPD pour %s !\n"
+-
+-msgid ""
+-"Usage: lpoptions [-h server] [-E] -d printer\n"
+-"       lpoptions [-h server] [-E] [-p printer] -l\n"
+-"       lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+-"       lpoptions [-h server] [-E] -x printer\n"
+-msgstr ""
+-"Utilisation : lpoptions [-h serveur] [-E] -d imprimante\n"
+-"              lpoptions [-h serveur] [-E] [-p imprimante] -l\n"
+-"              lpoptions [-h serveur] [-E] -p imprimante -o option[=valeur] ...\n"
+-"              lpoptions [-h serveur] [-E] -x imprimante\n"
+-
+-msgid "lppasswd: Only root can add or delete passwords!\n"
+-msgstr "lppasswd: Seul l'utilisateur « root » peut ajouter ou supprimer des mots de passe !\n"
+-
+-msgid "Enter old password:"
+-msgstr "Ancien mot de passe :"
+-
+-#, c-format
+-msgid "lppasswd: Unable to copy password string: %s\n"
+-msgstr "lppasswd: Impossible de copier le mot de passe : %s\n"
+-
+-msgid "Enter password:"
+-msgstr "Entrez le nouveau mot de passe :"
+-
+-msgid "Enter password again:"
+-msgstr "Confirmez le nouveau mot de passe :"
+-
+-msgid "lppasswd: Sorry, passwords don't match!\n"
+-msgstr "lppasswd: Désolé, les mots de passe sont différents !\n"
+-
+-msgid ""
+-"lppasswd: Sorry, password rejected.\n"
+-"Your password must be at least 6 characters long, cannot contain\n"
+-"your username, and must contain at least one letter and number.\n"
+-msgstr ""
+-"lppasswd: Désolé, mot de passe refusé.\n"
+-"Votre mot de passe doit comporter au moins 6 caractères, au moins une lettre\n"
+-"et un nombre, et ne peut contenir votre nom d'utilisateur.\n"
+-
+-msgid "lppasswd: Password file busy!\n"
+-msgstr "lppasswd: Le fichier des mots de passe exidte déjà !\n"
+-
+-#, c-format
+-msgid "lppasswd: Unable to open password file: %s\n"
+-msgstr "lppasswd: Impossible d'ouvrir le fichier des mots de passe: %s\n"
+-
+-#, c-format
+-msgid "lppasswd: Unable to write to password file: %s\n"
+-msgstr "lppasswd: Impossible d'écrire dans le fichier des mots de passe : %s\n"
+-
+-#, c-format
+-msgid "lppasswd: user \"%s\" and group \"%s\" do not exist.\n"
+-msgstr "lppasswd: l'utilisateur « %s » et/ou le groupe « %s » n'existe(nt) pas !\n"
+-
+-msgid "lppasswd: Sorry, password doesn't match!\n"
+-msgstr "lppasswd: Désolé, le mot de passe est erroné !\n"
+-
+-msgid "lppasswd: Password file not updated!\n"
+-msgstr "lppasswd: Le fichier des mots de passe n'a pas été mis-à-jour !\n"
+-
+-#, c-format
+-msgid "lppasswd: failed to backup old password file: %s\n"
+-msgstr "lppasswd: impossible de sauvegarder l'ancien fichier des mots de passe : %s\n"
+-
+-#, c-format
+-msgid "lppasswd: failed to rename password file: %s\n"
+-msgstr "lppasswd: impossible de renommer le fichier des mots de passe : %s\n"
+-
+-msgid "Usage: lppasswd [-g groupname]\n"
+-msgstr "Utilisation : lppasswd [-g nom_groupe]\n"
+-
+-msgid ""
+-"Usage: lppasswd [-g groupname] [username]\n"
+-"       lppasswd [-g groupname] -a [username]\n"
+-"       lppasswd [-g groupname] -x [username]\n"
+-msgstr ""
+-"Utilisation : lppasswd [-g nom_groupe] [nom_utilisateur]\n"
+-"              lppasswd [-g nom_groupe] -a [nom_utilisateur]\n"
+-"              lppasswd [-g nom_groupe] -x [nom_utilisateur]\n"
+-
+-msgid "Start Printer"
+-msgstr "Démarrer l'imprimante"
+-
+-msgid "Stop Printer"
+-msgstr "Arrêter l'imprimante"
+-
+-msgid "Start Class"
+-msgstr "Démarrer la classe"
+-
+-msgid "Stop Class"
+-msgstr "Arrêter la classe"
+-
+-msgid "Accept Jobs"
+-msgstr "Accepter les tâches"
+-
+-msgid "Reject Jobs"
+-msgstr "Refuser les tâches"
+-
+-msgid "Purge Jobs"
+-msgstr "Effacer les tâches"
+-
+-msgid "Set As Default"
+-msgstr "Choisir par défaut"
+-
+-msgid "Administration"
+-msgstr "Administration"
+-
+-msgid "Modify Class"
+-msgstr "Modifier la classe"
+-
+-msgid "Add Class"
+-msgstr "Ajouter une classe"
+-
+-msgid "The class name may only contain up to 127 printable characters and may not contain spaces, slashes (/), or the pound sign (#)."
+-msgstr "Le nom de classe doit comporter au plus 127 caractères, tous imprimables, sans espace, '/' ni '#'."
+-
+-msgid "Unable to modify class:"
+-msgstr "Impossible de modifier la classe :"
+-
+-msgid "Unable to add class:"
+-msgstr "Impossible d'ajouter la classe :"
+-
+-msgid "Modify Printer"
+-msgstr "Modifier l'imprimante"
+-
+-msgid "Add Printer"
+-msgstr "Ajouter une imprimante"
+-
+-msgid "The printer name may only contain up to 127 printable characters and may not contain spaces, slashes (/), or the pound sign (#)."
+-msgstr "Le nom d'imprimante doit comporter au plus 127 caractères, tous imprimables, sans espace, '/' ni '#'."
+-
+-msgid "Unable to get list of printer drivers:"
+-msgstr "Impossible d'obtenir la liste des pilotes pour l'imprimante:"
+-
+-msgid "Unable to modify printer:"
+-msgstr "Impossible de modifier l'imprimante :"
+-
+-msgid "Unable to add printer:"
+-msgstr "Impossible d'ajouter l'imprimante :"
+-
+-msgid "Set Printer Options"
+-msgstr "Définir les options de l'imprimante"
+-
+-msgid "Missing form variable!"
+-msgstr "Un champ du formulaire HTML n'a pas été rempli !"
+-
+-msgid "Unable to get PPD file!"
+-msgstr "Impossible de trouver le fichier PPD !"
+-
+-msgid "Unable to open PPD file:"
+-msgstr "Impossible d'ouvrir le fichier PPD :"
+-
+-msgid "Banners"
+-msgstr "Bannières"
+-
+-msgid "Starting Banner"
+-msgstr "Début de la bannière"
+-
+-msgid "Ending Banner"
+-msgstr "Fin de la bannière"
+-
+-msgid "Policies"
+-msgstr "Politiques"
+-
+-msgid "Error Policy"
+-msgstr "Politique d'erreur"
+-
+-msgid "Operation Policy"
+-msgstr "Politique des opérations"
+-
+-msgid "PS Binary Protocol"
+-msgstr "Protocole binaire PS"
+-
+-msgid "None"
+-msgstr "Auncun(e)"
+-
+-msgid "Unable to set options:"
+-msgstr "Impossible de définir les options :"
+-
+-msgid "Change Settings"
+-msgstr "Modifier les paramètres"
+-
+-msgid "Unable to change server settings:"
+-msgstr "Impossible de modifier les paramètres du serveur :"
+-
+-msgid "Unable to upload cupsd.conf file:"
+-msgstr "Impossible de transmettre le fichier cupsd.conf :"
+-
+-msgid "Edit Configuration File"
+-msgstr "Éditer le fichier de configuration"
+-
+-msgid "Unable to create temporary file:"
+-msgstr "Impossible de créer le fichier temporaire :"
+-
+-msgid "Unable to access cupsd.conf file:"
+-msgstr "Impossible d'accéder au fichier cupsd.conf :"
+-
+-msgid "Unable to edit cupsd.conf files larger than 1MB!"
+-msgstr "Impossible d'éditer des fichiers cupsd.conf de taille supérieure à 1Mo !"
+-
+-msgid "Delete Class"
+-msgstr "Supprimer la classe"
+-
+-msgid "Unable to delete class:"
+-msgstr "Impossible de supprimer la classe :"
+-
+-msgid "Delete Printer"
+-msgstr "Supprimer l'imprimante"
+-
+-msgid "Unable to delete printer:"
+-msgstr "Impossible de supprimer l'imprimante :"
+-
+-msgid "Export Printers to Samba"
+-msgstr "Exporter les imprimantes vers SAMBA"
+-
+-msgid "Unable to fork process!"
+-msgstr "Impossible de faire un « fork » !"
+-
+-msgid "Unable to connect to server!"
+-msgstr "Impossible de se connecter au serveur !"
+-
+-msgid "Unable to get printer attributes!"
+-msgstr "Impossible de récupérer les attributs de l'imprimante !"
+-
+-msgid "Unable to convert PPD file!"
+-msgstr "Impossible de convertir le fichier PPD !"
+-
+-msgid "Unable to copy Windows 2000 printer driver files!"
+-msgstr "Impossible de copier les fichiers de pilote d'impression pour Windows 2000 !"
+-
+-msgid "Unable to install Windows 2000 printer driver files!"
+-msgstr "Impossible d'installer les fichiers de pilote d'impression pour Windows 2000 !"
+-
+-msgid "Unable to copy Windows 9x printer driver files!"
+-msgstr "Impossible de copier les fichiers de pilote d'impression pour Windows 9x !"
+-
+-msgid "Unable to install Windows 9x printer driver files!"
+-msgstr "Impossible d'installer les fichiers de pilote d'impression pour Windows 9x !"
+-
+-msgid "Unable to set Windows printer driver!"
+-msgstr "Impossible d'installer les fichiers de pilote d'impression pour Windows !"
+-
+-msgid "No printer drivers found!"
+-msgstr "Aucun pilote trouvé pour l'imprimante !"
+-
+-msgid "Unable to execute cupsaddsmb command!"
+-msgstr "Impossible d'exécuter la commande cupsaddsmb !"
+-
+-#, c-format
+-msgid "cupsaddsmb failed with status %d"
+-msgstr "cupsaddsmb a échoué avec le statut %d"
+-
+-#, c-format
+-msgid "cupsaddsmb crashed on signal %d"
+-msgstr "cupsaddsmb s'est terminé inopinément sur réception du signal %d"
+-
+-msgid "A Samba username is required to export printer drivers!"
+-msgstr "Il faut un nom d'utilisateur SAMBA pour exporter les pilotes d'imprimante !"
+-
+-msgid "A Samba password is required to export printer drivers!"
+-msgstr "Il faut un mot de passe SAMBA pour exporter les pilotes d'imprimante !"
+-
+-msgid "Unable to open cupsd.conf file:"
+-msgstr "Impossible d'ouvrir le fichier cupsd.conf :"
+-
+-msgid "Unable to change printer:"
+-msgstr "Impossible de modifier l'imprimante :"
+-
+-msgid "Set Allowed Users"
+-msgstr "Définir les autorisations"
+-
+-msgid "Unable to get printer attributes:"
+-msgstr "Impossible de récupérer les attributs de l'imprimante :"
+-
+-msgid "Set Publishing"
+-msgstr "Publier"
+-
+-msgid "Unable to change printer-is-shared attribute:"
+-msgstr "Impossible de modifier l'attribut « printer-is-shared » :"
+-
+-msgid "Classes"
+-msgstr "Classes"
+-
+-msgid "Unable to get class list:"
+-msgstr "Impossible d'obtenir la liste des classes :"
+-
+-msgid "Unable to get class status:"
+-msgstr "Impossible d'obtenir l'état de la classe :"
+-
+-msgid "Move Job"
+-msgstr "Transférer la tâche"
+-
+-msgid "Unable to find destination for job!"
+-msgstr "Impossible de trouver la destination de la tâche !"
+-
+-msgid "Move All Jobs"
+-msgstr "Transférer toutes les tâches"
+-
+-msgid "Unable to move job"
+-msgstr "Impossible de transférer la tâche !"
+-
+-msgid "Unable to move jobs"
+-msgstr "Impossible de transférer les tâches !"
+-
+-msgid "Print Test Page"
+-msgstr "Imprimer la page de test"
+-
+-msgid "Unable to print test page:"
+-msgstr "Impossible d'imprimer la page de test :"
+-
+-msgid "Jobs"
+-msgstr "Tâches"
+-
+-msgid "Job operation failed:"
+-msgstr "L'opération sur la tâche a échoué :"
+-
+-msgid "Printers"
+-msgstr "Imprimantes"
+-
+-msgid "Unable to get printer list:"
+-msgstr "Impossible d'obtenir la liste des imprimantes :"
+-
+-msgid "Unable to get printer status:"
+-msgstr "Impossible d'obtenir l'état de l'imprimante :"
+-
+-msgid "OK"
+-msgstr "OK"
+-
+-msgid "Unable to open PPD file"
+-msgstr "Impossible d'ouvrir le fichier PPD !"
+-
+-msgid "NULL PPD file pointer"
+-msgstr "Pointeur de fichier PPD NUL !"
+-
+-msgid "Memory allocation error"
+-msgstr "Problème d'allocation de mémoire"
+-
+-msgid "Missing PPD-Adobe-4.x header"
+-msgstr "Il manque l'entête PPD-Adobe-4.x"
+-
+-msgid "Missing value string"
+-msgstr "Il manque la valeur"
+-
+-msgid "Internal error"
+-msgstr "Erreur interne"
+-
+-msgid "Bad OpenGroup"
+-msgstr "OpenGroup erroné"
+-
+-msgid "OpenGroup without a CloseGroup first"
+-msgstr "OpenGroup sans de CloseGroup d'abord"
+-
+-msgid "Bad OpenUI/JCLOpenUI"
+-msgstr "OpenUI/JCLOpenUI erroné"
+-
+-msgid "OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"
+-msgstr "OpenUI/JCLOpenUI sans de CloseUI/JCLCloseUI d'abord"
+-
+-msgid "Bad OrderDependency"
+-msgstr "OrderDependency erroné"
+-
+-msgid "Bad UIConstraints"
+-msgstr "UIConstraints erroné"
+-
+-msgid "Missing asterisk in column 1"
+-msgstr "Il manque un astérisque à la colonne 1"
+-
+-msgid "Line longer than the maximum allowed (255 characters)"
+-msgstr "Ligne plus longue que les 255 caractères autorisés"
+-
+-msgid "Illegal control character"
+-msgstr "Caractère de contrôle incorrect"
+-
+-msgid "Illegal main keyword string"
+-msgstr "Mot-clé essentiel incorrect"
+-
+-msgid "Illegal option keyword string"
+-msgstr "Mot-clé d'option incorrect"
+-
+-msgid "Illegal translation string"
+-msgstr "Traduction incorrecte"
+-
+-msgid "Illegal whitespace character"
+-msgstr "Caractère « espace blanc » incorrect"
+-
+-msgid "Bad custom parameter"
+-msgstr "Paramètre de personnalisation incorrect"
+-
+-msgid "Unknown"
+-msgstr "Inconnu(e)"
+-
+-msgid "Custom"
+-msgstr "Personnalisation"
+-
+-msgid "JCL"
+-msgstr "JCL ( Langage de contrôle de tâche )"
+-
+-msgid "No authentication information provided!"
+-msgstr "Pas d'information d'authentification !"
+-
+-#, c-format
+-msgid "Password for %s required to access %s via SAMBA: "
+-msgstr "Il faut un mot de passe à %s pour accéder à %s via SAMBA : "
+-
+-#, c-format
+-msgid "Running command: %s %s -N -U '%s%%%s' -c '%s'\n"
+-msgstr "Exécute la commande : %s %s -N -U '%s%%%s' -c '%s'\n"
+-
+-#, c-format
+-msgid "cupsaddsmb: Unable to run \"%s\": %s\n"
+-msgstr "cupsaddsmb: Impossible d'exécuter « %s » : %s\n"
+-
+-msgid "cupsaddsmb: No Windows printer drivers are installed!\n"
+-msgstr "cupsaddsmb: Aucun pilote d'impression pour Windows n'est installé !\n"
+-
+-msgid "cupsaddsmb: Warning, no Windows 2000 printer drivers are installed!\n"
+-msgstr "cupsaddsmb: Attention, aucun pilote d'impression pour Windows 2000 n'est installé !\n"
+-
+-#, c-format
+-msgid "lpadmin: Printer %s is already a member of class %s.\n"
+-msgstr "lpadmin: L'imprimante %s est déjà membre de la classe %s.\n"
+-
+-msgid "lpadmin: No member names were seen!\n"
+-msgstr "lpadmin: Aucun nom de membre trouvé !\n"
+-
+-#, c-format
+-msgid "lpadmin: Printer %s is not a member of class %s.\n"
+-msgstr "lpadmin: L'imprimante %s n'est pas membre de la classe %s.\n"
+-
+-#, c-format
+-msgid ""
+-"Device: uri = %s\n"
+-"        class = %s\n"
+-"        info = %s\n"
+-"        make-and-model = %s\n"
+-"        device-id = %s\n"
+-msgstr ""
+-"Matériel :   URI = %s\n"
+-"          classe = %s\n"
+-"            info = %s\n"
+-"   marque/modèle = %s\n"
+-"     ID matériel = %s\n"
+-
+-#, c-format
+-msgid ""
+-"Model:  name = %s\n"
+-"        natural_language = %s\n"
+-"        make-and-model = %s\n"
+-"        device-id = %s\n"
+-msgstr ""
+-"Modèle :        nom = %s\n"
+-"   langue naturelle = %s\n"
+-"      marque/modèle = %s\n"
+-"     ID matériel = %s\n"
+-
+-
+-msgid "Usage: lpmove job/src dest\n"
+-msgstr "Utilisation : lpmove tâche/source destination\n"
+-
+-msgid "lpstat: Need \"completed\", \"not-completed\", or \"all\" after -W!\n"
+-msgstr "lpstat: Il faut « completed » ou « not-completed » après l'option -W !\n"
+-
+-#, c-format
+-msgid "%s accepting requests since %s\n"
+-msgstr "%s accepte les requêtes depuis le %s\n"
+-
+-#, c-format
+-msgid ""
+-"%s not accepting requests since %s -\n"
+-"\t%s\n"
+-msgstr ""
+-"%s n'accepte pas les requêtes depuis le %s -\n"
+-"\t%s\n"
+-
+-#, c-format
+-msgid "%s/%s accepting requests since %s\n"
+-msgstr "%s/%s accepte les requêtes depuis le %s\n"
+-
+-#, c-format
+-msgid ""
+-"%s/%s not accepting requests since %s -\n"
+-"\t%s\n"
+-msgstr ""
+-"%s/%s n'accepte pas les requêtes depuis le %s -\n"
+-"\t%s\n"
+-
+-msgid "lpc> "
+-msgstr "lpc> "
+-
+-#, c-format
+-msgid "%s: Unable to contact server!\n"
+-msgstr "%s: Impossible de contacter le serveur !\n"
+-
+-#, c-format
+-msgid "%s: Error - expected username after '-U' option!\n"
+-msgstr "%s: Erreur - il faut un nom d'utilisateur après l'option '-U' !\n"
+-
+-#, c-format
+-msgid "%s: Error - unknown destination \"%s/%s\"!\n"
+-msgstr "%s: Erreur - destination « %s/%s » inconnue !\n"
+-
+-#, c-format
+-msgid "%s: Unknown destination \"%s\"!\n"
+-msgstr "%s: Destination « %s » inconnue !\n"
+-
+-#, c-format
+-msgid "%s: Error - expected hostname after '-h' option!\n"
+-msgstr "%s: Erreur - il faut un nom de machine après l'option '-h' !\n"
+-
+-#, c-format
+-msgid "%s: error - %s environment variable names non-existent destination \"%s\"!\n"
+-msgstr "%s: Erreur - la variable d'environnement %s désigne une destination inexistente « %s » !\n"
+-
+-#, c-format
+-msgid "%s: error - no default destination available.\n"
+-msgstr "%s: Erreur - aucune destination par défaut n'est disponible.\n"
+-
+-msgid "Usage: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]\n"
+-msgstr "Utilisation : lpq [-P dest] [-U nom_utilisateur] [-h nom_machine[:port]] [-l] [+intervalle]\n"
+-
+-#, c-format
+-msgid "%s: Error - expected hostname after '-H' option!\n"
+-msgstr "%s: Erreur - il faut un nom de machine après l'option '-H' !\n"
+-
+-#, c-format
+-msgid "%s: Error - expected value after '-%c' option!\n"
+-msgstr "%s: Erreur - il faut une valeur après l'option '-%c' !\n"
+-
+-#, c-format
+-msgid "%s: Warning - '%c' format modifier not supported - output may not be correct!\n"
+-msgstr "%s: Attention - le modificateur de format '%c' n'est pas géré - l'affichage pourrait être incorrect !\n"
+-
+-#, c-format
+-msgid "%s: error - expected option=value after '-o' option!\n"
+-msgstr "%s: Erreur - il faut un argument du type option=valeur après l'option '-o' !\n"
+-
+-#, c-format
+-msgid "%s: Error - expected destination after '-P' option!\n"
+-msgstr "%s: Erreur - il faut une destination après l'option '-P' !\n"
+-
+-#, c-format
+-msgid "%s: Error - expected copy count after '-#' option!\n"
+-msgstr "%s: Erreur - il faut un nombre de copies après l'option '-#' !\n"
+-
+-#, c-format
+-msgid "%s: Error - expected name after '-%c' option!\n"
+-msgstr "%s: Erreur - il faut un nom après l'option '-%c' !\n"
+-
+-#, c-format
+-msgid "%s: Error - unknown option '%c'!\n"
+-msgstr "%s: Erreur - option '%c' inconnue !\n"
+-
+-#, c-format
+-msgid "%s: Error - unable to access \"%s\" - %s\n"
+-msgstr "%s: Erreur - impossible d'accéder à « %s » - %s\n"
+-
+-#, c-format
+-msgid "%s: Error - too many files - \"%s\"\n"
+-msgstr "%s: Erreur - trop de fichiers - « %s »\n"
+-
+-#, c-format
+-msgid "%s: Error - %s environment variable names non-existent destination \"%s\"!\n"
+-msgstr "%s: Erreur - la variable d'environnement %s désigne une destination inexistente « %s » !\n"
+-
+-#, c-format
+-msgid "%s: Error - no default destination available.\n"
+-msgstr "%s: Erreur - aucune destination par défaut n'est disponible.\n"
+-
+-#, c-format
+-msgid "%s: Error - scheduler not responding!\n"
+-msgstr "%s: Erreur - l'ordonnanceur ne répond pas !\n"
+-
+-#, c-format
+-msgid "%s: Error - unable to create temporary file \"%s\" - %s\n"
+-msgstr "%s: Erreur - impossible de créer le fichier temporaire « %s » - %s\n"
+-
+-#, c-format
+-msgid "%s: Error - unable to write to temporary file \"%s\" - %s\n"
+-msgstr "%s: Erreur - impossible d'écrire dans le fichier temporaire « %s » - %s\n"
+-
+-#, c-format
+-msgid "%s: Error - stdin is empty, so no job has been sent.\n"
+-msgstr "%s: Erreur - stdin est vide, donc aucune tâche n'a été envoyée.\n"
+-
+-#, c-format
+-msgid "%s: Error - unknown destination \"%s\"!\n"
+-msgstr "%s: Erreur - destination « %s » inconnue !\n"
+-
+-#, c-format
+-msgid "%s: Error - expected reason text after '-r' option!\n"
+-msgstr "%s: Erreur - il faut le texte de la raison après l'option '-r' !\n"
+-
+-#, c-format
+-msgid "%s: Error - expected username after '-u' option!\n"
+-msgstr "%s: Erreur - il faut un nom d'utilisateur après l'option '-u' !\n"
+-
+-#, c-format
+-msgid "%s: %s failed: %s\n"
+-msgstr ""%s: %s a échoué : %s"
+-
+-#, c-format
+-msgid "%s: Error - expected destination after '-d' option!\n"
+-msgstr "%s: Erreur - il faut une destination après l'option '-d' !\n"
+-
+-#, c-format
+-msgid "%s: Error - expected form after '-f' option!\n"
+-msgstr "%s: Erreur - il faut un format après l'option '-f' !\n"
+-
+-#, c-format
+-msgid "%s: Warning - form option ignored!\n"
+-msgstr "%s: Attention - l'option « format » est ignorée !\n"
+-
+-#, c-format
+-msgid "%s: Expected job ID after '-i' option!\n"
+-msgstr "%s: Il faut un numéro de tâche après l'option '-i' !\n"
+-
+-#, c-format
+-msgid "%s: Error - cannot print files and alter jobs simultaneously!\n"
+-msgstr "%s: Erreur - impossible d'imprimer et modifier les tâches en même temps !\n"
+-
+-#, c-format
+-msgid "%s: Error - bad job ID!\n"
+-msgstr "%s: Erreur - numéro de tâche incorrect !\n"
+-
+-#, c-format
+-msgid "%s: Error - expected copies after '-n' option!\n"
+-msgstr "%s: Erreur - il faut un nombre de copies après l'option '-n' !\n"
+-
+-#, c-format
+-msgid "%s: Error - expected option string after '-o' option!\n"
+-msgstr "%s: Erreur - il faut une chaîne d'option \"nom=valeur\" après l'option '-o' !\n"
+-
+-#, c-format
+-msgid "%s: Error - expected priority after '-%c' option!\n"
+-msgstr "%s: Erreur - il faut une priorité après l'option '-%c' !\n"
+-
+-#, c-format
+-msgid "%s: Error - priority must be between 1 and 100.\n"
+-msgstr "%s: Erreur - la priorité doit être comprise entre 1 et 100.\n"
+-
+-#, c-format
+-msgid "%s: Error - expected title after '-t' option!\n"
+-msgstr "%s: Erreur - il faut un titre après l'option '-t'  !\n"
+-
+-#, c-format
+-msgid "%s: Error - expected mode list after '-y' option!\n"
+-msgstr "%s: Erreur - il faut une liste de modes après l'option '-y' !\n"
+-
+-#, c-format
+-msgid "%s: Warning - mode option ignored!\n"
+-msgstr "%s: Attention - l'option « mode » est ignorée !\n"
+-
+-#, c-format
+-msgid "%s: Error - expected hold name after '-H' option!\n"
+-msgstr "%s: Erreur - il faut un code de retenue après l'option '-H' !\n"
+-
+-#, c-format
+-msgid "%s: Need job ID ('-i jobid') before '-H restart'!\n"
+-msgstr "%s: Il faut un numéro de tâche ( '-i' ) avant '-H restart' !\n"
+-
+-#, c-format
+-msgid "%s: Error - expected page list after '-P' option!\n"
+-msgstr "%s: Erreur - il faut une liste de pages après l'option '-P' !\n"
+-
+-#, c-format
+-msgid "%s: Error - expected character set after '-S' option!\n"
+-msgstr "%s: Erreur - il faut un jeu de caractères après l'option '-S' !\n"
+-
+-#, c-format
+-msgid "%s: Warning - character set option ignored!\n"
+-msgstr "%s: Attention - l'option « jeu de caractères » est ignorée !\n"
+-
+-#, c-format
+-msgid "%s: Error - expected content type after '-T' option!\n"
+-msgstr "%s: Erreur - il faut un type de contenu après l'option '-T' !\n"
+-
+-#, c-format
+-msgid "%s: Warning - content type option ignored!\n"
+-msgstr "%s: Attention - l'option « type de contenu » est ignorée !\n"
+-
+-#, c-format
+-msgid "%s: Error - cannot print from stdin if files or a job ID are provided!\n"
+-msgstr ""
+-"%s: Erreur - impossible d'imprimer depuis l'entrée standard si un fichier\n"
+-"             ou un numéro de tâche est spécifié !\n"
+-
+-#, c-format
+-msgid "%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' option!\n"
+-msgstr "%s: Erreur - il faut « completed », « not-completed », ou « all » après l'option -W !\n"
+-
+-#, c-format
+-msgid "%s: Error - expected destination after '-b' option!\n"
+-msgstr "%s: Erreur - il faut une destination après l'option '-b' !\n"
+-
+-#, c-format
+-msgid "%s: Invalid destination name in list \"%s\"!\n"
+-msgstr "%s: Erreur - nom de destination incorrect dans la liste « %s » !\n"
+-
+-#, c-format
+-msgid "%s: Unable to connect to server\n"
+-msgstr "%s: Impossible de se connecter au serveur !\n"
+-
+-msgid "Print Job:"
+-msgstr "Imprimer la tâche :"
+-
+-msgid "pending"
+-msgstr "en attente"
+-
+-msgid "held"
+-msgstr "retenue"
+-
+-msgid "processing"
+-msgstr "en cours"
+-
+-msgid "stopped"
+-msgstr "arrêtée"
+-
+-msgid "canceled"
+-msgstr "annulée"
+-
+-msgid "aborted"
+-msgstr "abandonnée"
+-
+-msgid "completed"
+-msgstr "terminée"
+-
+-msgid "unknown"
+-msgstr "inconnue"
+-
+-msgid "untitled"
+-msgstr "sans titre"
+-
+-msgid "Printer:"
+-msgstr "Imprimante :"
+-
+-msgid "idle"
+-msgstr "inactive"
+-
+-msgid "Missing notify-subscription-ids attribute!"
+-msgstr "Il manque l'attibut notify-subscription-ids"
+-
+-msgid "Job subscriptions cannot be renewed!"
+-msgstr "Les souscriptions de tâche ne peuvent être renouvelées !"
+-
+-
+-I AM HERE
+-
+-
+-msgid "cupsd: Expected config filename after \"-c\" option!\n"
+-msgstr "cupsd: Il faut un nom de fichier de configuration après l'option '-c' !\n"
+-
+-msgid "cupsd: launchd(8) support not compiled in, running in normal mode.\n"
+-msgstr "cupsd: la gestion de launchd(8) n'a pas été compilée - exécution en mode normal.\n"
+-
+-#, c-format
+-msgid "cupsd: Unknown option \"%c\" - aborting!\n"
+-msgstr "cupsd: Option « %c » inconnue - abandon !\n"
+-
+-#, c-format
+-msgid "cupsd: Unknown argument \"%s\" - aborting!\n"
+-msgstr "cupsd: Argument « %s » inconnu - abandon !\n"
+-
+-msgid ""
+-"Usage: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+-"\n"
+-"-c config-file      Load alternate configuration file\n"
+-"-f                  Run in the foreground\n"
+-"-F                  Run in the foreground but detach\n"
+-"-h                  Show this usage message\n"
+-"-l                  Run cupsd from launchd(8)\n"
+-msgstr ""
+-"Utilisation : cupsd [-c fichier-config] [-f] [-F] [-h] [-l]\n"
+-"\n"
+-"-c fichier-config   Charge un autre fichier de configuration\n"
+-"-f                  Exécution au premier plan\n"
+-"-F                  Exécution au premier plan mais détaché\n"
+-"-h                  Affiche the message d'aide\n"
+-"-l                  Exécute cupsd depuis launchd(8)\n"
+-
+-#, c-format
+-msgid "        WARN    Line %d only contains whitespace!\n"
+-msgstr "        WARN    Line %d only contains whitespace!\n"
+-
+-msgid "        WARN    File contains a mix of CR, LF, and CR LF line endings!\n"
+-msgstr "        WARN    File contains a mix of CR, LF, and CR LF line endings!\n"
+-
+-msgid "        WARN    Non-Windows PPD files should use lines ending with only LF, not CR LF!\n"
+-msgstr "        WARN    Non-Windows PPD files should use lines ending with only LF, not CR LF!\n"
+-
+-msgid "Printer Maintenance"
+-msgstr "Maintenance de l'imprimante"
+-
+-msgid "Unable to send maintenance job:"
+-msgstr "Impossible d'envoyer la tâche de maintenance :"
+-
+-#, c-format
+-msgid "cupsaddsmb: No PPD file for printer \"%s\" - %s\n"
+-msgstr "cupsaddsmb: Pas de fichier PPD pour l'imprimante « %s » - %s\n"
+-
+-#, c-format
+-msgid "      **FAIL**  %s %s does not exist!\n"
+-msgstr "      **FAIL**  %s %s does not exist!\n"
+-
+-#, c-format
+-msgid "      **FAIL**  Bad language \"%s\"!\n"
+-msgstr "      **FAIL**  Bad language \"%s\"!\n"
+-
+-#, c-format
+-msgid "      **FAIL**  Missing \"%s\" translation string for option %s!\n"
+-msgstr "      **FAIL**  Missing \"%s\" translation string for option %s!\n"
+-
+-#, c-format
+-msgid "      **FAIL**  Default translation string for option %s contains 8-bit characters!\n"
+-msgstr "      **FAIL**  Default translation string for option %s contains 8-bit characters!\n"
+-
+-#, c-format
+-msgid "      **FAIL**  Missing \"%s\" translation string for option %s, choice %s!\n"
+-msgstr "      **FAIL**  Missing \"%s\" translation string for option %s, choice %s!\n"
+-
+-#, c-format
+-msgid "      **FAIL**  Default translation string for option %s choice %s contains 8-bit characters!\n"
+-msgstr "      **FAIL**  Default translation string for option %s choice %s contains 8-bit characters!\n"
+-
+-#, c-format
+-msgid "      **FAIL**  Bad cupsFilter value \"%s\"!\n"
+-msgstr "      **FAIL**  Bad cupsFilter value \"%s\"!\n"
+-
+-msgid "Help"
+-msgstr "Aide"
+-
+-#, c-format
+-msgid "Missing value on line %d!\n"
+-msgstr "Il manque une valeur à la ligne %d !\n"
+-
+-#, c-format
+-msgid "Missing double quote on line %d!\n"
+-msgstr "Il manque un \" à la ligne %d !\n"
+-
+-#, c-format
+-msgid "Bad option + choice on line %d!\n"
+-msgstr "Couple option + choix incorrect à la ligne %d !\n"
+-
+-#, c-format
+-msgid "Unable to copy Windows 2000 printer driver files (%d)!\n"
+-msgstr "Impossible de copier les fichiers de pilote d'impression pour Windows 2000 ( %d ) !\n"
+-
+-#, c-format
+-msgid "Unable to copy CUPS printer driver files (%d)!\n"
+-msgstr "Impossible de copier les fichiers de pilote d'impression pour CUPS ( %d ) !\n"
+-
+-#, c-format
+-msgid "Unable to install Windows 2000 printer driver files (%d)!\n"
+-msgstr "Impossible d'installer les fichiers de pilote d'impression pour Windows 2000 ( %d ) !\n"
+-
+-#, c-format
+-msgid "Unable to copy Windows 9x printer driver files (%d)!\n"
+-msgstr "Impossible de copier les fichiers de pilote d'impression pour Windows 9x ( %d ) !\n"
+-
+-#, c-format
+-msgid "Unable to install Windows 9x printer driver files (%d)!\n"
+-msgstr "Impossible d'installer les fichiers de pilote d'impression pour Windows 9x ( %d ) !\n"
+-
+-msgid "No Windows printer drivers are installed!\n"
+-msgstr "Aucun pilote d'impression pour Windows n'est installé !\n"
+-
+-msgid "Warning, no Windows 2000 printer drivers are installed!\n"
+-msgstr "Attention, aucun pilote d'impression pour Windows 2000 n'est installé !\n"
+-
+-#, c-format
+-msgid "Unable to set Windows printer driver (%d)!\n"
+-msgstr "Impossible d'installer les fichiers de pilote d'impression pour Windows ( %d ) !\n""
+-
+-msgid ""
+-"Usage: cupsaddsmb [options] printer1 ... printerN\n"
+-"       cupsaddsmb [options] -a\n"
+-"\n"
+-"Options:\n"
+-"  -E               Encrypt the connection to the server\n"
+-"  -H samba-server  Use the named SAMBA server\n"
+-"  -U samba-user    Authenticate using the named SAMBA user\n"
+-"  -a               Export all printers\n"
+-"  -h cups-server   Use the named CUPS server\n"
+-"  -v               Be verbose (show commands)\n"
+-msgstr ""
+-"Utilisation : cupsaddsmb [options] imprimante1 ... imprimanteN\n"
+-"              cupsaddsmb [options] -a\n"
+-"\n"
+-"Options:\n"
+-"  -E                    Crypter la connexion au serveur\n"
+-"  -H serveur-samba      Utiliser le serveur SAMBA désigné\n"
+-"  -U utilisateur-samba  S'authentifier avec l'utilisateur SAMBA désigné\n"
+-"  -a                    Exporter toutes les imprimantes\n"
+-"  -h serveur-CUPS       Utiliser le serveur CUPS désigné\n"
+-"  -v                    Être locace ( afficher les commandes )\n"
+-
+-#, c-format
+-msgid "Unable to copy Windows 2000 printer driver files (%d)!"
+-msgstr "Impossible de copier les fichiers de pilote d'impression pour Windows 2000 ( %d ) !"
+-
+-#, c-format
+-msgid "Unable to copy CUPS printer driver files (%d)!"
+-msgstr "Impossible de copier les fichiers de pilote d'impression pour CUPS ( %d ) !"
+-
+-#, c-format
+-msgid "Unable to install Windows 2000 printer driver files (%d)!"
+-msgstr "Impossible d'installer les fichiers de pilote d'impression pour Windows 2000 ( %d ) !"
+-
+-#, c-format
+-msgid "Unable to copy Windows 9x printer driver files (%d)!"
+-msgstr "Impossible de copier les fichiers de pilote d'impression pour Windows 9x ( %d ) !"
+-
+-#, c-format
+-msgid "Unable to install Windows 9x printer driver files (%d)!"
+-msgstr "Impossible d'installer les fichiers de pilote d'impression pour Windows 9x ( %d ) !"
+-
+-msgid "No Windows printer drivers are installed!"
+-msgstr "Aucun pilote d'impression pour Windows n'est installé !"
+-
+-msgid "Warning, no Windows 2000 printer drivers are installed!"
+-msgstr "Attention, aucun pilote d'impression pour Windows 2000 n'est installé !"
+-
+-#, c-format
+-msgid "open of %s failed: %s"
+-msgstr "l'ouverture de %s a échoué : %s"
+-
+-#, c-format
+-msgid "Running command: %s %s -N -A %s -c '%s'\n"
+-msgstr "Exécution de la commande : %s %s -N -A %s -c '%s'\n"
+-
+-#, c-format
+-msgid "stat of %s failed: %s"
+-msgstr "stat sur %s a échoué : %s"
+-
+-#, c-format
+-msgid "Job #%d is already cancelled - can't cancel."
+-msgstr "La tâche n°%d est déjà annulée - impossible de l'annuler."
+-
+-#, c-format
+-msgid "Job #%d is already aborted - can't cancel."
+-msgstr "La tâche n°%d est déjà abandonnée - impossible de l'annuler."
+-
+-#, c-format
+-msgid "Job #%d is already completed - can't cancel."
+-msgstr "La tâche n°%d est déjà terminée - impossible de l'annuler."
+-
+-#, c-format
+-msgid "You must access this page using the URL <A HREF=\"https://%s:%d%s\">https://%s:%d%s</A>."
+-msgstr "Vous devez accéder à cette page avec l'URL <A HREF=\"https://%s:%d%s\">https://%s:%d%s</A>."
+-
+-#, c-format
+-msgid "Unsupported format '%s'!"
+-msgstr "Format non géré '%s' !"
+-
+-msgid "FAIL\n"
+-msgstr "ÉCHEC"
+-
+-#, c-format
+-msgid ""
+-"    Line %d is longer than 255 characters (%d)!\n"
+-"        REF: Page 25, Line Length\n"
+-msgstr ""
+-"    Line %d is longer than 255 characters (%d)!\n"
+-"        REF: Page 25, Line Length\n"
+-
+-msgid ""
+-"    Missing %!PS-Adobe-3.0 on first line!\n"
+-"        REF: Page 17, 3.1 Conforming Documents\n"
+-msgstr ""
+-"    Missing %!PS-Adobe-3.0 on first line!\n"
+-"        REF: Page 17, 3.1 Conforming Documents\n"
+-
+-#, c-format
+-msgid ""
+-"    Bad %%%%Pages: on line %d!\n"
+-"        REF: Page 43, %%%%Pages:\n"
+-msgstr ""
+-"    Bad %%%%Pages: on line %d!\n"
+-"        REF: Page 43, %%%%Pages:\n"
+-
+-#, c-format
+-msgid ""
+-"    Bad %%%%BoundingBox: on line %d!\n"
+-"        REF: Page 39, %%%%BoundingBox:\n"
+-msgstr ""
+-"    Bad %%%%BoundingBox: on line %d!\n"
+-"        REF: Page 39, %%%%BoundingBox:\n"
+-
+-#, c-format
+-msgid ""
+-"    Bad %%%%Page: on line %d!\n"
+-"        REF: Page 53, %%%%Page:\n"
+-msgstr ""
+-"    Bad %%%%Page: on line %d!\n"
+-"        REF: Page 53, %%%%Page:\n"
+-
+-#, c-format
+-msgid ""
+-"    Missing or bad %%BoundingBox: comment!\n"
+-"        REF: Page 39, %%BoundingBox:\n"
+-msgstr ""
+-"    Missing or bad %%BoundingBox: comment!\n"
+-"        REF: Page 39, %%BoundingBox:\n"
+-
+-#, c-format
+-msgid ""
+-"    Missing or bad %%Pages: comment!\n"
+-"        REF: Page 43, %%Pages:\n"
+-msgstr ""
+-"    Missing or bad %%Pages: comment!\n"
+-"        REF: Page 43, %%Pages:\n"
+-
+-#, c-format
+-msgid ""
+-"    Missing %%EndComments comment!\n"
+-"        REF: Page 41, %%EndComments\n"
+-msgstr ""
+-"    Missing %%EndComments comment!\n"
+-"        REF: Page 41, %%EndComments\n"
+-
+-#, c-format
+-msgid ""
+-"    Missing or bad %%Page: comments!\n"
+-"        REF: Page 53, %%Page:\n"
+-msgstr ""
+-"    Missing or bad %%Page: comments!\n"
+-"        REF: Page 53, %%Page:\n"
+-
+-#, c-format
+-msgid "    Too many %%EndDocument comments!\n"
+-msgstr "    Too many %%EndDocument comments!\n"
+-
+-#, c-format
+-msgid "    Too many %%BeginDocument comments!\n"
+-msgstr "    Too many %%BeginDocument comments!\n"
+-
+-#, c-format
+-msgid "    Saw %d lines that exceeded 255 characters!\n"
+-msgstr "    Saw %d lines that exceeded 255 characters!\n"
+-
+-msgid "PASS\n"
+-msgstr "OK"
+-
+-msgid "    Warning: file contains binary data!\n"
+-msgstr "    Warning: file contains binary data!\n"
+-
+-#, c-format
+-msgid "    Warning: obsolete DSC version %.1f in file!\n"
+-msgstr "    Warning: obsolete DSC version %.1f in file!\n"
+-
+-#, c-format
+-msgid "    Warning: no %%EndComments comment in file!\n"
+-msgstr "    Warning: no %%EndComments comment in file!\n"
+-
+-msgid ""
+-"Usage: cupstestdsc [options] filename.ps [... filename.ps]\n"
+-"       cupstestdsc [options] -\n"
+-"\n"
+-"Options:\n"
+-"\n"
+-"    -h       Show program usage\n"
+-"\n"
+-"    Note: this program only validates the DSC comments, not the PostScript itself.\n"
+-msgstr ""
+-"Usage: cupstestdsc [options] filename.ps [... filename.ps]\n"
+-"       cupstestdsc [options] -\n"
+-"\n"
+-"Options:\n"
+-"\n"
+-"    -h       Show program usage\n"
+-"\n"
+-"    Note: this program only validates the DSC comments, not the PostScript itself.\n"
+-
+-
+-#, c-format
+-msgid "Password for %s on %s? "
+-msgstr "Mot de passe pour %s sur %s? "
+-
+-msgid ""
+-"      **FAIL**  1284DeviceId must be 1284DeviceID!\n"
+-"                REF: Page 72, section 5.5\n"
+-msgstr ""
+-"      **FAIL**  1284DeviceId must be 1284DeviceID!\n"
+-"                REF: Page 72, section 5.5\n"
+-
+-
+-#
+-# End of "$Id$".
+-#
+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
+@@ -279,9 +279,16 @@
+ 
+   globalParams = new GlobalParams(buffer);
+ 
+-  globalParams->setPSPaperWidth(width);
+-  globalParams->setPSPaperHeight(length);
+-  globalParams->setPSImageableArea(left, bottom, right, top);
++  if (fit || globalParams->getPSPaperWidth() > 0)
++  {
++    // Only set paper size and area if we are fitting to the job's
++    // page size or the pdftops.conf file does not contain
++    // "psPaperSize match"...
++    globalParams->setPSPaperWidth(width);
++    globalParams->setPSPaperHeight(length);
++    globalParams->setPSImageableArea(left, bottom, right, top);
++  }
++
+   globalParams->setPSDuplex(duplex);
+   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
+@@ -3,7 +3,7 @@
+  *
+  *   Printer class routines for the Common UNIX Printing System (CUPS).
+  *
+- *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
++ *   Copyright 1997-2007 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
+@@ -371,7 +371,21 @@
+       {
+         cupsdLogMessage(CUPSD_LOG_DEBUG, "Loading class %s...", value);
+ 
+-        p = cupsdAddClass(value);
++       /*
++        * Since prior classes may have implicitly defined this class,
++	* see if it already exists...
++	*/
++
++        if ((p = cupsdFindDest(value)) != NULL)
++	{
++	  p->type = CUPS_PRINTER_CLASS;
++	  cupsdSetStringf(&p->uri, "ipp://%s:%d/classes/%s", ServerName,
++	                  LocalPort, value);
++	  cupsdSetString(&p->error_policy, "retry-job");
++	}
++	else
++          p = cupsdAddClass(value);
++
+ 	p->accepting = 1;
+ 	p->state     = IPP_PRINTER_IDLE;
+ 
+@@ -708,6 +722,7 @@
+   time_t		curtime;	/* Current time */
+   struct tm		*curdate;	/* Current date */
+   cups_option_t		*option;	/* Current option */
++  const char		*ptr;		/* Pointer into info/location */
+ 
+ 
+  /*
+@@ -782,10 +797,40 @@
+       cupsFilePrintf(fp, "<Class %s>\n", pclass->name);
+ 
+     if (pclass->info)
+-      cupsFilePrintf(fp, "Info %s\n", pclass->info);
++    {
++      if ((ptr = strchr(pclass->info, '#')) != NULL)
++      {
++       /*
++        * Need to quote the first # in the info string...
++	*/
++
++        cupsFilePuts(fp, "Info ");
++	cupsFileWrite(fp, pclass->info, ptr - pclass->info);
++	cupsFilePutChar(fp, '\\');
++	cupsFilePuts(fp, ptr);
++	cupsFilePutChar(fp, '\n');
++      }
++      else
++        cupsFilePrintf(fp, "Info %s\n", pclass->info);
++    }
+ 
+     if (pclass->location)
+-      cupsFilePrintf(fp, "Location %s\n", pclass->location);
++    {
++      if ((ptr = strchr(pclass->info, '#')) != NULL)
++      {
++       /*
++        * Need to quote the first # in the location string...
++	*/
++
++        cupsFilePuts(fp, "Location ");
++	cupsFileWrite(fp, pclass->location, ptr - pclass->location);
++	cupsFilePutChar(fp, '\\');
++	cupsFilePuts(fp, ptr);
++	cupsFilePutChar(fp, '\n');
++      }
++      else
++        cupsFilePrintf(fp, "Location %s\n", pclass->location);
++    }
+ 
+     if (pclass->state == IPP_PRINTER_STOPPED)
+     {
+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
+@@ -3472,7 +3472,7 @@
+   int		pid,			/* Process ID of command */
+ 		status;			/* Status of command */
+   char		command[1024],		/* Command */
+-		*argv[11],		/* Command-line arguments */
++		*argv[12],		/* Command-line arguments */
+ 		*envp[MAX_ENV + 1],	/* Environment variables */
+ 		home[1024],		/* HOME environment variable */
+ 		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
+@@ -96,7 +96,8 @@
+ 		            int destsize, cups_option_t **options,
+ 			    int *accepting, int *shared, ipp_pstate_t *state);
+ static int	print_file(http_t *http, int id, const char *filename,
+-		           const char *docname, const char *user, int last);
++		           const char *docname, const char *user,
++			   const char *format, int last);
+ static int	recv_print_job(const char *name, int num_defaults,
+ 		               cups_option_t *defaults);
+ static int	remove_jobs(const char *name, const char *agent,
+@@ -824,6 +825,7 @@
+ 	   const char *filename,	/* I - File to print */
+            const char *docname,		/* I - document-name */
+ 	   const char *user,		/* I - requesting-user-name */
++	   const char *format,		/* I - document-format */
+ 	   int        last)		/* I - 1 = last file in job */
+ {
+   ipp_t		*request;		/* IPP request */
+@@ -846,6 +848,10 @@
+     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+         	 "document-name", NULL, docname);
+ 
++  if (format)
++    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
++                 "document-format", NULL, format);
++
+   if (last)
+     ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1);
+ 
+@@ -1278,6 +1284,8 @@
+         	docnumber ++;
+ 
+         	if (print_file(http, id, temp[i], docname, user,
++		               cupsGetOption("document-format", num_options,
++			                     options),
+ 	                       docnumber == doccount))
+                   status = 1;
+ 		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
+@@ -5466,9 +5466,6 @@
+     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;
+ 
+@@ -5480,6 +5477,9 @@
+     if (!job->attrs)
+       continue;
+ 
++    if (username[0] && strcasecmp(username, job->username))
++      continue;
++
+     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
+@@ -420,9 +420,10 @@
+ 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 */
++  char		backname[1024],		/* Backup log filename */
++		filename[1024],		/* Formatted log filename */
++		*ptr;			/* Pointer into filename */
++  const char	*logptr;		/* Pointer into log filename */
+ 
+ 
+  /*
+@@ -454,17 +455,17 @@
+     else
+       filename[0] = '\0';
+ 
+-    for (ptr = filename + strlen(filename);
+-         *logname && ptr < (filename + sizeof(filename) - 1);
+-	 logname ++)
+-      if (*logname == '%')
++    for (logptr = logname, ptr = filename + strlen(filename);
++         *logptr && ptr < (filename + sizeof(filename) - 1);
++	 logptr ++)
++      if (*logptr == '%')
+       {
+        /*
+         * Format spec...
+ 	*/
+ 
+-        logname ++;
+-	if (*logname == 's')
++        logptr ++;
++	if (*logptr == 's')
+ 	{
+ 	 /*
+ 	  * Insert the server name...
+@@ -479,11 +480,11 @@
+ 	  * Otherwise just insert the character...
+ 	  */
+ 
+-	  *ptr++ = *logname;
++	  *ptr++ = *logptr;
+ 	}
+       }
+       else
+-	*ptr++ = *logname;
++	*ptr++ = *logptr;
+ 
+     *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);
 +
-   globalParams->setPSDuplex(duplex);
-   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-11 17:45:03.000000000 +0000
-+++ cupsys-1.2.8/scheduler/classes.c	2007-03-11 17:45:03.000000000 +0000
-@@ -3,7 +3,7 @@
-  *
-  *   Printer class routines for the Common UNIX Printing System (CUPS).
-  *
-- *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
-+ *   Copyright 1997-2007 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
-@@ -371,7 +371,21 @@
-       {
-         cupsdLogMessage(CUPSD_LOG_DEBUG, "Loading class %s...", value);
- 
--        p = cupsdAddClass(value);
-+       /*
-+        * Since prior classes may have implicitly defined this class,
-+	* see if it already exists...
-+	*/
++ /*
++  * Format the filename as needed...
++  */
 +
-+        if ((p = cupsdFindDest(value)) != NULL)
-+	{
-+	  p->type = CUPS_PRINTER_CLASS;
-+	  cupsdSetStringf(&p->uri, "ipp://%s:%d/classes/%s", ServerName,
-+	                  LocalPort, value);
-+	  cupsdSetString(&p->error_policy, "retry-job");
-+	}
-+	else
-+          p = cupsdAddClass(value);
++  if (!*lf ||
++      (strncmp(logname, "/dev/", 5) && cupsFileTell(*lf) > MaxLogSize &&
++       MaxLogSize > 0))
++  {
++   /*
++    * Handle format strings...
++    */
 +
- 	p->accepting = 1;
- 	p->state     = IPP_PRINTER_IDLE;
- 
-@@ -708,6 +722,7 @@
-   time_t		curtime;	/* Current time */
-   struct tm		*curdate;	/* Current date */
-   cups_option_t		*option;	/* Current option */
-+  const char		*ptr;		/* Pointer into info/location */
- 
- 
-  /*
-@@ -782,10 +797,40 @@
-       cupsFilePrintf(fp, "<Class %s>\n", pclass->name);
- 
-     if (pclass->info)
--      cupsFilePrintf(fp, "Info %s\n", pclass->info);
++    filename[sizeof(filename) - 1] = '\0';
++
++    if (logname[0] != '/')
 +    {
-+      if ((ptr = strchr(pclass->info, '#')) != NULL)
++      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 == '%')
 +      {
 +       /*
-+        * Need to quote the first # in the info string...
++        * Format spec...
 +	*/
 +
-+        cupsFilePuts(fp, "Info ");
-+	cupsFileWrite(fp, pclass->info, ptr - pclass->info);
-+	cupsFilePutChar(fp, '\\');
-+	cupsFilePuts(fp, ptr);
-+	cupsFilePutChar(fp, '\n');
++        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
-+        cupsFilePrintf(fp, "Info %s\n", pclass->info);
++	*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 (pclass->location)
--      cupsFilePrintf(fp, "Location %s\n", pclass->location);
++
++    if (strncmp(filename, "/dev/", 5))
 +    {
-+      if ((ptr = strchr(pclass->info, '#')) != NULL)
-+      {
-+       /*
-+        * Need to quote the first # in the location string...
-+	*/
++     /*
++      * Change ownership and permissions of non-device logs...
++      */
 +
-+        cupsFilePuts(fp, "Location ");
-+	cupsFileWrite(fp, pclass->location, ptr - pclass->location);
-+	cupsFilePutChar(fp, '\\');
-+	cupsFilePuts(fp, ptr);
-+	cupsFilePutChar(fp, '\n');
-+      }
-+      else
-+        cupsFilePrintf(fp, "Location %s\n", pclass->location);
++      fchown(cupsFileNumber(*lf), RunUser, Group);
++      fchmod(cupsFileNumber(*lf), LogFilePerm);
 +    }
- 
-     if (pclass->state == IPP_PRINTER_STOPPED)
-     {
++  }
++
++ /*
++  * 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-11 17:45:03.000000000 +0000
++++ cupsys-1.2.8/scheduler/printers.c	2007-03-13 15:02:07.000000000 +0000
 @@ -1286,6 +1286,7 @@
    time_t		curtime;	/* Current time */
    struct tm		*curdate;	/* Current date */
@@ -269,9 +13003,53 @@
      if (printer->device_uri)
        cupsFilePrintf(fp, "DeviceURI %s\n", printer->device_uri);
  
+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
+@@ -184,6 +184,11 @@
+     status = status_long(cupslpd_stdin[1], cupslpd_stdout[0], dest, opargs);
+   else if (!strcmp(op, "status-short"))
+     status = status_short(cupslpd_stdin[1], cupslpd_stdout[0], dest, opargs);
++  else
++  {
++    printf("Unknown operation \"%s\"!\n", op);
++    status = 1;
++  }
+ 
+  /*
+   * Kill the test program...
+@@ -296,8 +301,8 @@
+            "Hlocalhost\n"
+            "P%s\n"
+            "J%s\n"
+-           "ldfA%03.3dlocalhost\n"
+-           "UdfA%03.3dlocalhost\n"
++           "ldfA%03dlocalhost\n"
++           "UdfA%03dlocalhost\n"
+            "N%s\n",
+ 	   cupsUser(), jobname, sequence, sequence, jobname);
+ 
+@@ -307,7 +312,7 @@
+ 
+   bytes = strlen(control);
+ 
+-  snprintf(command, sizeof(command), "\002%d cfA%03.3dlocalhost\n",
++  snprintf(command, sizeof(command), "\002%d cfA%03dlocalhost\n",
+            bytes, sequence);
+ 
+   if ((status = do_command(outfd, infd, command)) != 0)
+@@ -344,7 +349,7 @@
+   * Send the data file...
+   */
+ 
+-  snprintf(command, sizeof(command), "\003%d dfA%03.3dlocalhost\n",
++  snprintf(command, sizeof(command), "\003%d dfA%03dlocalhost\n",
+            (int)fileinfo.st_size, sequence);
+ 
+   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-11 17:45:07.000000000 +0000
++++ cupsys-1.2.8/systemv/cupstestppd.c	2007-03-13 15:02:07.000000000 +0000
 @@ -3,7 +3,7 @@
   *
   *   PPD test program for the Common UNIX Printing System (CUPS).
@@ -517,3 +13295,1505 @@
 +/*
   * End of "$Id: cupstestppd.c 5926 2006-09-05 20:45:47Z mike $".
   */
+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
+@@ -31,36 +31,3 @@
+ </TABLE>
+ 
+ </FORM>
+-<FORM METHOD="POST" ACTION="/admin">
+-<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+-
+-<H2 CLASS="title">Ajouter une classe</H2>
+-
+-<TABLE>
+-<TR>
+-<TH CLASS="label">Nom :</TH>
+-<TD><INPUT TYPE="TEXT" NAME="PRINTER_NAME" SIZE="40" MAXLENGTH="127"></TD>
+-</TR>
+-<TR>
+-<TH CLASS="label">Lieu :</TH>
+-<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" SIZE="40" MAXLENGTH="127"></TD>
+-</TR>
+-<TR>
+-<TH CLASS="label">Description :</TH>
+-<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" SIZE="40" MAXLENGTH="127"></TD>
+-</TR>
+-<TR>
+-<TH CLASS="label">Membres :</TH>
+-<TD>
+-<SELECT NAME="MEMBER_URIS" SIZE="10" MULTIPLE>
+-{[member_uris]<OPTION VALUE="{member_uris}" {?member_selected}>{member_names}}
+-</SELECT>
+-</TD>
+-</TR>
+-<TR>
+-<TD></TD>
+-<TD><INPUT TYPE="IMAGE" SRC="/images/button-add-class.gif" ALT="Ajouter une classe"></TD>
+-</TR>
+-</TABLE>
+-
+-</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
+@@ -1,50 +1,23 @@
+ <FORM METHOD="POST" ACTION="/admin">
+ <INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
++{device_uri?<INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">:}
+ 
+ <H2 CLASS="title">Ajouter une nouvelle imprimante</H2>
+ 
+ <TABLE>
+ <TR>
+ <TH CLASS="label">Nom :</TH>
+-<TD><INPUT TYPE="TEXT" NAME="PRINTER_NAME" SIZE="40" MAXLENGTH="127"><BR>
+-<SMALL>( Peut comporter tout caractère imprimable, "/", "#", et espace exceptés )</SMALL></TD>
+-</TR>
+-<TR>
+-<TH CLASS="label">Lieu :</TH>
+-<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" SIZE="40" MAXLENGTH="127"><BR>
+-<SMALL>( Lieu compréhensible pour un utilisateur, comme "Labo 1" )</SMALL></TD>
+-</TR>
+-<TR>
+-<TH CLASS="label">Description :</TH>
+-<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" SIZE="40" MAXLENGTH="127"><BR>
+-<SMALL>( Description compréhensible pour un utilisateur, comme "HP LaserJet recto/verso" )</SMALL></TD>
+-</TR>
+-<TR>
+-<TD></TD>
+-<TD><INPUT TYPE="IMAGE" SRC="/images/button-continue.gif" ALT="Poursuivre"></TD>
+-</TR>
+-</TABLE>
+-
+-</FORM>
+-<FORM METHOD="POST" ACTION="/admin">
+-<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+-
+-<H2 CLASS="title">Ajouter une nouvelle imprimante</H2>
+-
+-<TABLE>
+-<TR>
+-<TH CLASS="label">Nom :</TH>
+-<TD><INPUT TYPE="TEXT" NAME="PRINTER_NAME" SIZE="40" MAXLENGTH="127"><BR>
++<TD><INPUT TYPE="TEXT" NAME="PRINTER_NAME" SIZE="40" MAXLENGTH="127" VALUE="{?template_name}"><BR>
+ <SMALL>( Peut comporter tout caractère imprimable, "/", "#", et espace exceptés )</SMALL></TD>
+ </TR>
+ <TR>
+ <TH CLASS="label">Lieu :</TH>
+-<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" SIZE="40" MAXLENGTH="127"><BR>
++<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" SIZE="40" MAXLENGTH="127" VALUE="{?PRINTER_LOCATION}"><BR>
+ <SMALL>( Lieu compréhensible pour un utilisateur, comme "Labo 1" )</SMALL></TD>
+ </TR>
+ <TR>
+ <TH CLASS="label">Description :</TH>
+-<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" SIZE="40" MAXLENGTH="127"><BR>
++<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" SIZE="40" MAXLENGTH="127" VALUE="{?PRINTER_INFO}"><BR>
+ <SMALL>( Description compréhensible pour un utilisateur, comme "HP LaserJet recto/verso" )</SMALL></TD>
+ </TR>
+ <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
+@@ -1,88 +1,5 @@
+ <TABLE CELLPADDING="0" CELLSPACING="0" WIDTH="100%" SUMMARY="Tâches d'administration">
+-<TR><TD VALIGN="TOP" NOWRAP>
+-
+-<H2 CLASS="title">Imprimantes</H2>
+-
+-<P>
+-<A HREF="/admin?op=add-printer"><IMG
+-SRC="/images/button-add-printer.gif" ALT="Ajouter une imprimante" CLASS="button"></A>
+-<A HREF="/printers/"><IMG SRC="/images/button-manage-printers.gif"
+-ALT="Administrer les imprimantes" CLASS="button"></A>
+-{have_samba?<A HREF="/admin/?op=export-samba"><IMG
+-SRC="/images/button-export-samba.gif" ALT="Exporter les imprimantes vers SAMBA"
+-CLASS="button"></A>:}
+-</P>
+-
+-{#device_uri=0?:<P><B>Nouvelles imprimantes détectées:</B></P><UL>{[device_uri]
+-<LI><A HREF="/admin?op=add-printer&amp;{device_options}"><IMG
+-SRC="/images/button-add-this-printer.gif" ALT="Ajouter cette imprimante" CLASS="button"
+-ALIGN="MIDDLE"></A>
+-{device_make_and_model} ({device_info})</LI>
+-}</UL>}
+-
+-<H2 CLASS="title">Classes</H2>
+-
+-<P>
+-<A HREF="/admin?op=add-class"><IMG SRC="/images/button-add-class.gif"
+-ALT="Ajouter une classe" CLASS="button"></A>
+-<A HREF="/classes/"><IMG SRC="/images/button-manage-classes.gif"
+-ALT="Administrer les classes" CLASS="button"></A>
+-</P>
+-
+-<H2 CLASS="title">Tâches d'impression</H2>
+-
+-<P>
+-<A HREF="/jobs/"><IMG SRC="/images/button-manage-jobs.gif" ALT="Administrer les
+-tâches" CLASS="button"></A>
+-</P>
+-
+-</TD><TD>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD><TD VALIGN="TOP">
+-
+-<H2 CLASS="title">Serveur</H2>
+-
+-<P>
+-<A HREF="/admin?op=config-server"><IMG
+-SRC="/images/button-edit-configuration-file.gif" ALT="Éditer le fichier de
+-configuration" CLASS="button"></A>
+-<A HREF="/admin/log/access_log" TARGET="_blank"><IMG
+-SRC="/images/button-view-access-log.gif" ALT="Liste des accès"
+-CLASS="button"></A>
+-<A HREF="/admin/log/error_log" TARGET="_blank"><IMG
+-SRC="/images/button-view-error-log.gif" ALT="Liste des erreurs"
+-CLASS="button"></A>
+-<A HREF="/admin/log/page_log" TARGET="_blank"><IMG
+-SRC="/images/button-view-page-log.gif" ALT="Liste des pages"
+-CLASS="button"></A>
+-</P>
+-
+-{SETTINGS_ERROR?<P>{SETTINGS_MESSAGE}</P>
+-<BLOCKQUOTE>{SETTINGS_ERROR}</BLOCKQUOTE>:
+-
+-<FORM METHOD="POST" ACTION="/admin">
+-
+-<P><B>Paramètres de base du serveur :</B></P>
+-
+-<P><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+-<INPUT TYPE="CHECKBOX" NAME="REMOTE_PRINTERS" {?remote_printers}> Afficher les
+-imprimantes partagées par d'autres systèmes<BR>
+-<INPUT TYPE="CHECKBOX" NAME="SHARE_PRINTERS" {?share_printers}> Partager les
+-imprimantes publiques connectées à ce système<BR>
+-<INPUT TYPE="CHECKBOX" NAME="REMOTE_ADMIN" {?remote_admin}> Autoriser
+-l'administration à distance<BR>
+-<INPUT TYPE="CHECKBOX" NAME="USER_CANCEL_ANY" {?user_cancel_any}> Autoriser les
+-utilisateurs à annuler n'importe quelle tâche ( pas seulement les leurs )<BR>
+-<INPUT TYPE="CHECKBOX" NAME="DEBUG_LOGGING" {?debug_logging}> Enregistrer les
+-informations de <I>debug</I> pour la résolution de problèmes</P>
+-
+-<P><INPUT TYPE="IMAGE" SRC="/images/button-change-settings.gif" ALT="Modifier
+-les paramètres"></P>
+-
+-</FORM>}
+-
+-</TD></TR>
+-</TABLE>
+-<TABLE CELLPADDING="0" CELLSPACING="0" WIDTH="100%" SUMMARY="Tâches d'administration">
+-<TR><TD VALIGN="TOP" NOWRAP>
++<TR><TD VALIGN="TOP">
+ 
+ <H2 CLASS="title">Imprimantes</H2>
+ 
+@@ -119,7 +36,7 @@
+ tâches" CLASS="button"></A>
+ </P>
+ 
+-</TD><TD>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD><TD VALIGN="TOP">
++</TD><TD>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD><TD VALIGN="TOP">
+ 
+ <H2 CLASS="title">Serveur</H2>
+ 
+@@ -150,6 +67,7 @@
+ imprimantes partagées par d'autres systèmes<BR>
+ <INPUT TYPE="CHECKBOX" NAME="SHARE_PRINTERS" {?share_printers}> Partager les
+ imprimantes publiques connectées à ce système<BR>
++&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="REMOTE_ANY" {?remote_any}> Allow printing from the Internet<BR>
+ <INPUT TYPE="CHECKBOX" NAME="REMOTE_ADMIN" {?remote_admin}> Autoriser
+ l'administration à distance<BR>
+ <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
+@@ -24,29 +24,3 @@
+ </TABLE>
+ 
+ </FORM>
+-<FORM METHOD="POST" ACTION="/admin">
+-<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+-<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+-<INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{?printer_location}">
+-<INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{?printer_info}">
+-<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{?current_make_and_model}">
+-
+-<H2 CLASS="title">Matériel pour {printer_name}</H2>
+-
+-<TABLE>
+-<TR>
+-<TH CLASS="label">Matériel :</TH>
+-<TD>
+-<SELECT NAME="DEVICE_URI">
+-{[device_uri]<OPTION VALUE="{device_uri}{?device_make_and_model!Unknown?|{device_make_and_model}:}" {?current_device_uri={device_uri}?SELECTED:{current_device_scheme={device_uri}?SELECTED:}}>
+-{device_info} {?device_make_and_model!Unknown?({device_make_and_model}):}</OPTION>
+-}</SELECT>
+-</TD>
+-</TR>
+-<TR>
+-<TD></TD>
+-<TD><INPUT TYPE="IMAGE" SRC="/images/button-continue.gif" ALT="Poursuivre"></TD>
+-</TR>
+-</TABLE>
+-
+-</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
+@@ -40,45 +40,3 @@
+ </TABLE>
+ 
+ </FORM>
+-<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+-<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+-<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+-<INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{?printer_location}">
+-<INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{?printer_info}">
+-<INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">
+-<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+-<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+-<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+-<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+-
+-<H2 CLASS="title">Marque/Fabricant pour {printer_name}</H2>
+-
+-<TABLE>
+-<TR>
+-<TH CLASS="label">Marque :</TH>
+-<TD>
+-<SELECT NAME="PPD_MAKE" SIZE="10">
+-{[ppd_make]<OPTION VALUE="{ppd_make}" {?current_make={ppd_make}?SELECTED:}>{ppd_make}}
+-</SELECT>
+-</TD>
+-</TR>
+-<TR>
+-<TD></TD>
+-<TD><INPUT TYPE="IMAGE" SRC="/images/button-continue.gif" ALT="Poursuivre"></TD>
+-</TR>
+-<TR>
+-<TD></TD>
+-<TD>&nbsp;</TD>
+-</TR>
+-<TR>
+-<TH CLASS="label">Ou donnez un fichier PPD :</TH>
+-<TD><INPUT TYPE="HIDDEN" NAME="MAX_FILE_SIZE" VALUE="262144"><INPUT
+-TYPE="FILE" NAME="PPD_FILE"></TD>
+-</TR>
+-<TR>
+-<TD></TD>
+-<TD><INPUT TYPE="IMAGE" SRC="/images/button-{op}.gif" ALT="{op=add-printer?Ajouter une imprimante:Modifier l'imprimante}"></TD>
+-</TR>
+-</TABLE>
+-
+-</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
+@@ -32,37 +32,3 @@
+ </TABLE>
+ 
+ </FORM>
+-<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+-<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+-<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+-<INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{?printer_location}">
+-<INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{?printer_info}">
+-<INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">
+-<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+-<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+-<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+-<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+-
+-<H2 CLASS="title">Modèle/Pilote pour {printer_name}</H2>
+-
+-<TABLE>
+-<TR>
+-<TH CLASS="label">Modèle:</TH>
+-<TD>
+-<SELECT NAME="PPD_NAME" SIZE="10">
+-{[ppd_name]<OPTION VALUE="{ppd_name}" {?current_make_and_model={ppd_make_and_model}?SELECTED:}>{ppd_make_and_model} ({ppd_natural_language})
+-}</SELECT>
+-</TD>
+-</TR>
+-<TR>
+-<TH CLASS="label">Ou donnez un fichier PPD :</TH>
+-<TD><INPUT TYPE="HIDDEN" NAME="MAX_FILE_SIZE" VALUE="262144"><INPUT
+-TYPE="FILE" NAME="PPD_FILE"></TD>
+-</TR>
+-<TR>
+-<TD></TD>
+-<TD><INPUT TYPE="IMAGE" SRC="/images/button-{op}.gif" ALT="{op=add-printer?Ajouter une imprimante:Modifier l'imprimante}"></TD>
+-</TR>
+-</TABLE>
+-
+-</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
+@@ -45,50 +45,3 @@
+ </TABLE>
+ 
+ </FORM>
+-<FORM METHOD="POST" ACTION="/admin">
+-<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+-<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+-<INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{?printer_location}">
+-<INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{?printer_info}">
+-<INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">
+-
+-<H2 CLASS="title">Paramètres du port série pour {printer_name}</H2>
+-
+-<TABLE>
+-<TR>
+-<TH CLASS="label">Baud/s :</TH>
+-<TD><SELECT NAME="BAUDRATE">
+-{[baudrates]<OPTION {?baudrate={baudrates}?SELECTED:}>{baudrates}}
+-</SELECT></TD>
+-</TR>
+-<TR>
+-<TH CLASS="label">Parité :</TH>
+-<TD><SELECT NAME="PARITY">
+-<OPTION VALUE="none" {?parity=none?SELECTED:}>Aucune
+-<OPTION VALUE="even" {?parity=even?SELECTED:}>Paire
+-<OPTION VALUE="odd" {?parity=odd?SELECTED:}>Impaire
+-</SELECT></TD>
+-</TR>
+-<TR>
+-<TH CLASS="label">Bits données :</TH>
+-<TD><SELECT NAME="BITS">
+-<OPTION {?bits=8?SELECTED:}>8
+-<OPTION {?bits=7?SELECTED:}>7
+-</SELECT></TD>
+-</TR>
+-<TR>
+-<TH CLASS="label">Contrôle de flux :</TH>
+-<TD><SELECT NAME="FLOW">
+-<OPTION VALUE="none" {?flow=none?SELECTED:}>Auncun
+-<OPTION VALUE="soft" {?flow=soft?SELECTED:}>XON/XOFF ( Logiciel )
+-<OPTION VALUE="hard" {?flow=hard?SELECTED:}>RTS/CTS ( Matériel )
+-<OPTION VALUE="dtrdsr" {?flow=dtrdsr?SELECTED:}>DTR/DSR ( Matériel )
+-</SELECT></TD>
+-</TR>
+-<TR>
+-<TD></TD>
+-<TD><INPUT TYPE="IMAGE" SRC="/images/button-continue.gif" ALT="Poursuivre"></TD>
+-</TR>
+-</TABLE>
+-
+-</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
+@@ -40,45 +40,3 @@
+ </TABLE>
+ 
+ </FORM>
+-<FORM METHOD="POST" ACTION="/admin">
+-<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+-<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+-<INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{?printer_location}">
+-<INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{?printer_info}">
+-<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{?current_make_and_model}">
+-
+-<H2 CLASS="title">URI du matériel pour {printer_name}</H2>
+-
+-<TABLE>
+-<TR>
+-<TH CLASS="label">URI du matériel :</TH>
+-<TD><INPUT TYPE="TEXT" SIZE="60" MAXLENGTH="1024" NAME="DEVICE_URI" VALUE="{device_uri}"></TD>
+-</TR>
+-<TR>
+-<TD></TD>
+-<TD>Exemples :
+-<PRE>
+-    http://nom_machine:631/ipp/
+-    http://nom_machine:631/ipp/port1
+-
+-    ipp://nom_machine/ipp/
+-    ipp://nom_machine/ipp/port1
+-
+-    lpd://nom_machine/queue
+-
+-    socket://nom_machine
+-    socket://nom_machine:9100
+-</PRE>
+-
+-<P>cf. <A HREF="/help/network.html" TARGET="_blank">"Network
+-Printers"</A> pour construire l'URI à employer avec votre imprimante.</P>
+-
+-</TD>
+-</TR>
+-<TR>
+-<TD></TD>
+-<TD><INPUT TYPE="IMAGE" SRC="/images/button-continue.gif" ALT="Poursuivre"></TD>
+-</TR>
+-</TABLE>
+-
+-</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
+@@ -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
+@@ -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"
+ CLASS="button"></A></P>
+-<P><B>Attention :</B> Êtes vous sûr(e) de vouloir supprimer la classe
+-{printer_name}?</P>
+-
+-<P ALIGN="CENTER"><A
+-HREF="/admin?op=delete-class&printer_name={printer_name}&confirm=yes"><IMG
+-SRC="/images/button-delete-class.gif" ALT="Supprimer la classe"
+-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
+@@ -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
+@@ -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
+@@ -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
+@@ -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
+@@ -52,57 +52,3 @@
+ </TR>
+ </TABLE>
+ }}
+-{#printer_name=0?:
+-{[printer_name]
+-<H2 CLASS="title"><A HREF="{printer_uri_supported}">{printer_name}</A>{default_name={printer_name}? ( Imprimante par défaut ) :}
+-{?printer_state_message=?:<SPAN CLASS="message">"{printer_state_message}"</SPAN>}</H2>
+-
+-<TABLE WIDTH="100%" CLASS="button" CELLSPACING="0" CELLPADDING="0" SUMMARY="{printer_name}">
+-<TR>
+-<TD VALIGN=TOP><A HREF="{printer_uri_supported}">
+-<IMG SRC="/images/classes.gif" CLASS="button" ALT=""></A></TD>
+-<TD VALIGN=TOP><B>Description :</B> {printer_info}<BR>
+-<B>Lieu :</B> {printer_location}<BR>
+-<B>État de la classe:</B> {printer_state=3?ne fait rien:{printer_state=4?en cours d'impression:arrêtée}},
+-{printer_is_accepting_jobs=0?rejette les tâches:accepte les tâches}, {printer_is_shared=0?cachée:publique}.
+-{?member_uris=?:<BR>Membres : {member_uris}}
+-
+-<P>
+-<A HREF="{printer_uri_supported}?op=print-test-page">
+-<IMG SRC="/images/button-print-test-page.gif" ALT="Imprimer une page de test" CLASS="button"></A>
+-{printer_state=5?
+-<A HREF="{admin_uri}?op=start-class&amp;printer_name={%printer_name}&amp;is_class=Y">
+-<IMG SRC="/images/button-start-class.gif" ALT="Démarrer la classe" CLASS="button"></A>
+-:
+-<A HREF="{admin_uri}?op=stop-class&amp;printer_name={%printer_name}&amp;is_class=Y">
+-<IMG SRC="/images/button-stop-class.gif" ALT="Arrêter la classe" CLASS="button"></A>
+-}
+-{printer_is_accepting_jobs=0?
+-<A HREF="{admin_uri}?op=accept-jobs&amp;printer_name={%printer_name}&amp;is_class=Y">
+-<IMG SRC="/images/button-accept-jobs.gif" ALT="Accepter les tâches" CLASS="button"></A>
+-:
+-<A HREF="{admin_uri}?op=reject-jobs&amp;printer_name={%printer_name}&amp;is_class=Y">
+-<IMG SRC="/images/button-reject-jobs.gif" ALT="Rejeter les tâches" CLASS="button"></A>
+-}
+-<A HREF="{admin_uri}?op=purge-jobs&amp;printer_name={%printer_name}&amp;is_class=Y">
+-<IMG SRC="/images/button-cancel-all-jobs.gif" ALT="Annuler toutes les tâches" CLASS="button"></A>
+-{printer_is_shared=0?
+-<A HREF="{admin_uri}?op=set-sharing&amp;printer_name={%printer_name}&amp;shared=1&amp;is_class=Y">
+-<IMG SRC="/images/button-publish-printer.gif" ALT="Publier l'imprimante" CLASS="button"></A>
+-:
+-<A HREF="{admin_uri}?op=set-sharing&amp;printer_name={%printer_name}&amp;shared=0&amp;is_class=Y">
+-<IMG SRC="/images/button-unpublish-printer.gif" ALT="Cacher l'imprimante" CLASS="button"></A>
+-}
+-<A HREF="{admin_uri}?op=modify-class&amp;printer_name={%printer_name}">
+-<IMG SRC="/images/button-modify-class.gif" ALT="Modifier la classe" CLASS="button"></A>
+-<A HREF="{admin_uri}?op=delete-class&amp;printer_name={%printer_name}">
+-<IMG SRC="/images/button-delete-class.gif" ALT="Supprimer la classe" CLASS="button"></A>
+-<A HREF="{admin_uri}?op=set-as-default&amp;printer_name={%printer_name}&amp;is_class=Y">
+-<IMG SRC="/images/button-set-as-default.gif" ALT="Choisir par défaut" CLASS="button"></A>
+-<A HREF="{admin_uri}?op=set-allowed-users&amp;printer_name={%printer_name}&amp;is_class=Y">
+-<IMG SRC="/images/button-set-allowed-users.gif" ALT="Définir les autorisations" CLASS="button"></A>
+-</P>
+-</TD>
+-</TR>
+-</TABLE>
+-}}
+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
+@@ -9,6 +9,7 @@
+ "\\n" +
+ "# Groupe des utilisateurs UNIX pour les administrateurs CUPS...\\n" +
+ "SystemGroup @CUPS_SYSTEM_GROUPS@\\n" +
++"@CUPS_SYSTEM_AUTHKEY@\\n" +
+ "\\n" +
+ "\\n" +
+ "# N'accepter que les connexions de la machine locale.\\n" +
+@@ -19,98 +20,7 @@
+ "# Publier les imprimantes partagées sur le réseau local.\\n" +
+ "Browsing On\\n" +
+ "BrowseOrder allow,deny\\n" +
+-"BrowseAllow @LOCAL\\n" +
+-"\\n" +
+-"\\n" +
+-"# S'authentifier par défaut via les comptes UNIX...\\n" +
+-"DefaultAuthType Basic\\n" +
+-"\\n" +
+-"# Restreindre l'accès au serveur...\\n" +
+-"<Location />\\n" +
+-"  Order allow,deny\\n" +
+-"  Allow localhost\\n" +
+-"</Location>\\n" +
+-"\\n" +
+-"# Restreindre l'accès aux pages d'administration...\\n" +
+-"<Location /admin>\\n" +
+-"@ENCRYPTION_REQUIRED@\\n" +
+-"  Order allow,deny\\n" +
+-"  Allow localhost\\n" +
+-"</Location>\\n" +
+-"\\n" +
+-"# Restreindre l'accès au ficher de configuration...\\n" +
+-"<Location /admin/conf>\\n" +
+-"  AuthType Basic\\n" +
+-"  Require user @SYSTEM\\n" +
+-"  Order allow,deny\\n" +
+-"  Allow localhost\\n" +
+-"</Location>\\n" +
+-"\\n" +
+-"# Définir la politique par défaut des tâches d'impression...\\n" +
+-"<Policy default>\\n" +
+-"  # Les opérations sur les tâches doivent être faites par leur propriétaire ou un adminstrateur...\\n" +
+-"  <Limit Send-Document Send-URI Hold-Job Release-Job Restart-Job Purge-Jobs Set-Job-Attributes Create-Job-Subscription Renew-Subscription Cancel-Subscription Get-Notifications Reprocess-Job Cancel-Current-Job Suspend-Current-Job Resume-Job CUPS-Move-Job>\\n" +
+-"    Require user @OWNER @SYSTEM\\n" +
+-"    Order deny,allow\\n" +
+-"  </Limit>\\n" +
+-"\\n" +
+-"  # Toutes les opérations d'administration nécessite l'authentification d'un adminstrateur...\\n" +
+-"  <Limit Pause-Printer Resume-Printer Set-Printer-Attributes Enable-Printer Disable-Printer Pause-Printer-After-Current-Job Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After CUPS-Add-Printer CUPS-Delete-Printer CUPS-Add-Class CUPS-Delete-Class CUPS-Accept-Jobs CUPS-Reject-Jobs CUPS-Set-Default>\\n" +
+-"    AuthType Basic\\n" +
+-"    Require user @SYSTEM\\n" +
+-"    Order deny,allow\\n" +
+-"  </Limit>\\n" +
+-"\\n" +
+-"  # Seuls le propriétaire et un administrateur peuvent annuler ou authentifier une tâche...\\n" +
+-"  <Limit Cancel-Job CUPS-Authenticate-Job>\\n" +
+-"    Require user @OWNER @SYSTEM\\n" +
+-"    Order deny,allow\\n" +
+-"  </Limit>\\n" +
+-"\\n" +
+-"  <Limit All>\\n" +
+-"    Order deny,allow\\n" +
+-"  </Limit>\\n" +
+-"</Policy>\\n";
+-}
+-</SCRIPT>
+-
+-<H2 CLASS="title">Ficher de configuration du serveur</H2>
+-
+-<FORM NAME="cups" METHOD="POST" ACTION="/admin/">
+-
+-<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+-
+-<TEXTAREA NAME="CUPSDCONF" COLS="80" ROWS="25">{CUPSDCONF}</TEXTAREA>
+-
+-<P><INPUT TYPE="IMAGE" SRC="/images/button-save-changes.gif"
+-ALT="Enregistrer les modifications"> <A
+-HREF="javascript:reset_config();"><IMG
+-SRC="/images/button-use-default-config.gif" CLASS="button"
+-ALT="Utiliser la configuration par défaut"></A></P>
+-
+-</FORM>
+-<SCRIPT TYPE="text/javascript">
+-function reset_config()
+-{
+-  document.cups.CUPSDCONF.value =
+-"# Écrire des informations générales dans error_log - changez \\"info\\" en \\"debug\\"\\n" +
+-"# pour la résolution de problème...\\n" +
+-"LogLevel info\\n" +
+-"\\n" +
+-"\\n" +
+-"# Groupe des utilisateurs UNIX pour les administrateurs CUPS...\\n" +
+-"SystemGroup @CUPS_SYSTEM_GROUPS@\\n" +
+-"\\n" +
+-"\\n" +
+-"# N'accepter que les connexions de la machine locale.\\n" +
+-"Listen localhost:@DEFAULT_IPP_PORT@\\n" +
+-"@CUPS_LISTEN_DOMAINSOCKET@\\n" +
+-"\\n" +
+-"\\n" +
+-"# Publier les imprimantes partagées sur le réseau local.\\n" +
+-"Browsing On\\n" +
+-"BrowseOrder allow,deny\\n" +
+-"BrowseAllow @LOCAL\\n" +
++"BrowseAllow all\\n" +
+ "\\n" +
+ "\\n" +
+ "# 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
+@@ -1,6 +1,3 @@
+ <P>Erreur :</P>
+ 
+ <BLOCKQUOTE>Opération inconnue : "{op}"!</BLOCKQUOTE>
+-<P>Erreur :</P>
+-
+-<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
+@@ -1,6 +1,3 @@
+ <P>{?message?{message}:Erreur :}</P>
+ 
+ <BLOCKQUOTE>{error}</BLOCKQUOTE>
+-<P>{?message?{message}:Erreur :}</P>
+-
+-<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
+@@ -61,66 +61,3 @@
+ <TR CLASS="page">
+ <TD WIDTH="15">&nbsp;</TD>
+ <TD COLSPAN="2" WIDTH="100%" STYLE="height: 100%;" VALIGN="TOP" CLASS="page">
+-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+-<HTML>
+-<HEAD>
+-	<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+-	<TITLE>{title} - CUPS @CUPS_VERSION@@CUPS_REVISION@</TITLE>
+-	<!-- Prevent caching of CGI content -->
+-	<META HTTP-EQUIV="Expires" CONTENT="now">
+-	<META HTTP-EQUIV="Pragma" CONTENT="no-cache"> 
+-	{refresh_page?<META HTTP-EQUIV="Refresh" CONTENT="{refresh_page}">:}
+-	<LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups.css">
+-	<LINK REL="SHORTCUT ICON" HREF="/favicon.ico" TYPE="image/x-icon">
+-</HEAD>
+-<BODY>
+-<TABLE WIDTH="100%" STYLE="height: 100%;" BORDER="0" CELLSPACING="0" CELLPADDING="0" SUMMARY="{title}">
+-<TR CLASS="HEADER">
+-<TD VALIGN="TOP" WIDTH="15" ROWSPAN="2"><IMG SRC="/images/top-left.gif" WIDTH="15" HEIGHT="80" ALT=""></TD>
+-<TD VALIGN="TOP" WIDTH="55" ROWSPAN="2"><IMG SRC="/images/top-middle.gif" WIDTH="55" HEIGHT="80" ALT=""></TD>
+-<TD WIDTH="100%" HEIGHT="60"><H1>{title}</H1></TD>
+-<TD ALIGN="RIGHT" VALIGN="TOP" WIDTH="15" ROWSPAN="2"><IMG
+-SRC="/images/top-right.gif" WIDTH="15" HEIGHT="15" ALT=""></TD>
+-</TR>
+-<TR CLASS="HEADER"><TD WIDTH="100%" VALIGN="BOTTOM" NOWRAP>
+-
+-<A CLASS="unsel" HREF="/"><IMG SRC="/images/tab-left.gif"
+-WIDTH="4" HEIGHT="4" ALIGN="TOP" BORDER="0"
+-ALT="">&nbsp;&nbsp;Accueil&nbsp;&nbsp;<IMG
+-SRC="/images/tab-right.gif" WIDTH="4" HEIGHT="4" ALIGN="TOP"
+-BORDER="0" ALT=""></A>
+-
+-&nbsp;<A CLASS="{SECTION=admin?:un}sel" HREF="/admin"><IMG
+-SRC="/images/tab-left.gif" WIDTH="4" HEIGHT="4" ALIGN="TOP"
+-BORDER="0" ALT="">&nbsp;&nbsp;Administration&nbsp;&nbsp;<IMG
+-SRC="/images/tab-right.gif" WIDTH="4" HEIGHT="4" ALIGN="TOP"
+-BORDER="0" ALT=""></A>
+-
+-&nbsp;<A CLASS="{SECTION=classes?:un}sel" HREF="/classes/"><IMG
+-SRC="/images/tab-left.gif" WIDTH="4" HEIGHT="4" ALIGN="TOP"
+-BORDER="0" ALT="">&nbsp;&nbsp;Classes&nbsp;&nbsp;<IMG
+-SRC="/images/tab-right.gif" WIDTH="4" HEIGHT="4" ALIGN="TOP"
+-BORDER="0" ALT=""></A>
+-
+-&nbsp;<A CLASS="{SECTION=help?:un}sel" HREF="/help/"><IMG
+-SRC="/images/tab-left.gif" WIDTH="4" HEIGHT="4" ALIGN="TOP"
+-BORDER="0" ALT="">&nbsp;&nbsp;Documentation/Aide&nbsp;&nbsp;<IMG
+-SRC="/images/tab-right.gif" WIDTH="4" HEIGHT="4" ALIGN="TOP"
+-BORDER="0" ALT=""></A>
+-
+-&nbsp;<A CLASS="{SECTION=jobs?:un}sel" HREF="/jobs/"><IMG
+-SRC="/images/tab-left.gif" WIDTH="4" HEIGHT="4" ALIGN="TOP"
+-BORDER="0" ALT="">&nbsp;&nbsp;Tâches&nbsp;&nbsp;<IMG
+-SRC="/images/tab-right.gif" WIDTH="4" HEIGHT="4" ALIGN="TOP"
+-BORDER="0" ALT=""></A>
+-
+-&nbsp;<A CLASS="{SECTION=printers?:un}sel" HREF="/printers/"><IMG
+-SRC="/images/tab-left.gif" WIDTH="4" HEIGHT="4" ALIGN="TOP"
+-BORDER="0" ALT="">&nbsp;&nbsp;Imprimantes&nbsp;&nbsp;<IMG
+-SRC="/images/tab-right.gif" WIDTH="4" HEIGHT="4" ALIGN="TOP"
+-BORDER="0" ALT=""></A>
+-
+-</TD></TR>
+-<TR CLASS="page">
+-<TD WIDTH="15">&nbsp;</TD>
+-<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
+@@ -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
+ fonctionnalités.</P>}
+-<FORM ACTION="/help/{?HELPFILE}" METHOD="GET">
+-{TOPIC?<INPUT TYPE="HIDDEN" NAME="TOPIC" VALUE="{TOPIC}">:}
+-
+-<P ALIGN="CENTER"><B>Rechercher dans 
+-{HELPTITLE?{HELPTITLE}:{TOPIC?{TOPIC}:Tous les Documents}}:</B> <INPUT
+-TYPE="TEXT" NAME="QUERY" VALUE="{?QUERY}" SIZE="60"> <INPUT
+-TYPE="IMAGE" SRC="/images/button-search.gif" ALT="Search">
+-<A HREF="/help/{?HELPFILE}{QUERY?{TOPIC??TOPIC={TOPIC}:}:}"><IMG
+-SRC="/images/button-clear.gif" ALT="Clear" CLASS="button"></A></P>
+-
+-</FORM>
+-
+-<!-- Bookmarks -->
+-<DIV CLASS="sidebar">
+-<H3 CLASS="title">Documents d'aide en ligne</H3>
+-
+-<P CLASS="l0"><A HREF="/help/{QUERY??QUERY={QUERY}:}">Tous les documents</A></P>
+-<HR>
+-
+-{[BMTEXT]<P CLASS="l{BMINDENT}"><A HREF="{BMLINK}">{BMTEXT}</A></P>
+-}
+-</DIV>
+-
+-{QUERY?<P>Résultats de la recherche dans {HELPFILE?{HELPTITLE}:{TOPIC?{TOPIC}:Tous les Documents}}\:</P>
+-{QTEXT?<UL>
+-{[QTEXT]<LI><A HREF="{QLINK}">{QTEXT}</A>{QPTEXT? (in <I><A HREF="{QPLINK}">{QPTEXT}</A></I>):}</LI>}
+-{QTEXT?</UL>:}
+-:<P>Aucun résultat.</P>}
+-<HR NOSHADE>:}
+-{HELPTITLE?<H1>{HELPTITLE}
+-<A HREF="/help/{HELPFILE}?PRINTABLE=YES" TARGET="_blank"><IMG
+-SRC="/images/button-view-printable-version.gif" ALT="Version imprimable"
+-CLASS="button"></A></H1>:<H1>Pages d'aide de CUPS</H1>
+-
+-<P>Voici l'interface d'aide en ligne de CUPS. Entrez ci-dessus les mots à rechercher
+-ou cliquez sur un lien ci-contre pour afficher l'ade en ligne du document.</P>
+-
+-<P><SMALL><B>NDT:</B> Cette interface n'a pas été traduite en Français. Si vous souhaitez vous
+-atteler à cette tâche, merci d'aller au préalable sur le forum <A
+-HREF="http://www.cups.org/newsgroups.php?gcups.development">cups.development</A>
+-pour en informer les développeurs.</SMALL></P>
+-
+-<P>Si vous êtes un nouvel utilisateur de CUPS, lisez la page "<a
+-href="overview.html">Overview of CUPS</a>". Il est conseillé aux utilisateurs
+-habitués de lire la page "<a href="whatsnew.html">What's New in CUPS
+-1.2</a>".</P>
+-
+-<P>La <A HREF="http://www.cups.org/">page d'accueil de CUPS</A> donne aussi
+-accès à de nombreuses ressources, comme des forums de discussion pour les
+-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
+-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
+@@ -9,14 +9,3 @@
+ <BODY>
+ 
+ <H1>{HELPTITLE}</H1>
+-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+-<HTML>
+-<HEAD>
+-	<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+-	<TITLE>{HELPTITLE}</TITLE>
+-	<LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups-printable.css">
+-	<LINK REL="SHORTCUT ICON" HREF="/favicon.ico" TYPE="image/x-icon">
+-</HEAD>
+-<BODY>
+-
+-<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
+@@ -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
+@@ -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
+@@ -20,25 +20,3 @@
+ </TABLE>
+ 
+ </FORM>
+-<FORM METHOD="POST" ACTION="/{SECTION}/{job_id?:{printer_name}}">
+-<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+-{job_id?<INPUT TYPE="HIDDEN" NAME="JOB_ID" VALUE="{job_id}">:}
+-
+-<H2 CLASS="title">{job_id?Transférer la tâche n°{job_id}:Transférer toutes les tâches}</H2>
+-
+-<TABLE>
+-<TR>
+-<TH CLASS="label">Nouvelle destination :</TH>
+-<TD>
+-<SELECT NAME="JOB_PRINTER_URI" SIZE="10">
+-{[job_printer_uri]<OPTION VALUE="{job_printer_uri}">{job_printer_name}}
+-</SELECT>
+-</TD>
+-</TR>
+-<TR>
+-<TD></TD>
+-<TD><INPUT TYPE="IMAGE" SRC="/images/button-move-job{job_id?:s}.gif" ALT="Transférer {job_id?la tâche:les tâches}"></TD>
+-</TR>
+-</TABLE>
+-
+-</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
+@@ -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>
+-<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>
+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
+@@ -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
+@@ -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
+@@ -14,19 +14,3 @@
+ 
+ <P ALIGN="CENTER">{total=0?Aucune tâche:Affichage de {#job_id}
+ tâche{#job_id=1?:s} {?which_jobs=?en cours:{which_jobs=all?:terminée{#job_id=1?:s}}} sur {total}}.</P>
+-<P>{?which_jobs=?<A
+-HREF="{?printer_name=?/jobs:{printer_uri_supported}}?which_jobs=completed"><IMG
+-SRC="/images/button-show-completed.gif" CLASS="button" ALT="Montrer les tâches terminées"></A>
+-<A HREF="{?printer_name=?/jobs:{printer_uri_supported}}?which_jobs=all"><IMG
+-SRC="/images/button-show-all.gif" CLASS="button" ALT="Montrer toutes les tâches">:{which_jobs=all?<A
+-HREF="{?printer_name=?/jobs:{printer_uri_supported}}?which_jobs=completed"><IMG
+-SRC="/images/button-show-completed.gif" CLASS="button" ALT="Montrer les tâches terminées"></A>
+-<A HREF="{?printer_name=?/jobs:{printer_uri_supported}}"><IMG
+-SRC="/images/button-show-active.gif" CLASS="button" ALT="Montrer les tâches en cours">:<A
+-HREF="{?printer_name=?/jobs:{printer_uri_supported}}"><IMG
+-SRC="/images/button-show-active.gif" CLASS="button" ALT="Montrer les tâches en cours"></A>
+-<A HREF="{?printer_name=?/jobs:{printer_uri_supported}}?which_jobs=all"><IMG
+-SRC="/images/button-show-all.gif" CLASS="button" ALT="Montrer toutes les tâches">}}</A></P>
+-
+-<P ALIGN="CENTER">{total=0?Aucune tâche:Affichage de {#job_id}
+-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
+@@ -40,45 +40,3 @@
+ }
+ </TABLE>
+ }
+-{#job_id=0?:
+-<TABLE CELLPADDING="0" CELLSPACING="0" CLASS="button" WIDTH="100%" SUMMARY="Liste de tâches">
+-<TR CLASS="data">
+-<TH>N°&nbsp;</TH>
+-<TH>Nom&nbsp;</TH>
+-<TH>Utilisateur&nbsp;</TH>
+-<TH>Taille&nbsp;</TH>
+-<TH>Pages&nbsp;</TH>
+-<TH>État&nbsp;</TH>
+-<TH>Contrôle&nbsp;</TH>
+-</TR>
+-
+-{[job_id]
+-<TR CLASS="data" VALIGN="TOP">
+-<TD><A HREF="{job_printer_uri}">{job_printer_name}</A>-{job_id}&nbsp;</TD>
+-<TD>{?job_name=?Inconnue:{job_name}}&nbsp;</TD>
+-<TD>{job_originating_user_name}&nbsp;</TD>
+-<TD>{job_k_octets}ko&nbsp;</TD>
+-<TD>{job_media_sheets_completed=0?Inconnue:{?job_media_sheets_completed}}</TD>
+-<TD>{job_state=3?en attente depuis le<BR>{time_at_creation}:{job_state=4?retenue depuis le<BR>{time_at_creation}:
+-{job_state=5?en cours depuis le<BR>{time_at_processing}:{job_state=6?arrêtée:
+-{job_state=7?annulée le<BR>{time_at_completed}:{job_state=8?abandonnée:terminée le<BR>{time_at_completed}}}}}}}&nbsp;</TD>
+-<TD>
+-{job_preserved>0?
+-<A HREF="/jobs/?op=restart-job&amp;job_id={job_id}&amp;job_printer_uri={job_printer_uri}">
+-<IMG SRC="/images/button-restart-job.gif" ALT="Redémarrer la tâche" CLASS="button"></A>:}
+-{job_state=4?
+-<A HREF="/jobs/?op=release-job&amp;job_id={job_id}&amp;job_printer_uri={job_printer_uri}">
+-<IMG SRC="/images/button-release-job.gif" ALT="Libérer la tâche" CLASS="button"></A>:}
+-{job_state=3?
+-<A HREF="/jobs/?op=hold-job&amp;job_id={job_id}&amp;job_printer_uri={job_printer_uri}">
+-<IMG SRC="/images/button-hold-job.gif" ALT="Retenir la tâche" CLASS="button"></A>:}
+-{job_state<7?
+-<A HREF="/jobs/?op=cancel-job&amp;job_id={job_id}&amp;job_printer_uri={job_printer_uri}">
+-<IMG SRC="/images/button-cancel-job.gif" ALT="Annuler la tâche" CLASS="button"></A>
+-<A HREF="/jobs/?op=move-job&amp;job_id={job_id}"><IMG
+-SRC="/images/button-move-job.gif" ALT="Transférer la tâche" CLASS="button"></A>:}
+-&nbsp;</TD>
+-</TR>
+-}
+-</TABLE>
+-}
+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
+@@ -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>
+-<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>
+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
+@@ -32,37 +32,3 @@
+ </TABLE>
+ 
+ </FORM>
+-<FORM METHOD="POST" ACTION="/admin">
+-<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+-
+-<H2 CLASS="title">Modifier la classe {printer_name}</H2>
+-
+-<TABLE>
+-<TR>
+-<TH CLASS="label">Nom :</TH>
+-<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+-{printer_name}</TD>
+-</TR>
+-<TR>
+-<TH CLASS="label">Lieu :</TH>
+-<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" VALUE="{?printer_location}" SIZE="40" MAXLENGTH="127"></TD>
+-</TR>
+-<TR>
+-<TH CLASS="label">Description :</TH>
+-<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" VALUE="{?printer_info}" SIZE="40" MAXLENGTH="127"></TD>
+-</TR>
+-<TR>
+-<TH CLASS="label">Membres :</TH>
+-<TD>
+-<SELECT NAME="MEMBER_URIS" SIZE="10" MULTIPLE>
+-{[member_uris]<OPTION VALUE="{member_uris}" {?member_selected}>{member_names}}
+-</SELECT>
+-</TD>
+-</TR>
+-<TR>
+-<TD></TD>
+-<TD><INPUT TYPE="IMAGE" SRC="/images/button-modify-class.gif" ALT="Modifier la classe"></TD>
+-</TR>
+-</TABLE>
+-
+-</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
+@@ -27,32 +27,3 @@
+ </TABLE>
+ 
+ </FORM>
+-<FORM METHOD="POST" ACTION="/admin">
+-<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+-{?device_uri=?:<INPUT TYPE="HIDDEN" NAME="CURRENT_DEVICE_URI" VALUE="{device_uri}">}
+-{?printer_make_and_model=?:<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{printer_make_and_model}">}
+-
+-<H2 CLASS="title">Modifier l'imprimante {printer_name}</H2>
+-
+-<TABLE>
+-<TR>
+-<TH CLASS="label">Nom :</TH>
+-<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">{printer_name}</TD>
+-</TR>
+-<TR>
+-<TH CLASS="label">Lieu :</TH>
+-<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" VALUE="{?printer_location}" SIZE="40" MAXLENGTH="127"><BR>
+-<SMALL>( Lieu compréhensible pour un utilisateur, comme "Labo 1" )</SMALL></TD>
+-</TR>
+-<TR>
+-<TH CLASS="label">Description :</TH>
+-<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" VALUE="{?printer_info}" SIZE="40" MAXLENGTH="127"><BR>
+-<SMALL>( Description compréhensible pour un utilisateur, comme "HP LaserJet recto/verso" )</SMALL></TD>
+-</TR>
+-<TR>
+-<TD></TD>
+-<TD><INPUT TYPE="IMAGE" SRC="/images/button-continue.gif" ALT="Poursuivre"></TD>
+-</TR>
+-</TABLE>
+-
+-</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
+@@ -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
+@@ -5,10 +5,3 @@
+ {[choices]<INPUT TYPE="RADIO" NAME="{keyword}" {choices={defchoice}?CHECKED:} VALUE="{choices}">{text}}
+ </TD>
+ </TR>
+-<TR>
+-<TH CLASS="label"{conflicted=1? CLASS="conflict":}><A
+-NAME="{keyword}">{keytext}</A> :</TH>
+-<TD>
+-{[choices]<INPUT TYPE="RADIO" NAME="{keyword}" {choices={defchoice}?CHECKED:} VALUE="{choices}">{text}}
+-</TD>
+-</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
+@@ -5,10 +5,3 @@
+ }</UL>
+ 
+ <P>Veuillez modifier une ou plusieurs des ces options pour résoudre les conflits.</P>
+-<P><B>Erreur :</B> Les options suivantes sont incompatibles entre elles :</P>
+-
+-<UL>
+-{[ckeyword]<LI><A HREF="#{ckeyword}">{ckeytext}</A></LI>
+-}</UL>
+-
+-<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
+@@ -1,6 +1,3 @@
+ <H2 CLASS="title">{printer_name} : {group}</H2>
+ 
+ <TABLE>
+-<H2 CLASS="title">{printer_name} : {group}</H2>
+-
+-<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
+@@ -5,10 +5,3 @@
+ {[choices]<OPTION {choices={defchoice}?SELECTED:} VALUE="{choices}">{text}}
+ </SELECT></TD>
+ </TR>
+-<TR>
+-<TH CLASS="label"{conflicted=1? CLASS="conflict":}><A
+-NAME="{keyword}">{keytext}</A> :</TH>
+-<TD><SELECT NAME="{keyword}" MULTIPLE SIZE="10">
+-{[choices]<OPTION {choices={defchoice}?SELECTED:} VALUE="{choices}">{text}}
+-</SELECT></TD>
+-</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
+@@ -5,10 +5,3 @@
+ {[choices]<OPTION {choices={defchoice}?SELECTED:} VALUE="{choices}">{text}}
+ </SELECT></TD>
+ </TR>
+-<TR>
+-<TH CLASS="label"{conflicted=1? CLASS="conflict":}><A
+-NAME="{keyword}">{keytext}</A> :</TH>
+-<TD><SELECT NAME="{keyword}">
+-{[choices]<OPTION {choices={defchoice}?SELECTED:} VALUE="{choices}">{text}}
+-</SELECT></TD>
+-</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
+@@ -4,9 +4,3 @@
+ ALT="Définir les options de l'imprimante"></TD>
+ </TR>
+ </TABLE>
+-<TR>
+-<TD></TD>
+-<TD><INPUT TYPE="IMAGE" SRC="/images/button-set-printer-options.gif"
+-ALT="Définir les options de l'imprimante"></TD>
+-</TR>
+-</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
+@@ -9,14 +9,3 @@
+         SRC="/images/button-show-next.gif" ALT="Montrer les suivantes" CLASS="button"></A>:&nbsp;}</TD>
+ </TR>
+ </TABLE>
+-<TABLE WIDTH="100%" CLASS="pager" SUMMARY="Mise en page">
+-<TR>
+-	<TD WIDTH="33%">{PREVURL?<A HREF="{PREVURL}"><IMG
+-        SRC="/images/button-show-previous.gif" ALT="Montrer les précédentes" CLASS="button"></A>:&nbsp;}</TD>
+-	<TD WIDTH="34%" ALIGN="CENTER">{ORDER=dec?<A
+-        HREF="{THISURL}&amp;ORDER=asc"><IMG
+-        SRC="/images/button-sort-ascending.gif" ALT="Par ordre croissant" CLASS="button"></A>:<A HREF="{THISURL}&amp;ORDER=dec"><IMG SRC="/images/button-sort-descending.gif" ALT="Par ordre décroissant" CLASS="button"></A>}</TD>
+-	<TD WIDTH="33%" ALIGN="RIGHT">{NEXTURL?<A HREF="{NEXTURL}"><IMG
+-        SRC="/images/button-show-next.gif" ALT="Montrer les suivantes" CLASS="button"></A>:&nbsp;}</TD>
+-</TR>
+-</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
+@@ -1,6 +1,3 @@
+ <P>{is_class?Class:Printer} <A
+ HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+ accepte désormais les tâches d'impression.</P>
+-<P>{is_class?Class:Printer} <A
+-HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+-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
+@@ -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
+@@ -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
+@@ -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"
+ CLASS="button"></A></P>
+-<P><B>Attention :</B> Êtes-vous sûr(e) de vouloir supprimer l'imprimante
+-{printer_name} ?</P>
+-
+-<P ALIGN="CENTER"><A
+-HREF="/admin?op=delete-printer&printer_name={printer_name}&confirm=yes"><IMG
+-SRC="/images/button-delete-printer.gif" ALT="Supprimer l'imprimante"
+-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
+@@ -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
+ ignoré.</BLOCKQUOTE>
+-<P>{is_class?La classe:L'imprimante} <A
+-HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+-a été définie comme imprimante par défaut sur le serveur.</P>
+-
+-<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
+-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
+@@ -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
+@@ -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
+@@ -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
+@@ -1,6 +1,3 @@
+ <P>{is_class?La classe:L'imprimante} <A
+ HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+ a été nettoyée de toute tâche... d'impression !</P>
+-<P>{is_class?La classe:L'imprimante} <A
+-HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+-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
+@@ -1,6 +1,3 @@
+ <P>{is_class?La classe:L'imprimante} <A
+ HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+ n'accepte plus les tâches d'impression.</P>
+-<P>{is_class?La classe:L'imprimante} <A
+-HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+-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
+@@ -1,6 +1,3 @@
+ <P>{is_class?La classe:L'imprimante} <A
+ HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+ a été démarrée.</P>
+-<P>{is_class?La classe:L'imprimante} <A
+-HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+-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
+@@ -1,6 +1,3 @@
+ <P>{is_class?La classe:L'imprimante} <A
+ HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+ a été arrêtée.</P>
+-<P>{is_class?La classe:L'imprimante} <A
+-HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+-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
+@@ -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
+@@ -64,69 +64,3 @@
+ </TR>
+ </TABLE>
+ }}
+-{printer_type?:}{#printer_name=0?:
+-{[printer_name]
+-<H2 CLASS="title"><A
+-HREF="{printer_uri_supported}">{printer_name}</A>{default_name={printer_name}? (
+-imprimante par défaut ) :}
+-{?printer_state_message=?:<SPAN CLASS="message">"{printer_state_message}"</SPAN>}</H2>
+-
+-<TABLE WIDTH="100%" CLASS="button" CELLSPACING="0" CELLPADDING="0" SUMMARY="{printer_name}">
+-<TR>
+-<TD VALIGN="TOP"><A HREF="{printer_uri_supported}">
+-<IMG SRC="/images/printer-{printer_state=3?idle:{printer_state=4?processing:stopped}}.gif" CLASS="button" ALT=""></A>
+-</TD>
+-<TD VALIGN="TOP"><B>Description :</B> {printer_info}<BR>
+-<B>Lieu :</B> {printer_location}<BR>
+-<B>Marque et modèle :</B> {printer_make_and_model}<BR>
+-<B>État de l'imprimante :</B> {printer_state=3?ne fait rien:{printer_state=4?en cours d'impression:arrêtée}},
+-{printer_is_accepting_jobs=0?rejette les tâches:accepte les tâches}, {printer_is_shared=0?cachée:publique}.
+-{?device_uri=?:<BR><B>URI du matériel :</B> {device_uri}}
+-
+-<P>
+-<A HREF="{printer_uri_supported}?op=print-test-page">
+-<IMG SRC="/images/button-print-test-page.gif" ALT="Imprimer la page de test CUPS" CLASS="button"></A>
+-{?cupscommand=1?<A HREF="{printer_uri_supported}?op=clean-print-heads">
+-<IMG SRC="/images/button-clean-print-heads.gif" ALT="Nettoyer les têtes d'impression" CLASS="button"></A>
+-<A HREF="{printer_uri_supported}?op=print-self-test-page">
+-<IMG SRC="/images/button-print-self-test-page.gif" ALT="Imprimer la page de test de l'imprimante" CLASS="button"></A>:}
+-{printer_state=5?
+-<A HREF="{admin_uri}?op=start-printer&amp;printer_name={%printer_name}">
+-<IMG SRC="/images/button-start-printer.gif" ALT="Démarrer l'imprimante" CLASS="button"></A>
+-:
+-<A HREF="{admin_uri}?op=stop-printer&amp;printer_name={%printer_name}">
+-<IMG SRC="/images/button-stop-printer.gif" ALT="Arrêter l'imprimante" CLASS="button"></A>
+-}
+-{printer_is_accepting_jobs=0?
+-<A HREF="{admin_uri}?op=accept-jobs&amp;printer_name={%printer_name}">
+-<IMG SRC="/images/button-accept-jobs.gif" ALT="Accepter les tâches" CLASS="button"></A>
+-:
+-<A HREF="{admin_uri}?op=reject-jobs&amp;printer_name={%printer_name}">
+-<IMG SRC="/images/button-reject-jobs.gif" ALT="Rejeter les tâches" CLASS="button"></A>
+-}
+-<A HREF="{printer_uri_supported}?op=move-jobs&amp;printer_name={%printer_name}">
+-<IMG SRC="/images/button-move-jobs.gif" ALT="Transférer toutes les tâches" CLASS="button"></A>
+-<A HREF="{admin_uri}?op=purge-jobs&amp;printer_name={%printer_name}">
+-<IMG SRC="/images/button-cancel-all-jobs.gif" ALT="Annuler toutes les tâches" CLASS="button"></A>
+-{printer_is_shared=0?
+-<A HREF="{admin_uri}?op=set-sharing&amp;printer_name={%printer_name}&amp;shared=1">
+-<IMG SRC="/images/button-publish-printer.gif" ALT="Publier l'imprimante" CLASS="button"></A>
+-:
+-<A HREF="{admin_uri}?op=set-sharing&amp;printer_name={%printer_name}&amp;shared=0">
+-<IMG SRC="/images/button-unpublish-printer.gif" ALT="Cacher l'imprimante" CLASS="button"></A>
+-}
+-<A HREF="{admin_uri}?op=modify-printer&amp;printer_name={%printer_name}">
+-<IMG SRC="/images/button-modify-printer.gif" ALT="Modifier l'imprimante" CLASS="button"></A>
+-<A HREF="{admin_uri}?op=set-printer-options&amp;printer_name={%printer_name}">
+-<IMG SRC="/images/button-set-printer-options.gif" ALT="Définir les options de l'imprimante" CLASS="button"></A>
+-<A HREF="{admin_uri}?op=delete-printer&amp;printer_name={%printer_name}">
+-<IMG SRC="/images/button-delete-printer.gif" ALT="Supprimer l'imprimante" CLASS="button"></A>
+-<A HREF="{admin_uri}?op=set-as-default&amp;printer_name={%printer_name}">
+-<IMG SRC="/images/button-set-as-default.gif" ALT="Définir par défaut" CLASS="button"></A>
+-<A HREF="{admin_uri}?op=set-allowed-users&amp;printer_name={%printer_name}">
+-<IMG SRC="/images/button-set-allowed-users.gif" ALT="Définir les autorisations" CLASS="button"></A>
+-</P>
+-</TD>
+-</TR>
+-</TABLE>
+-}}
+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
+@@ -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
+@@ -51,56 +51,3 @@
+ </TABLE>
+ 
+ </FORM>
+-<SCRIPT TYPE="text/javascript"><!--
+-function select_printers() {
+-  var list = document.export_samba.EXPORT_NAME;
+-  var sel = document.export_samba.EXPORT_ALL.checked;
+-
+-  for (i = 0; i < list.length; i ++) {
+-    list.options[i].selected = sel;
+-  }
+-}
+---></SCRIPT>
+-
+-<FORM METHOD="POST" ACTION="/admin/" NAME="export_samba">
+-<INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba">
+-
+-<H2 CLASS="title">Exporter des imprimantes vers SAMBA</H2>
+-
+-{error?<P>Impossible d'exporter les imprimantes vers SAMBA \:</P>
+-<BLOCKQUOTE>{error}</BLOCKQUOTE>
+-<P>Regardez le fichier <A HREF="/admin/log/error_log"
+-TARGET="_blank">error_log</A> pour plus d'informations.</P>:
+-<P>Cette page vous permet d'exporter des imprimantes vers SAMBA de sorte que des
+-clients Windows puissent y accéder via l'icône <VAR>Voisinage réseau</VAR> ou
+-<VAR>Favoris réseau</VAR> du bureau. Vous devez au préalable installer les
+-pilotes Windows d'imprimante PostScript : cf. la page <i>man</i> <A
+-HREF="/help/man-cupsaddsmb.html" TARGET="_blank">cupsaddsmb(8)</A>.</P>}
+-
+-<TABLE>
+-<TR>
+-<TH CLASS="label">Imprimantes :</TH>
+-<TD>
+-<SELECT NAME="EXPORT_NAME" SIZE="10" MULTIPLE>
+-{[printer_name]<OPTION VALUE="{printer_name}"{export_all? SELECTED:{printer_export? SELECTED:}}>{printer_name}}
+-</SELECT><BR>
+-<INPUT TYPE="CHECKBOX" NAME="EXPORT_ALL"{export_all? CHECKED:}
+-onChange="select_printers()"> Exporter toutes les imprimantes
+-</TD>
+-</TR>
+-<TR>
+-<TH CLASS="label">Utilisateur SAMBA :</TH>
+-<TD><INPUT TYPE="TEXT" NAME="USERNAME" VALUE="{?USERNAME}"> ( indispensable )</TD>
+-</TR>
+-<TR>
+-<TH CLASS="label">Mot-de-passe SAMBA :</TH>
+-<TD><INPUT TYPE="PASSWORD" NAME="PASSWORD" VALUE=""> ( indispensable )</TD>
+-</TR>
+-<TR>
+-<TD></TD>
+-<TD><INPUT TYPE="IMAGE" SRC="/images/button-export-samba.gif"
+-ALT="Exporter les imprimantes vers SAMBA"></TD>
+-</TR>
+-</TABLE>
+-
+-</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
+@@ -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
+@@ -11,16 +11,3 @@
+ SRC="/images/button-clear.gif" ALT="Nettoyer" CLASS="button"></A></P>
+ 
+ </FORM>
+-<FORM ACTION="/{SECTION}/{?SEARCH_DEST}" METHOD="GET">
+-{WHICH_JOBS?<INPUT TYPE="HIDDEN" NAME="WHICH_JOBS" VALUE="{WHICH_JOBS}">:}
+-{ORDER?<INPUT TYPE="HIDDEN" NAME="ORDER" VALUE="{ORDER}">:}
+-
+-<P ALIGN="CENTER"><B>Rechercher dans 
+-{SEARCH_DEST?{SEARCH_DEST}:{SECTION=classes?les classes:{SECTION=jobs?les tâches:les imprimantes}}} :</B>
+-<INPUT TYPE="TEXT" NAME="QUERY" VALUE="{?QUERY}" SIZE="60"> <INPUT
+-TYPE="IMAGE" SRC="/images/button-search.gif" ALT="Rechercher">
+-<A
+-HREF="/{SECTION}/{?SEARCH_DEST}{WHICH_JOBS??WHICH_JOBS={WHICH_JOBS}{ORDER?&amp;ORDER={ORDER}:}:{ORDER??ORDER={ORDER}:}}"><IMG
+-SRC="/images/button-clear.gif" ALT="Nettoyer" CLASS="button"></A></P>
+-
+-</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
+@@ -1,6 +1,3 @@
+ <FORM METHOD="POST" ACTION="/admin">
+ <INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+ <INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+-<FORM METHOD="POST" ACTION="/admin">
+-<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+-<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
+@@ -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
+@@ -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>
+-<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>
+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
+@@ -19,24 +19,3 @@
+ </TABLE>
+ </BODY>
+ </HTML>
+-</TD>
+-<TD WIDTH="15">&nbsp;</TD>
+-</TR>
+-<TR CLASS="trailer">
+-<TD VALIGN="BOTTOM" WIDTH="15"><IMG SRC="/images/bottom-left.gif"
+-WIDTH="15" HEIGHT="15" ALT=""></TD>
+-<TD COLSPAN="2" WIDTH="100%" STYLE="padding: 5;">
+-
+-<P><SMALL>Le logiciel CUPS ( Common UNIX Printing System ) et son logo sont
+-propriété commerciale de <A HREF="http://www.easysw.com">Easy Software
+-Products</A>. CUPS est sous copyright 1997-2006 par Easy Software Products, Tous
+-Droits Réservés.</SMALL></P>
+-
+-</TD>
+-
+-<TD ALIGN="RIGHT" VALIGN="BOTTOM" WIDTH="15"><IMG SRC="/images/bottom-right.gif"
+-WIDTH="15" HEIGHT="15" ALT=""></TD>
+-</TR>
+-</TABLE>
+-</BODY>
+-</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
+@@ -24,29 +24,3 @@
+ </TABLE>
+ 
+ </FORM>
+-<FORM METHOD="POST" ACTION="/admin">
+-<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{OP}">
+-<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+-{IS_CLASS?<INPUT TYPE="HIDDEN" NAME="IS_CLASS" VALUE="{IS_CLASS}">:}
+-
+-<H2 CLASS="title">Utilisateurs autorisés à utiliser {printer_name}</H2>
+-
+-<TABLE>
+-<TR>
+-<TH CLASS="label">Utilisateurs :</TH>
+-<TD>
+-<INPUT TYPE='TEXT' NAME='users' SIZE='60' VALUE='{?requesting_user_name_allowed}{?requesting_user_name_denied}'>
+-<BR>
+-<INPUT TYPE='RADIO' NAME='type' VALUE='requesting-user-name-allowed' {requesting_user_name_allowed?checked:}>Autoriser ces utilisateurs à imprimer
+-<INPUT TYPE='RADIO' NAME='type' VALUE='requesting-user-name-denied' {requesting_user_name_denied?checked:}>Empêcher ces utilisateurs d'imprimer
+-</TD>
+-</TR>
+-<TR>
+-<TD></TD>
+-<TD>
+-<INPUT TYPE="IMAGE" SRC="/images/button-set-allowed-users.gif" ALT="Définir les autorisations">
+-</TD>
+-</TR>
+-</TABLE>
+-
+-</FORM>

Added: cupsys/branches/cups-1.2-ubuntu/debian/patches/98_search_mime_files_in_usr_share.dpatch
==============================================================================
--- (empty file)
+++ cupsys/branches/cups-1.2-ubuntu/debian/patches/98_search_mime_files_in_usr_share.dpatch	Wed Mar 14 08:25:28 2007
@@ -0,0 +1,190 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 98_search_mime_files_in_usr_share.dpatch by  <till.kamppeter at gmail.com>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: No description.
+
+ at DPATCH@
+diff -urNad cupsys-1.2.8~/scheduler/conf.c cupsys-1.2.8/scheduler/conf.c
+--- cupsys-1.2.8~/scheduler/conf.c	2007-03-13 17:43:16.000000000 +0000
++++ cupsys-1.2.8/scheduler/conf.c	2007-03-13 17:48:52.000000000 +0000
+@@ -216,6 +216,7 @@
+   cups_file_t	*fp;			/* Configuration file */
+   int		status;			/* Return status */
+   char		temp[1024],		/* Temporary buffer */
++                temp2[1024],            /* Another temporary buffer */
+ 		*slash;			/* Directory separator */
+   cups_lang_t	*language;		/* Language */
+   struct passwd	*user;			/* Default user */
+@@ -973,19 +974,20 @@
+     */
+ 
+     snprintf(temp, sizeof(temp), "%s/filter", ServerBin);
++    snprintf(temp2, sizeof(temp2), "%s/mime:%s", DataDir, ServerRoot);
+ 
+-    MimeDatabase = mimeLoad(ServerRoot, temp);
++    MimeDatabase = mimeLoad(temp2, temp);
+ 
+     if (!MimeDatabase)
+     {
+       cupsdLogMessage(CUPSD_LOG_EMERG,
+-                      "Unable to load MIME database from \'%s\'!", ServerRoot);
++                      "Unable to load MIME database from \'%s\'!", temp2);
+       exit(errno);
+     }
+ 
+     cupsdLogMessage(CUPSD_LOG_INFO,
+                     "Loaded MIME database from \'%s\': %d types, %d filters...",
+-                    ServerRoot, mimeNumTypes(MimeDatabase),
++                    temp2, mimeNumTypes(MimeDatabase),
+ 		    mimeNumFilters(MimeDatabase));
+ 
+    /*
+diff -urNad cupsys-1.2.8~/scheduler/mime.c cupsys-1.2.8/scheduler/mime.c
+--- cupsys-1.2.8~/scheduler/mime.c	2006-05-30 20:40:34.000000000 +0100
++++ cupsys-1.2.8/scheduler/mime.c	2007-03-13 17:45:01.000000000 +0000
+@@ -217,9 +217,12 @@
+ 
+ mime_t *				/* O - Updated MIME database */
+ mimeMerge(mime_t     *mime,		/* I - MIME database to add to */
+-          const char *pathname,		/* I - Directory to load */
+-          const char *filterpath)	/* I - Directory to load */
++          const char *pathname,		/* I - Directory/ies to load */
++          const char *filterpath)	/* I - Filter directory */
+ {
++  char          *paths,                 /* Pointers for parsing mime */
++                *dirname,               /* directories */
++                *colon;
+   cups_dir_t	*dir;			/* Directory */
+   cups_dentry_t	*dent;			/* Directory entry */
+   char		filename[1024];		/* Full filename of types/converts file */
+@@ -234,62 +237,88 @@
+   if (!pathname)
+     return (NULL);
+ 
+-  if ((dir = cupsDirOpen(pathname)) == NULL)
+-    return (NULL);
++  paths = strdup(pathname); /* copy path as we are writing into it */
++  dirname = paths;
++  colon = paths;
++  while (colon != NULL) { /* Go through each of the colon-separated
++			     directories */
++    colon = strchr(dirname, ':');
++    if (colon != NULL) *colon = '\0';
+ 
+- /*
+-  * If "mime" is NULL, make a new, blank database...
+-  */
++    if ((dir = cupsDirOpen(dirname)) == NULL)
++      continue;
+ 
+-  if (!mime)
+-    mime = mimeNew();
+-  if (!mime)
+-    return (NULL);
++    /*
++     * If "mime" is NULL, make a new, blank database...
++     */
+ 
+- /*
+-  * Read all the .types files...
+-  */
++    if (!mime)
++      mime = mimeNew();
++    if (!mime)
++      return (NULL);
+ 
+-  while ((dent = cupsDirRead(dir)) != NULL)
+-  {
+-    if (strlen(dent->filename) > 6 &&
+-        !strcmp(dent->filename + strlen(dent->filename) - 6, ".types"))
+-    {
+-     /*
+-      * Load a mime.types file...
+-      */
++    /*
++     * Read all the .types files...
++     */
+ 
+-      snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->filename);
+-      load_types(mime, filename);
+-    }
+-  }
++    while ((dent = cupsDirRead(dir)) != NULL)
++      {
++	if (strlen(dent->filename) > 6 &&
++	    !strcmp(dent->filename + strlen(dent->filename) - 6, ".types"))
++	  {
++	    /*
++	     * Load a mime.types file...
++	     */
++ 
++	    snprintf(filename, sizeof(filename), "%s/%s", dirname, dent->filename);
++	    load_types(mime, filename);
++	  }
++      }
+ 
+-  cupsDirRewind(dir);
++    cupsDirClose(dir);
++    if (colon != NULL) dirname = colon + 1;
++  }
++  free(paths); /* We need to copy the original path again for reading
++		  the convs */
+ 
+- /*
+-  * Read all the .convs files...
+-  */
++  /*
++   * Read all the .convs files...
++   */
+ 
+   filtercache = cupsArrayNew((cups_array_func_t)compare_fcache, NULL);
+ 
+-  while ((dent = cupsDirRead(dir)) != NULL)
+-  {
+-    if (strlen(dent->filename) > 6 &&
+-        !strcmp(dent->filename + strlen(dent->filename) - 6, ".convs"))
+-    {
+-     /*
+-      * Load a mime.convs file...
+-      */
++  paths = strdup(pathname); /* copy path as we are writing into it */
++  dirname = paths;
++  colon = paths;
++  while (colon != NULL) { /* Go through each of the colon-separated
++			     directories */
++    colon = strchr(dirname, ':');
++    if (colon != NULL) *colon = '\0';
+ 
+-      snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->filename);
+-      load_convs(mime, filename, filterpath, filtercache);
+-    }
++    if ((dir = cupsDirOpen(dirname)) == NULL)
++      continue;
++
++    while ((dent = cupsDirRead(dir)) != NULL)
++      {
++	if (strlen(dent->filename) > 6 &&
++	    !strcmp(dent->filename + strlen(dent->filename) - 6, ".convs"))
++	  {
++	    /*
++	     * Load a mime.convs file...
++	     */
++
++	    snprintf(filename, sizeof(filename), "%s/%s", dirname, dent->filename);
++	    load_convs(mime, filename, filterpath, filtercache);
++	  }
++      }
++
++    cupsDirClose(dir);
++    if (colon != NULL) dirname = colon + 1;
+   }
++  free(paths);
+ 
+   delete_fcache(filtercache);
+ 
+-  cupsDirClose(dir);
+-
+   return (mime);
+ }
+ 



More information about the Pkg-cups-devel mailing list