Add a (non-shipping) man page for ippserver.
authormsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>
Thu, 28 Aug 2014 18:57:27 +0000 (18:57 +0000)
committermsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>
Thu, 28 Aug 2014 18:57:27 +0000 (18:57 +0000)
Add some missing file to the repository.

Update the README.txt file for CUPS, which still had old links and legal
language.

httpGetHostname did not make sure a .local name ended with a ".".

ippserver now properly assigns the default port number and hostname, and adds
the job attributes to the environment of the print command (if specified).

ippserver now validates that the print command can be run before it accepts any
jobs.

Rename "document-format-tests.*" to "document-tests.*".

Implement the script to build the IPP Everywhere Printer Self-Certification
tools.

Add a readme for the self-certification tools.

git-svn-id: svn+ssh://src.apple.com/svn/cups/cups.org/trunk@12127 a1ca3aef-8c08-0410-bb20-df032aa958be

13 files changed:
README.txt
cups/http-addr.c
everywhere/README.txt [new file with mode: 0644]
everywhere/document-tests.bat [moved from everywhere/document-format-tests.bat with 100% similarity]
everywhere/document-tests.sh [moved from everywhere/document-format-tests.sh with 66% similarity]
everywhere/document-tests.test [moved from everywhere/document-format-tests.test with 100% similarity]
everywhere/ipp-tests.sh
everywhere/make-ippeveselfcert.sh
everywhere/man-ippserver.html [new file with mode: 0644]
test/identify-printer.test [new file with mode: 0644]
test/ippserver.c
test/ippserver.man [new file with mode: 0644]
xcode/CUPS.xcodeproj/project.pbxproj

index 29466d5..d12bfab 100644 (file)
@@ -1,4 +1,4 @@
-README - CUPS v2.0rc1 - 2014-08-20
+README - CUPS v2.0rc1 - 2014-08-28
 ----------------------------------
 
 ********************************************************************************
@@ -54,10 +54,10 @@ READING THE DOCUMENTATION
 
 GETTING SUPPORT AND OTHER RESOURCES
 
-    If you have problems, READ THE DOCUMENTATION FIRST!  We also provide many
-    discussion forums which are available at:
+    If you have problems, READ THE DOCUMENTATION FIRST!  We also provide two
+    mailing lists which are available at:
 
-       http://www.cups.org/newsgroups.php
+       http://www.cups.org/lists.php
 
     See the CUPS web site at "http://www.cups.org/" for other resources.
 
@@ -122,11 +122,7 @@ SETTING UP PRINTER QUEUES FROM THE COMMAND-LINE
         lpadmin -p printername -E -v lpd://11.22.33.44/ -m ppd-name
 
     The sample drivers provide basic printing capabilities, but generally do not
-    exercise the full potential of the printers or CUPS.  The CUPS web site
-    provides links and drivers:
-
-        http://www.cups.org/ppd.php      PPD files
-       http://www.cups.org/links.php    Links to other drivers
+    exercise the full potential of the printers or CUPS.
 
 
 PRINTING FILES
@@ -143,8 +139,8 @@ PRINTING FILES
        lpr -o media=A4 -o resolution=600dpi filename
 
     CUPS recognizes many types of images files as well as PDF, PostScript,
-    HP-GL/2, and text files, so you can print those files directly rather than
-    through an application.
+    and text files, so you can print those files directly rather than through
+    an application.
 
     If you have an application that generates output specifically for your
     printer then you need to use the "-oraw" or "-l" options:
@@ -152,8 +148,7 @@ PRINTING FILES
        lp -o raw filename
        lpr -l filename
 
-    This will prevent the filters from misinterpreting your print
-    file.
+    This will prevent the filters from misinterpreting your print file.
 
 
 LEGAL STUFF
@@ -163,8 +158,6 @@ LEGAL STUFF
 
     The MD5 Digest code is Copyright 1999 Aladdin Enterprises.
 
-    This software is based in part on the work of the Independent JPEG Group.
-
     CUPS is provided under the terms of version 2 of the GNU General Public
     License and GNU Library General Public License. This program is distributed
     in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
index 00eabff..62b0e17 100644 (file)
@@ -865,6 +865,13 @@ httpGetHostname(http_t *http,              /* I - HTTP connection or NULL */
       }
 #endif /* HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME */
     }
+
+   /*
+    * Make sure .local hostnames end with a period...
+    */
+
+    if (strlen(s) > 6 && !strcmp(s + strlen(s) - 6, ".local"))
+      strlcat(s, ".", slen);
   }
 
  /*
diff --git a/everywhere/README.txt b/everywhere/README.txt
new file mode 100644 (file)
index 0000000..d9004ca
--- /dev/null
@@ -0,0 +1,65 @@
+README.txt - 2014-08-28
+-----------------------
+
+INTRODUCTION
+
+    This directory contains the IPP Everywhere Printer Self-Certification tools.
+
+    In addition to the files in this directory, you must also download and
+    extract one or more PWG Raster Format file archives from:
+
+      http://ftp.pwg.org/pub/pwg/ipp/examples/
+
+    These archives are used for the Document Data tests.
+
+
+CONTENTS
+
+    Scripts for running the self-certification tests:
+
+      bonjour-tests.bat   Bonjour Tests for Windows
+      bonjour-tests.sh    Bonjour Tests for Linux and OS X
+
+      ipp-tests.bat       IPP Tests for Windows
+      ipp-tests.sh        IPP Tests for Linux and OS X
+
+      document-tests.bat  Document Data Tests for Windows
+      document-tests.sh   Document Data Tests for Linux and OS X
+
+    Tools:
+
+      ippfind             Tool for finding printers with Bonjour/DNS-SD
+      ippserver           Sample IPP server, useful for testing
+      ipptool             IPP test tool
+
+    Documentation:
+
+      LICENSE.txt         CUPS software license
+      man-*.html          HTML documentation for the tools
+      README.txt          This README file
+
+
+GETTING SUPPORT AND OTHER RESOURCES
+
+    The IPP Everywhere home page provides access to all information relevant to
+    IPP Eveywhere:
+
+      http://www.pwg.org/ipp/everywhere.html
+
+    The "ippeveselfcert@pwg.org" mailing list is used to discuss IPP Everywhere
+    Printer Self-Certification.  You can subscribe from the following page:
+
+      https://www.pwg.org/mailman/listinfo/ippeveselfcert
+
+
+LEGAL STUFF
+
+    These tools are Copyright 2014 by The Printer Working Group and Copyright
+    2007-2014 by Apple Inc.  CUPS and the CUPS logo are trademarks of Apple Inc.
+    PWG and IPP Everywhere are trademarks of the IEEE-ISTO.
+
+    CUPS is provided under the terms of version 2 of the GNU General Public
+    License and GNU Library General Public License. This program is distributed
+    in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+    the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+    See the file "LICENSE.txt" for more information.
similarity index 66%
rename from everywhere/document-format-tests.sh
rename to everywhere/document-tests.sh
index e6a37e3..99d69af 100755 (executable)
@@ -18,7 +18,7 @@
 #
 # Usage:
 #
-#   ./document-format-tests.sh "Printer Name"
+#   ./document-tests.sh "Printer Name"
 #
 
 if test -x ../test/ippfind-static; then
@@ -37,7 +37,22 @@ else
        IPPTOOL="ipptool"
 fi
 
-$IPPFIND "$1._ipp._tcp.local." -x $IPPTOOL -P "$1 Document Format Results.plist" -I '{}' document-format-tests.test \;
+for file in color.jpg document-a4.pdf document-letter.pdf; do
+       if test ! -f $file -a -f ../test/$file; then
+               ln -s ../test/$file .
+       fi
+done
+
+if test "`ls -d pwg-raster-samples-*dpi-20111130 2>/dev/null`" = ""; then
+       echo "You must first download and extract the PWG Raster Format sample files from:"
+       echo ""
+       echo "    http://ftp.pwg.org/pub/pwg/ipp/examples/"
+       echo ""
+       echo "Before you can run this script."
+       exit 1
+fi
+
+$IPPFIND "$1._ipp._tcp.local." -x $IPPTOOL -P "$1 Document Results.plist" -I '{}' document-tests.test \;
 
 #
 # End of "$Id$".
index eb2106e..f793573 100755 (executable)
@@ -37,6 +37,12 @@ else
        IPPTOOL="ipptool"
 fi
 
+for file in color.jpg; do
+       if test ! -f $file -a -f ../test/$file; then
+               ln -s ../test/$file .
+       fi
+done
+
 $IPPFIND "$1._ipp._tcp.local." -x $IPPTOOL -P "$1 IPP Results.plist" -I '{}' ipp-tests.test \;
 
 #
index e69de29..d293fc3 100755 (executable)
@@ -0,0 +1,72 @@
+#!/bin/sh
+#
+# "$Id$"
+#
+#   Make an IPP Everywhere Printer self-certification package.
+#
+#   Copyright 2014 The Printer Working Group.
+#   Copyright 2007-2013 by Apple Inc.
+#   Copyright 1997-2007 by Easy Software Products, all rights reserved.
+#
+#   These coded instructions, statements, and computer programs are the
+#   property of Apple Inc. 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
+#   file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+# Make sure we are running in the right directory...
+if test ! -f everywhere/make-ippeveselfcert.sh; then
+        echo "Run this script from the top-level CUPS source directory, e.g.:"
+        echo ""
+        echo "    everywhere/make-ippeveselfcert.sh $*"
+        echo ""
+        exit 1
+fi
+
+if test $# != 2; then
+       echo "Usage: everywhere/make-ippeveselfcert.sh platform YYYYMMDD"
+       exit 1
+fi
+
+platform="$1"
+fileversion="$2"
+
+echo Creating package directory...
+pkgdir="ippeveselfcert-$fileversion"
+
+test -d $pkgdir && rm -r $pkgdir
+mkdir $pkgdir || exit 1
+
+echo Copying package files
+cp LICENSE.txt $pkgdir
+cp doc/help/man-ipp*.html $pkgdir
+cp everywhere/README.txt $pkgdir
+cp everywhere/man-ippserver.html $pkgdir
+cp everywhere/*-tests.* $pkgdir
+cp test/color.jpg $pkgdir
+cp test/document-*.pdf $pkgdir
+cp test/ippfind-static $pkgdir/ippfind
+cp test/ippserver $pkgdir
+cp test/ipptool-static $pkgdir/ipptool
+cp test/printer.png $pkgdir
+
+if test x$platform = xosx; then
+       pkgfile="$pkgdir-osx.dmg"
+       echo Creating disk image $pkgfile...
+       test -f $pkgfile && rm $pkgfile
+       hdiutil create -srcfolder $pkgdir $pkgfile
+else
+       pkgfile="$pkgdir-$platform.tar.gz"
+       echo Creating archive $pkgfile...
+       tar czf $pkgfile $pkgdir || exit 1
+fi
+
+echo Removing temporary files...
+rm -r $pkgdir
+
+echo Done.
+
+#
+# End of "$Id$".
+#
diff --git a/everywhere/man-ippserver.html b/everywhere/man-ippserver.html
new file mode 100644 (file)
index 0000000..bd4e854
--- /dev/null
@@ -0,0 +1,151 @@
+<!DOCTYPE HTML>
+<html>
+<!-- SECTION: Man Pages -->
+<head>
+       <link rel="stylesheet" type="text/css" href="../cups-printable.css">
+       <title>ippserver(1)</title>
+</head>
+<body>
+<h1 class="title">ippserver(1)</h1>
+<h2 class="title"><a name="NAME">Name</a></h2>
+ippserver - a simple internet printing protocol server
+<h2 class="title"><a name="SYNOPSIS">Synopsis</a></h2>
+<b>ippserver</b>
+[
+<b>-2</b>
+] [
+<b>-M</b>
+<i>manufacturer</i>
+] [
+<b>-P</b>
+] [
+<b>-c</b>
+<i>command</i>
+] [
+<b>-d</b>
+<i>spool-directory</i>
+] [
+<b>-f</b>
+<i>type/subtype[,...]</i>
+] [
+<b>-h</b>
+] [
+<b>-i</b>
+<i>iconfile.png</i>
+] [
+<b>-k</b>
+] [
+<b>-l</b>
+<i>location</i>
+] [
+<b>-m</b>
+<i>model</i>
+] [
+<b>-n</b>
+<i>hostname</i>
+] [
+<b>-p</b>
+<i>port</i>
+] [
+<b>-r</b>
+<i>subtype</i>
+] [
+<b>-s</b>
+<i>speed[,color-speed]</i>
+] [
+<b>-v[vvv]</b>
+]
+<i>service-name</i>
+<h2 class="title"><a name="DESCRIPTION">Description</a></h2>
+<b>ippserver</b>
+is a simple Internet Printing Protocol (IPP) server conforming to the IPP Everywhere (PWG 5100.14) specification. It can be used to test client software or act as a very basic print server that runs a command for every job that is printed.
+<h2 class="title"><a name="OPTIONS">Options</a></h2>
+The following options are recognized by
+<b>ippserver:</b>
+<dl class="man">
+<dt><b>-2</b>
+<dd style="margin-left: 5.0em">Report support for two-sided (duplex) printing.
+<dt><b>-M </b><i>manufacturer</i>
+<dd style="margin-left: 5.0em">Set the manufacturer of the printer.
+The default is "Test".
+<dt><b>-P</b>
+<dd style="margin-left: 5.0em">Report support for PIN printing.
+<dt><b>-c </b><i>command</i>
+<dd style="margin-left: 5.0em">Run the specified command for each document that is printed.
+<dt><b>-d </b><i>spool-directory</i>
+<dd style="margin-left: 5.0em">Specifies the directory that will hold the print files.
+The default is a directory under the user's current temporary directory.
+<dt><b>-f </b><i>type/subtype[,...]</i>
+<dd style="margin-left: 5.0em">Specifies a list of MIME media types that the server will accept.
+The default is "application/pdf,image/jpeg,image/pwg-raster".
+<dt><b>-h</b>
+<dd style="margin-left: 5.0em">Shows program help.
+<dt><b>-i </b><i>iconfile.png</i>
+<dd style="margin-left: 5.0em">Specifies the printer icon file for the server.
+The default is "printer.png".
+<dt><b>-k</b>
+<dd style="margin-left: 5.0em">Keeps the print documents in the spool directory rather than deleting them.
+<dt><b>-l </b><i>location</i>
+<dd style="margin-left: 5.0em">Specifies the human-readable location string that is reported by the server.
+The default is the empty string.
+<dt><b>-m </b><i>model</i>
+<dd style="margin-left: 5.0em">Specifies the model name of the printer.
+The default is "Printer".
+<dt><b>-n </b><i>hostname</i>
+<dd style="margin-left: 5.0em">Specifies the hostname that is reported by the server.
+The default is the name returned by the
+<b>hostname</b>(1)
+command.
+<dt><b>-p </b><i>port</i>
+<dd style="margin-left: 5.0em">Specifies the port number to listen on.
+The default is a user-specific number from 8000 to 8999.
+<dt><b>-r </b><i>subtype</i>
+<dd style="margin-left: 5.0em">Specifies the Bonjour subtype(s) to advertise.
+Separate multiple subtypes with a comma.
+The default is "_print".
+<dt><b>-s </b><i>speed[,color-speed]</i>
+<dd style="margin-left: 5.0em">Specifies the printer speed in pages per minute.
+If two numbers are specified and the second number is greater than zero, the server will report support for color printing.
+The default is "10,0".
+<dt><b>-v[vvv]</b>
+<dd style="margin-left: 5.0em">Be (very) verbose when logging activity to the standard output.
+</dl>
+<h2 class="title"><a name="EXIT_STATUS">Exit Status</a></h2>
+The
+<b>ippserver</b>
+program returns 1 if it is unable to process the command-line arguments or register the IPP service.
+Otherwise
+<b>ippserver</b>
+will run continuously until terminated.
+<h2 class="title"><a name="CONFORMING_TO">Conforming To</a></h2>
+The
+<b>ippserver</b>
+program is unique to CUPS and conforms to the IPP Everywhere (PWG 5100.14) specification.
+<h2 class="title"><a name="ENVIRONMENT">Environment</a></h2>
+<b>ippserver</b>
+adds environment variables starting with "IPP_" for all IPP Job attributes in the print request.
+For example, when executing a command for an IPP Job containing the "media" Job Template attribute, the "IPP_MEDIA" environment variable will be set to the value of that attribute.
+<p>Enumerated values are converted to their keyword equivalents.
+For example, a "print-quality" Job Template attribute with a enum value of 3 will become the "IPP_PRINT_QUALITY" environment variable with a value of "draft".
+<h2 class="title"><a name="EXAMPLES">Examples</a></h2>
+Run
+<b>ippserver</b>
+with a service name of My Cool Printer:
+<pre class="man">
+
+    ippserver "My Cool Printer"
+</pre>
+<p>Run the
+<b>file</b>(1)
+command whenever a job is sent to the server:
+<pre class="man">
+
+    ippserver -c file "My Cool Printer"
+</pre>
+<h2 class="title"><a name="SEE_ALSO">See Also</a></h2>
+PWG Internet Printing Protocol Workgroup (<a href="http://www.pwg.org/ipp">http://www.pwg.org/ipp</a>)
+<h2 class="title"><a name="COPYRIGHT">Copyright</a></h2>
+Copyright &copy; 2007-2014 by Apple Inc.
+
+</body>
+</html>
diff --git a/test/identify-printer.test b/test/identify-printer.test
new file mode 100644 (file)
index 0000000..b97bb71
--- /dev/null
@@ -0,0 +1,20 @@
+# Make the printer beep
+{
+       # The name of the test...
+       NAME "Identify Printer with Sound"
+
+       # The operation to use
+       OPERATION Identify-Printer
+
+       # Attributes, starting in the operation group...
+       GROUP operation-attributes-tag
+       ATTR charset attributes-charset utf-8
+       ATTR language attributes-natural-language en
+       ATTR uri printer-uri $uri
+       ATTR name requesting-user-name $user
+       ATTR keyword identify-actions sound
+
+       # What statuses are OK?
+       STATUS successful-ok
+       STATUS successful-ok-ignored-or-substituted-attributes
+}
index 65039c6..3d3f5b2 100644 (file)
@@ -38,6 +38,8 @@
 
 #include <sys/wait.h>
 
+extern char **environ;
+
 #ifdef HAVE_DNSSD
 #  include <dns_sd.h>
 #endif /* HAVE_DNSSD */
@@ -318,7 +320,7 @@ static void         copy_job_attributes(_ipp_client_t *client,
                                            _ipp_job_t *job, cups_array_t *ra);
 static _ipp_client_t   *create_client(_ipp_printer_t *printer, int sock);
 static _ipp_job_t      *create_job(_ipp_client_t *client);
-static int             create_listener(int family, int *port);
+static int             create_listener(int family, int port);
 static ipp_t           *create_media_col(const char *media, const char *source, const char *type, int width, int length, int margins);
 static ipp_t           *create_media_size(int width, int length);
 static _ipp_printer_t  *create_printer(const char *servername,
@@ -424,12 +426,13 @@ main(int  argc,                           /* I - Number of command-line args */
 #ifdef HAVE_DNSSD
   const char   *subtype = "_print";    /* Bonjour service subtype */
 #endif /* HAVE_DNSSD */
-  int          port = 8631,            /* Port number (0 = auto) */
+  int          port = 0,               /* Port number (0 = auto) */
                duplex = 0,             /* Duplex mode */
                ppm = 10,               /* Pages per minute for mono */
                ppm_color = 0,          /* Pages per minute for color */
                pin = 0;                /* PIN printing mode? */
-  char         directory[1024] = "";   /* Spool directory */
+  char         directory[1024] = "",   /* Spool directory */
+               hostname[1024];         /* Auto-detected hostname */
   _ipp_printer_t *printer;             /* Printer object */
 
 
@@ -577,6 +580,15 @@ main(int  argc,                            /* I - Number of command-line args */
   * Apply defaults as needed...
   */
 
+  if (!servername)
+    servername = httpGetHostname(NULL, hostname, sizeof(hostname));
+
+  if (!port)
+  {
+    port = 8000 + ((int)getuid() % 1000);
+    fprintf(stderr, "Listening on port %d.\n", port);
+  }
+
   if (!directory[0])
   {
     snprintf(directory, sizeof(directory), "/tmp/ippserver.%d", (int)getpid());
@@ -1051,26 +1063,20 @@ static void create_job_filename(
  * 'create_listener()' - Create a listener socket.
  */
 
-static int                             /* O  - Listener socket or -1 on error */
-create_listener(int family,            /* I  - Address family */
-                int *port)             /* IO - Port number */
+static int                             /* O - Listener socket or -1 on error */
+create_listener(int family,            /* I - Address family */
+                int port)              /* I - Port number */
 {
   int                  sock;           /* Listener socket */
   http_addrlist_t      *addrlist;      /* Listen address */
   char                 service[255];   /* Service port */
 
 
-  if (!*port)
-  {
-    *port = 8000 + ((int)getuid() % 1000);
-    fprintf(stderr, "Listening on port %d.\n", *port);
-  }
-
-  snprintf(service, sizeof(service), "%d", *port);
+  snprintf(service, sizeof(service), "%d", port);
   if ((addrlist = httpAddrGetList(NULL, family, service)) == NULL)
     return (-1);
 
-  sock = httpAddrListen(&(addrlist->addr), *port);
+  sock = httpAddrListen(&(addrlist->addr), port);
 
   httpAddrFreeList(addrlist);
 
@@ -1174,8 +1180,10 @@ create_printer(const char *servername,   /* I - Server hostname (NULL for default)
 {
   int                  i, j;           /* Looping vars */
   _ipp_printer_t       *printer;       /* Printer */
-  char                 hostname[256],  /* Hostname */
-                       uri[1024],      /* Printer URI */
+#ifndef WIN32
+  char                 path[1024];     /* Full path to command */
+#endif /* !WIN32 */
+  char                 uri[1024],      /* Printer URI */
                        icons[1024],    /* printer-icons URI */
                        adminurl[1024], /* printer-more-info URI */
                        supplyurl[1024],/* printer-supply-info-uri URI */
@@ -1361,13 +1369,41 @@ create_printer(const char *servername,  /* I - Server hostname (NULL for default)
   };
 
 
+#ifndef WIN32
+ /*
+  * If a command was specified, make sure it exists and is executable...
+  */
+
+  if (command)
+  {
+    if (*command == '/' || !strncmp(command, "./", 2))
+    {
+      if (access(command, X_OK))
+      {
+        fprintf(stderr, "ippserver: Unable to execute command \"%s\": %s\n", command, strerror(errno));
+       return (NULL);
+      }
+    }
+    else
+    {
+      if (!cupsFileFind(command, getenv("PATH"), 1, path, sizeof(path)))
+      {
+       fprintf(stderr, "ippserver: Unable to find command \"%s\".\n", command);
+       return (NULL);
+      }
+
+      command = path;
+    }
+  }
+#endif /* !WIN32 */
+
  /*
   * Allocate memory for the printer...
   */
 
   if ((printer = calloc(1, sizeof(_ipp_printer_t))) == NULL)
   {
-    perror("Unable to allocate memory for printer");
+    perror("ippserver: Unable to allocate memory for printer");
     return (NULL);
   }
 
@@ -1379,7 +1415,7 @@ create_printer(const char *servername,    /* I - Server hostname (NULL for default)
 #endif /* HAVE_DNSSD */
   printer->command       = command ? strdup(command) : NULL;
   printer->directory     = strdup(directory);
-  printer->hostname      = strdup(servername ? servername : httpGetHostname(NULL, hostname, sizeof(hostname)));
+  printer->hostname      = strdup(servername);
   printer->port          = port;
   printer->start_time    = time(NULL);
   printer->config_time   = printer->start_time;
@@ -1420,13 +1456,13 @@ create_printer(const char *servername,  /* I - Server hostname (NULL for default)
   * Create the listener sockets...
   */
 
-  if ((printer->ipv4 = create_listener(AF_INET, &(printer->port))) < 0)
+  if ((printer->ipv4 = create_listener(AF_INET, printer->port)) < 0)
   {
     perror("Unable to create IPv4 listener");
     goto bad_printer;
   }
 
-  if ((printer->ipv6 = create_listener(AF_INET6, &(printer->port))) < 0)
+  if ((printer->ipv6 = create_listener(AF_INET6, printer->port)) < 0)
   {
     perror("Unable to create IPv6 listener");
     goto bad_printer;
@@ -5210,19 +5246,79 @@ process_job(_ipp_job_t *job)            /* I - Job */
                status;                 /* Exit status */
     time_t     start,                  /* Start time */
                end;                    /* End time */
+    char       *myargv[3],             /* Command-line arguments */
+               *myenvp[200];           /* Environment variables */
+    int                myenvc;                 /* Number of environment variables */
+    ipp_attribute_t *attr;             /* Job attribute */
+    char       val[1280],              /* IPP_NAME=value */
+               *valptr;                /* Pointer into string */
 
     fprintf(stderr, "Running command \"%s %s\".\n", job->printer->command,
             job->filename);
     time(&start);
 
+   /*
+    * Setup the command-line arguments...
+    */
+
+    myargv[0] = job->printer->command;
+    myargv[1] = job->filename;
+    myargv[2] = NULL;
+
+   /*
+    * Copy the current environment, then add ENV variables for every Job
+    * attribute...
+    */
+
+    for (myenvc = 0; environ[myenvc] && myenvc < (int)(sizeof(myenvp) / sizeof(myenvp[0]) - 1); myenvc ++)
+      myenvp[myenvc] = strdup(environ[myenvc]);
+
+    for (attr = ippFirstAttribute(job->attrs); attr && myenvc < (int)(sizeof(myenvp) / sizeof(myenvp[0]) - 1); attr = ippNextAttribute(job->attrs))
+    {
+     /*
+      * Convert "attribute-name" to "IPP_ATTRIBUTE_NAME=" and then add the
+      * value(s) from the attribute.
+      */
+
+      const char *name = ippGetName(attr);
+      if (!name)
+        continue;
+
+      valptr = val;
+      *valptr++ = 'I';
+      *valptr++ = 'P';
+      *valptr++ = 'P';
+      *valptr++ = '_';
+      while (*name && valptr < (val + sizeof(val) - 2))
+      {
+        if (*name == '-')
+         *valptr++ = '_';
+       else
+         *valptr++ = (char)toupper(*name & 255);
+
+       name ++;
+      }
+      *valptr++ = '=';
+      ippAttributeString(attr, valptr, sizeof(val) - (size_t)(valptr - val));
+
+      myenvp[myenvc++] = strdup(val);
+    }
+    myenvp[myenvc] = NULL;
+
+   /*
+    * Now run the program...
+    */
+
+#ifdef WIN32
+    status = _spawnvpe(_P_WAIT, job->printer->command, myargv, myenvp);
+#else
     if ((pid = fork()) == 0)
     {
      /*
       * Child comes here...
       */
 
-      execlp(job->printer->command, job->printer->command, job->filename,
-             (void *)NULL);
+      execve(job->printer->command, myargv, myenvp);
       exit(errno);
     }
     else if (pid < 0)
@@ -5232,34 +5328,48 @@ process_job(_ipp_job_t *job)            /* I - Job */
       */
 
       perror("Unable to start job processing command");
+      status = -1;
     }
     else
     {
+     /*
+      * Free memory used for environment...
+      */
+
+      while (myenvc > 0)
+       free(myenvp[-- myenvc]);
+
      /*
       * Wait for child to complete...
       */
 
-#ifdef HAVE_WAITPID
+#  ifdef HAVE_WAITPID
       while (waitpid(pid, &status, 0) < 0);
-#else
+#  else
       while (wait(&status) < 0);
-#endif /* HAVE_WAITPID */
+#  endif /* HAVE_WAITPID */
+    }
+#endif /* WIN32 */
 
-      if (status)
-      {
-        if (WIFEXITED(status))
-         fprintf(stderr, "Command \"%s\" exited with status %d.\n",
-                 job->printer->command, WEXITSTATUS(status));
-        else
-         fprintf(stderr, "Command \"%s\" terminated with signal %d.\n",
-                 job->printer->command, WTERMSIG(status));
-
-        job->state = IPP_JSTATE_ABORTED;
-      }
+    if (status)
+    {
+#ifndef WIN32
+      if (WIFEXITED(status))
+#endif /* !WIN32 */
+       fprintf(stderr, "Command \"%s\" exited with status %d.\n",
+               job->printer->command, WEXITSTATUS(status));
+#ifndef WIN32
       else
-       fprintf(stderr, "Command \"%s\" completed successfully.\n",
-               job->printer->command);
+       fprintf(stderr, "Command \"%s\" terminated with signal %d.\n",
+               job->printer->command, WTERMSIG(status));
+#endif /* !WIN32 */
+      job->state = IPP_JSTATE_ABORTED;
     }
+    else if (status < 0)
+      job->state = IPP_JSTATE_ABORTED;
+    else
+      fprintf(stderr, "Command \"%s\" completed successfully.\n",
+             job->printer->command);
 
    /*
     * Make sure processing takes at least 5 seconds...
diff --git a/test/ippserver.man b/test/ippserver.man
new file mode 100644 (file)
index 0000000..a5c1c1c
--- /dev/null
@@ -0,0 +1,172 @@
+.\"
+.\" "$Id$"
+.\"
+.\" ippserver man page for CUPS.
+.\"
+.\" Copyright 2014 by Apple Inc.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH ippserver 1 "CUPS" "28 August 2014" "Apple Inc."
+.SH NAME
+ippserver \- a simple internet printing protocol server
+.SH SYNOPSIS
+.B ippserver
+[
+.B \-2
+] [
+.B \-M
+.I manufacturer
+] [
+.B \-P
+] [
+.B \-c
+.I command
+] [
+.B \-d
+.I spool-directory
+] [
+.B \-f
+.I type/subtype[,...]
+] [
+.B \-h
+] [
+.B \-i
+.I iconfile.png
+] [
+.B \-k
+] [
+.B \-l
+.I location
+] [
+.B \-m
+.I model
+] [
+.B \-n
+.I hostname
+] [
+.B \-p
+.I port
+] [
+.B \-r
+.I subtype
+] [
+.B \-s
+.I speed[,color-speed]
+] [
+.B \-v[vvv]
+]
+.I service-name
+.SH DESCRIPTION
+.B ippserver
+is a simple Internet Printing Protocol (IPP) server conforming to the IPP Everywhere (PWG 5100.14) specification. It can be used to test client software or act as a very basic print server that runs a command for every job that is printed.
+.SH OPTIONS
+The following options are recognized by
+.B ippserver:
+.TP 5
+.B \-2
+Report support for two-sided (duplex) printing.
+.TP 5
+\fB\-M \fImanufacturer\fR
+Set the manufacturer of the printer.
+The default is "Test".
+.TP 5
+.B \-P
+Report support for PIN printing.
+.TP 5
+\fB\-c \fIcommand\fR
+Run the specified command for each document that is printed.
+.TP 5
+\fB\-d \fIspool-directory\fR
+Specifies the directory that will hold the print files.
+The default is a directory under the user's current temporary directory.
+.TP 5
+\fB\-f \fItype/subtype[,...]\fR
+Specifies a list of MIME media types that the server will accept.
+The default is "application/pdf,image/jpeg,image/pwg-raster".
+.TP 5
+.B \-h
+Shows program help.
+.TP 5
+\fB\-i \fIiconfile.png\fR
+Specifies the printer icon file for the server.
+The default is "printer.png".
+.TP 5
+.B \-k
+Keeps the print documents in the spool directory rather than deleting them.
+.TP 5
+\fB\-l \fIlocation\fR
+Specifies the human-readable location string that is reported by the server.
+The default is the empty string.
+.TP 5
+\fB\-m \fImodel\fR
+Specifies the model name of the printer.
+The default is "Printer".
+.TP 5
+\fB\-n \fIhostname\fR
+Specifies the hostname that is reported by the server.
+The default is the name returned by the
+.BR hostname (1)
+command.
+.TP 5
+\fB\-p \fIport\fR
+Specifies the port number to listen on.
+The default is a user-specific number from 8000 to 8999.
+.TP 5
+\fB\-r \fIsubtype\fR
+Specifies the Bonjour subtype(s) to advertise.
+Separate multiple subtypes with a comma.
+The default is "_print".
+.TP 5
+\fB\-s \fIspeed[,color-speed]\fR
+Specifies the printer speed in pages per minute.
+If two numbers are specified and the second number is greater than zero, the server will report support for color printing.
+The default is "10,0".
+.TP 5
+.B \-v[vvv]
+Be (very) verbose when logging activity to the standard output.
+.SH EXIT STATUS
+The
+.B ippserver
+program returns 1 if it is unable to process the command-line arguments or register the IPP service.
+Otherwise
+.B ippserver
+will run continuously until terminated.
+.SH CONFORMING TO
+The
+.B ippserver
+program is unique to CUPS and conforms to the IPP Everywhere (PWG 5100.14) specification.
+.SH ENVIRONMENT
+.B ippserver
+adds environment variables starting with "IPP_" for all IPP Job attributes in the print request.
+For example, when executing a command for an IPP Job containing the "media" Job Template attribute, the "IPP_MEDIA" environment variable will be set to the value of that attribute.
+.LP
+Enumerated values are converted to their keyword equivalents.
+For example, a "print-quality" Job Template attribute with a enum value of 3 will become the "IPP_PRINT_QUALITY" environment variable with a value of "draft".
+.SH EXAMPLES
+Run
+.B ippserver
+with a service name of My Cool Printer:
+.nf
+
+    ippserver "My Cool Printer"
+.fi
+.LP
+Run the
+.BR file (1)
+command whenever a job is sent to the server:
+.nf
+
+    ippserver \-c file "My Cool Printer"
+.fi
+.SH SEE ALSO
+PWG Internet Printing Protocol Workgroup (http://www.pwg.org/ipp)
+.SH COPYRIGHT
+Copyright \[co] 2007-2014 by Apple Inc.
+.\"
+.\" End of "$Id$".
+.\"
index bff5aa0..9d658ff 100644 (file)
@@ -30,6 +30,7 @@
                        );
                        dependencies = (
                                274FF5E313332D4300317ECB /* PBXTargetDependency */,
+                               72BEA8D819AFA8BB0085F0F3 /* PBXTargetDependency */,
                                72F75A711336FACD004BB496 /* PBXTargetDependency */,
                                274FF5E513332D4300317ECB /* PBXTargetDependency */,
                                274FF622133331D300317ECB /* PBXTargetDependency */,
@@ -44,6 +45,8 @@
                                274FF65E13333A3400317ECB /* PBXTargetDependency */,
                                724379531333FECE009631B9 /* PBXTargetDependency */,
                                724379111333E4EA009631B9 /* PBXTargetDependency */,
+                               72BEA8D619AFA8A00085F0F3 /* PBXTargetDependency */,
+                               72BEA8D419AFA89C0085F0F3 /* PBXTargetDependency */,
                                276683FF1337F7C5000D33D0 /* PBXTargetDependency */,
                                7243792B1333E962009631B9 /* PBXTargetDependency */,
                                276683D71337B24A000D33D0 /* PBXTargetDependency */,
                        remoteGlobalIDString = 274FF6891333B1C400317ECB;
                        remoteInfo = libcups_static;
                };
+               72BEA8D319AFA89C0085F0F3 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 726AD6F6135E88F0002C930D;
+                       remoteInfo = ippserver;
+               };
+               72BEA8D519AFA8A00085F0F3 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 72CF95E618A19134000FCAE4;
+                       remoteInfo = ippfind;
+               };
+               72BEA8D719AFA8BB0085F0F3 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 274FF6891333B1C400317ECB;
+                       remoteInfo = libcups_static;
+               };
                72CF95E818A19134000FCAE4 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
                        target = 274FF6891333B1C400317ECB /* libcups_static */;
                        targetProxy = 726AD705135E8AC5002C930D /* PBXContainerItemProxy */;
                };
+               72BEA8D419AFA89C0085F0F3 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 726AD6F6135E88F0002C930D /* ippserver */;
+                       targetProxy = 72BEA8D319AFA89C0085F0F3 /* PBXContainerItemProxy */;
+               };
+               72BEA8D619AFA8A00085F0F3 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 72CF95E618A19134000FCAE4 /* ippfind */;
+                       targetProxy = 72BEA8D519AFA8A00085F0F3 /* PBXContainerItemProxy */;
+               };
+               72BEA8D819AFA8BB0085F0F3 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 274FF6891333B1C400317ECB /* libcups_static */;
+                       targetProxy = 72BEA8D719AFA8BB0085F0F3 /* PBXContainerItemProxy */;
+               };
                72CF95E718A19134000FCAE4 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = 72220EAD1333047D00FCA411 /* libcups */;