]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Merge changes from CUPS 1.5svn-r8933.
authormsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>
Wed, 16 Dec 2009 00:13:28 +0000 (00:13 +0000)
committermsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>
Wed, 16 Dec 2009 00:13:28 +0000 (00:13 +0000)
git-svn-id: svn+ssh://src.apple.com/svn/cups/easysw/current@1788 a1ca3aef-8c08-0410-bb20-df032aa958be

17 files changed:
CHANGES-1.4.txt
berkeley/lpq.c
config-scripts/cups-common.m4
config-scripts/cups-defaults.m4
cups/dest.c
cups/util.c
doc/help/ref-cupsd-conf.html.in
doc/help/spec-ppd.html
scheduler/ipp.c
scheduler/job.c
scheduler/main.c
scheduler/printers.c
scheduler/printers.h
systemv/lpstat.c
test/4.3-job-ops.test
test/Dependencies
test/ipptest.c

index 74c59597118fce61f2b4ebcf81758619d29708d9..5508abe0e7229ccb5bf4d16ca91cd9826be38c1b 100644 (file)
@@ -6,6 +6,12 @@ CHANGES IN CUPS V1.4.3
        - SECURITY: The scheduler could try responding on a closed client
          connection, leading to a crash (STR #3200)
        - Localization updates (STR #3352, STR #3409, STR #3422)
+       - Documentation update (STR #3451)
+       - IPP conformance: Get-Jobs has a default value for requested-attributes
+         (STR #3383)
+       - cupsPrintFiles() did not report all errors (STR #3449)
+       - cupsAddDest() could read freed memory (STR #3448)
+       - The DBUS notifier did not build (STR #3447)
        - The scheduler would crash when an active printer was deleted.
        - The snmp backend did not work with some printers (STR #3413)
        - The web interface did not show the conflicting values when setting
index b744848f7f81de0d22f0e069ff6fdc1089b84920..8304bdc4e2469c838edd117a6aa327e24616544c 100644 (file)
@@ -340,7 +340,18 @@ show_jobs(const char *command,             /* I - Command name */
   char         resource[1024];         /* Resource string */
   char         rankstr[255];           /* Rank string */
   char         namestr[1024];          /* Job name string */
-  static const char *ranks[10] =       /* Ranking strings */
+  static const char * const jobattrs[] =/* Job attributes we want to see */
+               {
+                 "copies",
+                 "job-id",
+                 "job-k-octets",
+                 "job-name",
+                 "job-originating-user-name",
+                 "job-printer-uri",
+                 "job-priority",
+                 "job-state"
+               };
+  static const char * const ranks[10] =        /* Ranking strings */
                {
                  "th",
                  "st",
@@ -368,6 +379,7 @@ show_jobs(const char *command,              /* I - Command name */
   *    attributes-charset
   *    attributes-natural-language
   *    job-uri or printer-uri
+  *    requested-attributes
   */
 
   request = ippNewRequest(id ? IPP_GET_JOB_ATTRIBUTES : IPP_GET_JOBS);
@@ -397,6 +409,10 @@ show_jobs(const char *command,             /* I - Command name */
     ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1);
   }
 
+  ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+                "requested-attributes",
+                (int)(sizeof(jobattrs) / sizeof(jobattrs[0])), NULL, jobattrs);
+
  /*
   * Do the request and get back a response...
   */
index 8583acfaf675e6f59b4ebd074ea6571bae0c6689..51b108beb7a50f18fd33a7a9021e1e93b43ad76a 100644 (file)
@@ -262,6 +262,8 @@ if test "x$enable_dbus" != xno; then
                        AC_DEFINE(HAVE_DBUS)
                        CFLAGS="$CFLAGS `$PKGCONFIG --cflags dbus-1` -DDBUS_API_SUBJECT_TO_CHANGE"
                        CUPSDLIBS="$CUPSDLIBS `$PKGCONFIG --libs dbus-1`"
+                       DBUS_NOTIFIER="dbus"
+                       DBUS_NOTIFIERLIBS="`$PKGCONFIG --libs dbus-1`"
                        AC_CHECK_LIB(dbus-1,
                                dbus_message_iter_init_append,
                                AC_DEFINE(HAVE_DBUS_MESSAGE_ITER_INIT_APPEND),,
index 1a4eb7b89603f2d03b6a7cc892c384b9e6f6d81d..4f455a8232f9733f27d584426c8e13ec4c605cb6 100644 (file)
@@ -208,6 +208,10 @@ AC_ARG_WITH(cups_user, [  --with-cups-user        set default user for CUPS],
                AC_MSG_RESULT(no password file, using "$CUPS_USER")
        fi)
 
+if test "x$CUPS_USER" = "xroot" -o "x$CUPS_USER" = "x0"; then
+       AC_MSG_ERROR([The default user for CUPS cannot be root!])
+fi
+
 AC_ARG_WITH(cups_group, [  --with-cups-group       set default group for CUPS],
        CUPS_GROUP="$withval",
        AC_MSG_CHECKING(for default print group)
@@ -238,6 +242,10 @@ AC_ARG_WITH(cups_group, [  --with-cups-group       set default group for CUPS],
                AC_MSG_RESULT(no group file, using "$CUPS_GROUP")
        fi)
 
+if test "x$CUPS_GROUP" = "xroot" -o "x$CUPS_GROUP" = "xwheel" -o "x$CUPS_GROUP" = "x0"; then
+       AC_MSG_ERROR([The default group for CUPS cannot be root!])
+fi
+
 AC_ARG_WITH(system_groups, [  --with-system-groups    set default system groups for CUPS],
        CUPS_SYSTEM_GROUPS="$withval",
        if test x$uname = xDarwin; then
@@ -269,9 +277,14 @@ AC_ARG_WITH(system_groups, [  --with-system-groups    set default system groups
                fi
        fi)
 
-
 CUPS_PRIMARY_SYSTEM_GROUP="`echo $CUPS_SYSTEM_GROUPS | awk '{print $1}'`"
 
+for group in $CUPS_SYSTEM_GROUPS; do
+       if test "x$CUPS_GROUP" = "x$group"; then
+               AC_MSG_ERROR([The default system groups cannot contain the default CUPS group!])
+       fi
+done
+
 AC_SUBST(CUPS_USER)
 AC_SUBST(CUPS_GROUP)
 AC_SUBST(CUPS_SYSTEM_GROUPS)
index 099f451d8248c778ade3db9238d87366529ca0d1..85a2b38364cc72720bfb6218b8fd1c110b8b06c1 100644 (file)
@@ -144,6 +144,12 @@ cupsAddDest(const char  *name,             /* I  - Destination name */
 
     dest = cups_add_dest(name, instance, &num_dests, dests);
 
+   /*
+    * Find the base dest again now the array has been realloc'd.
+    */
+
+    parent = cupsGetDest(name, NULL, num_dests, *dests);
+
     if (instance && parent && parent->num_options > 0)
     {
      /*
index 87ba2c0ce508e03eaa0ba12d7e7e7ec7d96e978a..7bfbe29a2c76502dc3d5fcd5385a46d9b1c46faa 100644 (file)
@@ -570,17 +570,17 @@ cupsGetJobs2(http_t     *http,            /* I - Connection to server or @code CUPS_HTTP_D
   _cups_globals_t *cg = _cupsGlobals();        /* Pointer to library globals */
   static const char * const attrs[] =  /* Requested attributes */
                {
+                 "document-format",
                  "job-id",
-                 "job-priority",
                  "job-k-octets",
+                 "job-name",
+                 "job-originating-user-name",
+                 "job-printer-uri",
+                 "job-priority",
                  "job-state",
                  "time-at-completed",
                  "time-at-creation",
-                 "time-at-processing",
-                 "job-printer-uri",
-                 "document-format",
-                 "job-name",
-                 "job-originating-user-name"
+                 "time-at-processing"
                };
 
 
@@ -1456,6 +1456,9 @@ cupsPrintFiles2(
   char         buffer[8192];           /* Copy buffer */
   ssize_t      bytes;                  /* Bytes in buffer */
   http_status_t        status;                 /* Status of write */
+  _cups_globals_t *cg = _cupsGlobals();        /* Global data */
+  ipp_status_t cancel_status;          /* Status code to preserve */
+  char         *cancel_message;        /* Error message to preserve */
 
 
   DEBUG_printf(("cupsPrintFiles2(http=%p, name=\"%s\", num_files=%d, "
@@ -1507,8 +1510,8 @@ cupsPrintFiles2(
       * Unable to open print file, cancel the job and return...
       */
 
-      cupsCancelJob2(http, name, job_id, 0);
-      return (0);
+      _cupsSetError(IPP_DOCUMENT_ACCESS_ERROR, NULL, 0);
+      goto cancel_job;
     }
 
     do
@@ -1550,12 +1553,30 @@ cupsPrintFiles2(
       * Unable to queue, cancel the job and return...
       */
 
-      cupsCancelJob2(http, name, job_id, 0);
-      return (0);
+      goto cancel_job;
     }
   }
 
   return (job_id);
+
+ /*
+  * If we get here, something happened while sending the print job so we need
+  * to cancel the job without setting the last error (since we need to preserve
+  * the current error...
+  */
+
+  cancel_job:
+
+  cancel_status  = cg->last_error;
+  cancel_message = cg->last_status_message ?
+                       _cupsStrRetain(cg->last_status_message) : NULL;
+
+  cupsCancelJob2(http, name, job_id, 0);
+
+  cg->last_error          = cancel_status;
+  cg->last_status_message = cancel_message;
+
+  return (0);
 }
 
 
index 4f880b461d6b2db5d05d593434f45248004cd3ba..6b3384bbc22e363962beb40d3f78af57e233c88f 100644 (file)
@@ -123,7 +123,8 @@ to the access log file. The following levels are defined:</P>
   Allow from nnn.nnn.nnn.nnn
   Allow from nnn.nnn.nnn.nnn/mm
   Allow from nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
-  Allow from xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
+  Allow from [xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx]
+  Allow from [xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx]/mmm
   Allow from @LOCAL
   Allow from @IF(name)
 &lt;/Location&gt;
@@ -1071,7 +1072,8 @@ printers are shared (published) by default. The default is
   Deny from nnn.nnn.nnn.nnn
   Deny from nnn.nnn.nnn.nnn/mm
   Deny from nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
-  Deny from xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
+  Deny from [xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx]
+  Deny from [xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx]/mmm
   Deny from @LOCAL
   Deny from @IF(name)
 &lt;/Location&gt;
index 9fce558dcef6f8bf0ef449654a4921075956efef..2ac011e77e400d9182e57c6601128b30853916e7 100644 (file)
@@ -161,9 +161,8 @@ based on well-known colorspaces such as sRGB and Adobe RGB.</p>
 
 <blockquote><b>Note:</b>
 
-<p>At this time, none of the CUPS raster
-filters support ICC profiles. This will be addressed as time
-and resources permit.</p>
+<p>At this time, none of the CUPS raster filters support ICC profiles. This
+will be addressed as time and resources permit.</p>
 
 </blockquote>
 
@@ -174,7 +173,7 @@ gamma m00 m01 m02 m10 m11 m12 m20 m21 m22"</p>
 
 <p>This string attribute specifies an sRGB-based color profile
 consisting of gamma and density controls and a 3x3 CMY color
-transform matrix.</p>
+transform matrix. <em>This attribute is not supported on Mac OS X.</em></p>
 
 <p>The <i>Resolution</i> and <i>MediaType</i> values may be "-"
 to act as a wildcard. Otherwise they must match one of the
@@ -277,6 +276,15 @@ data as requested by the driver. The <tt>APCustomColorMatchingProfile</tt>
 and <tt>APDefaultColorMatchingProfile</tt> attributes specify alternate
 color profiles (sRGB or AdobeRGB) to use for 3-color (RGB) raster data.</p>
 
+<blockquote><b>Note:</b>
+
+<p>Prior to Mac OS X 10.6, the default RGB color space was Apple's "GenericRGB".
+The new default in Mac OS X 10.6 and later is "sRGB". For more information, see
+<a href="http://support.apple.com/kb/HT3712">"Mac OS X v10.6: About gamma
+2.2"</a> on Apple's support site.</p>
+
+</blockquote>
+
 <h4><span class='info'>Mac OS X 10.5</span><a name='APCustomColorMatchingName'>APCustomColorMatchingName</a></h4>
 
 <p class='summary'>*APCustomColorMatchingName name/text: ""</p>
index f95417e64ff4e600238168cae9f92eb496a8f935..b4659fe3f3b6dc9d276de6307188744089c33ed3 100644 (file)
@@ -5430,14 +5430,6 @@ copy_printer_attrs(
 
   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, "marker-change-time"))
     ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
                   "marker-change-time", printer->marker_time);
@@ -7007,7 +6999,18 @@ get_jobs(cupsd_client_t  *con,           /* I - Client connection */
   else
     username[0] = '\0';
 
-  ra = create_requested_array(con->request);
+  if ((ra = create_requested_array(con->request)) == NULL &&
+      !ippFindAttribute(con->request, "requested-attributes", IPP_TAG_KEYWORD))
+  {
+   /*
+    * IPP conformance - Get-Jobs has a default requested-attributes value of
+    * "job-id" and "job-uri".
+    */
+
+    ra = cupsArrayNew((cups_array_func_t)strcmp, NULL);
+    cupsArrayAdd(ra, "job-id");
+    cupsArrayAdd(ra, "job-uri");
+  }
 
  /*
   * OK, build a list of jobs for this printer...
index b3385670735120fec2c8c59eade295892b583188..dd3df67a80049ac16c24c960c374169397c24875 100644 (file)
@@ -2441,7 +2441,7 @@ cupsdSetJobState(
   * Finalize the job immediately if we forced things...
   */
 
-  if (action >= CUPSD_JOB_FORCE)
+  if (action >= CUPSD_JOB_FORCE && job->printer)
     finalize_job(job, 0);
 
  /*
index 28ae983f01d6fb699acaf098306b384224bbadcf..60e97d095a037814bc48d9776fe6faa75b8d7239 100644 (file)
@@ -134,7 +134,7 @@ main(int  argc,                             /* I - Number of command-line args */
                        senddoc_time,   /* Send-Document time */
                        expire_time,    /* Subscription expire time */
                        report_time,    /* Malloc/client/job report time */
-                       event_time;     /* Last time an event notification was done */
+                       event_time;     /* Last event notification time */
   long                 timeout;        /* Timeout for cupsdDoSelect() */
   struct rlimit                limit;          /* Runtime limit */
 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
@@ -270,19 +270,22 @@ main(int  argc,                           /* I - Number of command-line args */
              break;
 
           case 'p' : /* Stop immediately for profiling */
-              puts("Warning: -p (startup profiling) is for internal testing use only!");
+              fputs("cupsd: -p (startup profiling) is for internal testing "
+                    "use only!\n", stderr);
              stop_scheduler = 1;
              fg             = 1;
              break;
 
           case 'P' : /* Disable security profiles */
-              puts("Warning: -P (disable security profiles) is for internal testing use only!");
+              fputs("cupsd: -P (disable security profiles) is for internal "
+                    "testing use only!\n", stderr);
              UseProfiles = 0;
              break;
 
 #ifdef __APPLE__
           case 'S' : /* Disable system management functions */
-              puts("Warning: -S (disable system management) for internal testing use only!");
+              fputs("cupsd: -S (disable system management) for internal "
+                    "testing use only!\n", stderr);
              use_sysman = 0;
              break;
 #endif /* __APPLE__ */
@@ -763,7 +766,8 @@ main(int  argc,                             /* I - Number of command-line args */
        if (Launchd)
        {
         /*
-         * If we were started by launchd get the listen sockets file descriptors...
+         * If we were started by launchd, get the listen socket file
+         * descriptors...
          */
 
          launchd_checkin();
@@ -1566,8 +1570,8 @@ launchd_checkin(void)
          if ((lis = calloc(1, sizeof(cupsd_listener_t))) == NULL)
          {
            cupsdLogMessage(CUPSD_LOG_ERROR,
-                           "launchd_checkin: Unable to allocate listener - %s.",
-                           strerror(errno));
+                           "launchd_checkin: Unable to allocate listener - "
+                           "%s.", strerror(errno));
            exit(EXIT_FAILURE);
          }
 
@@ -1623,7 +1627,8 @@ launchd_checkout(void)
         (BrowseLocalProtocols && NumBrowsers && cupsArrayCount(Printers))))))
   {
     cupsdLogMessage(CUPSD_LOG_DEBUG,
-                    "Creating launchd keepalive file \"" CUPS_KEEPALIVE "\"...");
+                    "Creating launchd keepalive file \"" CUPS_KEEPALIVE
+                    "\"...");
 
     if ((fd = open(CUPS_KEEPALIVE, O_RDONLY | O_CREAT | O_EXCL, S_IRUSR)) >= 0)
       close(fd);
@@ -1631,7 +1636,8 @@ launchd_checkout(void)
   else
   {
     cupsdLogMessage(CUPSD_LOG_DEBUG,
-                    "Removing launchd keepalive file \"" CUPS_KEEPALIVE "\"...");
+                    "Removing launchd keepalive file \"" CUPS_KEEPALIVE
+                    "\"...");
 
     unlink(CUPS_KEEPALIVE);
   }
@@ -1767,7 +1773,7 @@ process_children(void)
                job->printer_message = ippAddString(job->attrs, IPP_TAG_JOB,
                                                    IPP_TAG_TEXT,
                                                    "job-printer-state-message",
-                                                   NULL, "");
+                                                   NULL, NULL);
            }
 
            if (job->printer_message)
@@ -1781,7 +1787,7 @@ process_children(void)
        * filters are done, and if so move to the next file.
        */
 
-       if (job->current_file < job->num_files)
+       if (job->current_file < job->num_files && job->printer)
        {
          for (i = 0; job->filters[i] < 0; i ++);
 
@@ -1794,7 +1800,7 @@ process_children(void)
            cupsdContinueJob(job);
          }
        }
-       else if (job->state_value == IPP_JOB_CANCELED)
+       else if (job->state_value >= IPP_JOB_CANCELED)
        {
         /*
          * Remove the job from the active list if there are no processes still
index b12a5498e40905b081ce8cf41547a54c0be901d0..1e615ebe0c15c8d8d53fc4b13676a903f6838d00 100644 (file)
@@ -205,11 +205,6 @@ cupsdAddPrinterHistory(
   ippAddBoolean(history, IPP_TAG_PRINTER, "printer-is-shared", p->shared);
   ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-state-message",
                NULL, p->state_message);
-#ifdef __APPLE__
-  if (p->recoverable)
-    ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_TEXT,
-                 "com.apple.print.recoverable-message", NULL, p->recoverable);
-#endif /* __APPLE__ */
   if (p->num_reasons == 0)
     ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
                  "printer-state-reasons", NULL, "none");
@@ -649,7 +644,10 @@ cupsdDeleteAllPrinters(void)
   for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
        p;
        p = (cupsd_printer_t *)cupsArrayNext(Printers))
+  {
+    p->op_policy_ptr = DefaultPolicyPtr;
     cupsdDeletePrinter(p, 0);
+  }
 }
 
 
@@ -841,10 +839,6 @@ cupsdDeletePrinter(
   if (p->browse_attrs)
     free(p->browse_attrs);
 
-#ifdef __APPLE__
-  cupsdClearString(&p->recoverable);
-#endif /* __APPLE__ */
-
   cupsFreeOptions(p->num_options, p->options);
 
   free(p);
@@ -1094,7 +1088,6 @@ cupsdLoadAllPrinters(void)
     else if (!strcasecmp(line, "Reason"))
     {
       if (value &&
-          strcmp(value, "com.apple.print.recoverable-warning") &&
           strcmp(value, "connecting-to-device") &&
           strcmp(value, "cups-insecure-filter-warning") &&
           strcmp(value, "cups-missing-filter-warning"))
@@ -1599,8 +1592,7 @@ cupsdSaveAllPrinters(void)
     cupsFilePrintf(fp, "StateTime %d\n", (int)printer->state_time);
 
     for (i = 0; i < printer->num_reasons; i ++)
-      if (strcmp(printer->reasons[i], "com.apple.print.recoverable-warning") &&
-          strcmp(printer->reasons[i], "connecting-to-device") &&
+      if (strcmp(printer->reasons[i], "connecting-to-device") &&
           strcmp(printer->reasons[i], "cups-insecure-filter-warning") &&
           strcmp(printer->reasons[i], "cups-missing-filter-warning"))
         cupsFilePutConf(fp, "Reason", printer->reasons[i]);
@@ -3756,7 +3748,7 @@ add_printer_formats(cupsd_printer_t *p)   /* I - Printer */
         filter;
         filter = (mime_filter_t *)cupsArrayNext(MimeDatabase->filters))
     {
-      if (filter->dst == p->filetype && filter->filter && 
+      if (filter->dst == p->filetype && filter->filter &&
          strstr(filter->filter, "PrintJobMgr"))
        break;
     }
index 292a4b5622ab938ca0e491217acbd8e4acd20662..713539941874ea3cd3cdcb4b54085224f2984410 100644 (file)
@@ -94,7 +94,6 @@ typedef struct cupsd_printer_s
   time_t       marker_time;            /* Last time marker attributes were updated */
   cups_array_t *filters,               /* Filters for queue */
                *pre_filters;           /* Pre-filters for queue */
-  char         *recoverable;           /* com.apple.print.recoverable-message */
 
 #ifdef HAVE_DNSSD
   char         *reg_name,              /* Name used for service registration */
index 603ecdd25b008b1ca66a8f83139e2209daf0ac17..e98aaa70d749b0c7ee4ed57d34b444469911a90e 100644 (file)
@@ -1287,10 +1287,10 @@ show_jobs(const char *dests,            /* I - Destinations */
                  "job-id",
                  "job-k-octets",
                  "job-name",
-                 "time-at-creation",
-                 "job-printer-uri",
                  "job-originating-user-name",
-                 "job-state-reasons"
+                 "job-printer-uri",
+                 "job-state-reasons",
+                 "time-at-creation"
                };
 
 
index 1b0a71afae1f315d362a5cd63729839dda250067..2f2236b0cc7db6061eb0c2d03f9ad50a31de8b56 100644 (file)
        # What attributes do we expect?
        EXPECT attributes-charset
        EXPECT attributes-natural-language
+       EXPECT !job-printer-uri
 }
 {
        # The name of the test...
        ATTR charset attributes-charset utf-8
        ATTR language attributes-natural-language en
        ATTR uri printer-uri $scheme://$hostname:$port/
+       ATTR keyword requested-attributes all
 
        # What statuses are OK?
        STATUS successful-ok
        EXPECT job-uri
        EXPECT job-id
        EXPECT job-state
+       EXPECT job-printer-uri
 }
 
 #
index 43ea40074639ff4441e66c841099262d357547cb..a395277e9fc1d822fe7f90f5d128a9bb87d920b9 100644 (file)
@@ -3,3 +3,4 @@
 ipptest.o: ../cups/string.h ../config.h ../cups/cups.h ../cups/ipp.h
 ipptest.o: ../cups/http.h ../cups/versioning.h ../cups/ppd.h ../cups/array.h
 ipptest.o: ../cups/file.h ../cups/language.h ../cups/language.h
+ipptest.o: ../cups/http-private.h ../cups/md5.h ../cups/ipp-private.h
index 59f2fb803549f22a897fc29b0fd5cc8ce20103c5..28404388da93d9763fa1ead1dd91a81b3718aa85 100644 (file)
  *
  * Contents:
  *
- *   main()       - Parse options and do tests.
- *   do_tests()   - Do tests as specified in the test file.
- *   get_token()  - Get a token from a file.
- *   print_attr() - Print an attribute on the screen.
- *   usage()      - Show program usage.
+ *   main()           - Parse options and do tests.
+ *   do_tests()       - Do tests as specified in the test file.
+ *   expect_matches() - Return true if the tag matches the specification.
+ *   get_token()      - Get a token from a file.
+ *   print_attr()     - Print an attribute on the screen.
+ *   print_col()      - Print a collection attribute on the screen.
+ *   usage()          - Show program usage.
  */
 
 /*
 
 #include <cups/cups.h>
 #include <cups/language.h>
+#include <cups/http-private.h>
+#ifndef O_BINARY
+#  define O_BINARY 0
+#endif /* !O_BINARY */
+
+
+/*
+ * Types...
+ */
+
+typedef struct _cups_expect_s          /**** Expected attribute info ****/
+{
+  int  not_expect;                     /* Don't expect attribute? */
+  char *name,                          /* Attribute name */
+       *of_type,                       /* Type name */
+       *same_count_as,                 /* Parallel attribute name */
+       *if_defined;                    /* Only required if variable defined */
+} _cups_expect_t;
 
 
 /*
  * Globals...
  */
 
+int            Chunking = 0;           /* Use chunked requests */
 int            Verbosity = 0;          /* Show all attributes? */
 
 
@@ -46,13 +67,13 @@ int         Verbosity = 0;          /* Show all attributes? */
  * Local functions...
  */
 
-int            do_tests(const char *, const char *);
-ipp_op_t       ippOpValue(const char *);
-ipp_status_t   ippErrorValue(const char *);
-char           *get_token(FILE *, char *, int, int *linenum);
-void           print_attr(ipp_attribute_t *);
-void           print_col(ipp_t *col);
-void           usage(const char *option);
+static int     do_tests(const char *uri, const char *testfile);
+static int      expect_matches(_cups_expect_t *expect, ipp_tag_t value_tag);
+static char    *get_token(FILE *fp, char *buf, int buflen,
+                          int *linenum);
+static void    print_attr(ipp_attribute_t *attr);
+static void    print_col(ipp_t *col);
+static void    usage(void);
 
 
 /*
@@ -60,13 +81,14 @@ void                usage(const char *option);
  */
 
 int                                    /* O - Exit status */
-main(int  argc,                                /* I - Number of command-line arguments */
+main(int  argc,                                /* I - Number of command-line args */
      char *argv[])                     /* I - Command-line arguments */
 {
   int          i;                      /* Looping var */
   int          status;                 /* Status of tests... */
-  const char   *uri;                   /* URI to use */
-  const char   *testfile;              /* Test file to use */
+  char         *opt;                   /* Current option */
+  const char   *uri,                   /* URI to use */
+               *testfile;              /* Test file to use */
   int          interval;               /* Test interval */
 
 
@@ -85,28 +107,48 @@ main(int  argc,                            /* I - Number of command-line arguments */
   {
     if (argv[i][0] == '-')
     {
-      if (!strcmp(argv[i], "-v"))
-        Verbosity ++;
-      else if (!strcmp(argv[i], "-d"))
+      for (opt = argv[i] + 1; *opt; opt ++)
       {
-        i ++;
+        switch (*opt)
+        {
+          case 'c' : /* Enable HTTP chunking */
+              Chunking = 1;
+              break;
 
-       if (i >= argc)
-         usage(NULL);
-       else
-         putenv(argv[i]);
-      }
-      else if (!strcmp(argv[i], "-i"))
-      {
-        i++;
+          case 'd' : /* Define a variable */
+             i ++;
 
-       if (i >= argc)
-         usage(NULL);
-       else
-         interval = atoi(argv[i]);
+             if (i >= argc)
+             {
+               fputs("ipptest: Missing name=value for \"-d\"!\n", stderr);
+               usage();
+              }
+             else
+               putenv(argv[i]);
+             break;
+
+          case 'i' : /* Test every N seconds */
+             i++;
+
+             if (i >= argc)
+             {
+               fputs("ipptest: Missing seconds for \"-i\"!\n", stderr);
+               usage();
+              }
+             else
+               interval = atoi(argv[i]);
+             break;
+
+          case 'v' : /* Be verbose */
+             Verbosity ++;
+             break;
+
+         default :
+             fprintf(stderr, "ipptest: Unknown option \"-%c\"!\n", *opt);
+             usage();
+             break;
+       }
       }
-      else
-        usage(argv[i]);
     }
     else if (!strncmp(argv[i], "ipp://", 6) ||
              !strncmp(argv[i], "http://", 7) ||
@@ -117,7 +159,11 @@ main(int  argc,                            /* I - Number of command-line arguments */
       */
 
       if (!testfile && uri)
-        usage(NULL);
+      {
+        fputs("ipptest: May only specify a single URI before a test!\n",
+              stderr);
+        usage();
+      }
 
       uri      = argv[i];
       testfile = NULL;
@@ -136,7 +182,7 @@ main(int  argc,                             /* I - Number of command-line arguments */
   }
 
   if (!uri || !testfile)
-    usage(NULL);
+    usage();
 
  /*
   * Loop if the interval is set...
@@ -158,12 +204,12 @@ main(int  argc,                           /* I - Number of command-line arguments */
   return (status);
 }
 
-
+        
 /*
  * 'do_tests()' - Do tests as specified in the test file.
  */
 
-int                                    /* 1 = success, 0 = failure */
+static int                             /* 1 = success, 0 = failure */
 do_tests(const char *uri,              /* I - URI to connect on */
          const char *testfile)         /* I - Test file to use */
 {
@@ -186,12 +232,15 @@ do_tests(const char *uri,         /* I - URI to connect on */
   ipp_op_t     op;                     /* Operation */
   ipp_tag_t    group;                  /* Current group */
   ipp_tag_t    value;                  /* Current value type */
-  ipp_attribute_t *attrptr;            /* Attribute pointer */
+  ipp_attribute_t *attrptr,            /* Attribute pointer */
+               *found;                 /* Found attribute */
   char         attr[128];              /* Attribute name */
   int          num_statuses;           /* Number of valid status codes */
   ipp_status_t statuses[100];          /* Valid status codes */
   int          num_expects;            /* Number of expected attributes */
-  char         *expects[100];          /* Expected attributes */
+  _cups_expect_t expects[100],         /* Expected attributes */
+               *expect,                /* Current expected attribute */
+               *last_expect;           /* Last EXPECT (for predicates) */
   int          num_displayed;          /* Number of displayed attributes */
   char         *displayed[100];        /* Displayed attributes */
   char         name[1024];             /* Name of test */
@@ -265,6 +314,7 @@ do_tests(const char *uri,           /* I - URI to connect on */
     num_statuses  = 0;
     num_expects   = 0;
     num_displayed = 0;
+    last_expect   = NULL;
     filename[0]   = '\0';
 
     strcpy(name, testfile);
@@ -277,6 +327,12 @@ do_tests(const char *uri,          /* I - URI to connect on */
 
     while (get_token(fp, token, sizeof(token), &linenum) != NULL)
     {
+      if (strcasecmp(token, "EXPECT") &&
+          strcasecmp(token, "IF-DEFINED") &&
+          strcasecmp(token, "OF-TYPE") &&
+          strcasecmp(token, "SAME-COUNT-AS"))
+        last_expect = NULL;
+
       if (!strcmp(token, "}"))
         break;
       else if (!strcasecmp(token, "NAME"))
@@ -526,16 +582,87 @@ do_tests(const char *uri,         /* I - URI to connect on */
        statuses[num_statuses] = ippErrorValue(token);
        num_statuses ++;
       }
-      else if (!strcasecmp(token, "EXPECT") &&
-               num_expects < (int)(sizeof(expects) / sizeof(expects[0])))
+      else if (!strcasecmp(token, "EXPECT"))
       {
        /*
         * Expected attributes...
        */
 
+        if (num_expects >= (int)(sizeof(expects) / sizeof(expects[0])))
+        {
+         fprintf(stderr, "ipptest: Too many EXPECT's on line %d\n", linenum);
+         httpClose(http);
+         ippDelete(request);
+         return (0);
+        }
+
        get_token(fp, token, sizeof(token), &linenum);
-       expects[num_expects] = strdup(token);
+
+        last_expect = expects + num_expects;
        num_expects ++;
+
+        if (token[0] == '!')
+        {
+          last_expect->not_expect = 1;
+          last_expect->name       = strdup(token + 1);
+        }
+        else
+        {
+          last_expect->not_expect = 0;
+         last_expect->name       = strdup(token);
+       }
+
+        last_expect->of_type       = NULL;
+        last_expect->same_count_as = NULL;
+        last_expect->if_defined    = NULL;
+      }
+      else if (!strcasecmp(token, "OF-TYPE"))
+      {
+       get_token(fp, token, sizeof(token), &linenum);
+
+       if (last_expect)
+         last_expect->of_type = strdup(token);
+       else
+       {
+         fprintf(stderr,
+                 "ipptest: OF-TYPE without a preceding EXPECT on line %d\n",
+                 linenum);
+         httpClose(http);
+         ippDelete(request);
+         return (0);
+       }
+      }
+      else if (!strcasecmp(token, "SAME-COUNT-AS"))
+      {
+       get_token(fp, token, sizeof(token), &linenum);
+
+       if (last_expect)
+         last_expect->same_count_as = strdup(token);
+       else
+       {
+         fprintf(stderr,
+                 "ipptest: SAME-COUNT-AS without a preceding EXPECT on line "
+                 "%d\n", linenum);
+         httpClose(http);
+         ippDelete(request);
+         return (0);
+       }
+      }
+      else if (!strcasecmp(token, "IF-DEFINED"))
+      {
+       get_token(fp, token, sizeof(token), &linenum);
+
+       if (last_expect)
+         last_expect->if_defined = strdup(token);
+       else
+       {
+         fprintf(stderr,
+                 "ipptest: IF-DEFINED without a preceding EXPECT on line %d\n",
+                 linenum);
+         httpClose(http);
+         ippDelete(request);
+         return (0);
+       }
       }
       else if (!strcasecmp(token, "DISPLAY") &&
                num_displayed < (int)(sizeof(displayed) / sizeof(displayed[0])))
@@ -550,8 +677,9 @@ do_tests(const char *uri,           /* I - URI to connect on */
       }
       else
       {
-       printf("Unexpected token %s seen on line %d - aborting test!\n", token,
-              linenum);
+       fprintf(stderr,
+               "ipptest: Unexpected token %s seen on line %d - aborting "
+               "test!\n", token, linenum);
        httpClose(http);
        ippDelete(request);
        return (0);
@@ -569,7 +697,7 @@ do_tests(const char *uri,           /* I - URI to connect on */
 
     if (Verbosity)
     {
-      printf("%s:\n", ippOpString(op));
+      printf("    %s:\n", ippOpString(op));
 
       for (attrptr = request->attrs; attrptr; attrptr = attrptr->next)
        print_attr(attrptr);
@@ -578,7 +706,36 @@ do_tests(const char *uri,          /* I - URI to connect on */
     printf("    %-60.60s [", name);
     fflush(stdout);
 
-    if (filename[0])
+    if (Chunking)
+    {
+      http_status_t status = cupsSendRequest(http, request, resource, 0);
+
+      if (status == HTTP_CONTINUE && filename[0])
+      {
+        int    fd;                     /* File to send */
+        char   buffer[8192];           /* Copy buffer */
+        ssize_t        bytes;                  /* Bytes read/written */
+
+
+        if ((fd = open(filename, O_RDONLY | O_BINARY)) >= 0)
+        {
+          while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
+            if ((status = cupsWriteRequestData(http, buffer,
+                                               bytes)) != HTTP_CONTINUE)
+              break;
+        }
+        else
+          status = HTTP_ERROR;
+      }
+
+      ippDelete(request);
+
+      if (status == HTTP_CONTINUE)
+       response = cupsGetResponse(http, resource);
+      else
+       response = NULL;
+    }
+    else if (filename[0])
       response = cupsDoFileRequest(http, request, resource, filename);
     else
       response = cupsDoIORequest(http, request, resource, -1,
@@ -597,6 +754,9 @@ do_tests(const char *uri,           /* I - URI to connect on */
     }
     else
     {
+      if (http->version != HTTP_1_1)
+        pass = 0;
+
       if ((attrptr = ippFindAttribute(response, "job-id",
                                       IPP_TAG_INTEGER)) != NULL)
         job_id = attrptr->values[0].integer;
@@ -613,12 +773,32 @@ do_tests(const char *uri,         /* I - URI to connect on */
        pass = 0;
       else
       {
-        for (i = 0; i < num_expects; i ++)
-         if (ippFindAttribute(response, expects[i], IPP_TAG_ZERO) == NULL)
-         {
-           pass = 0;
-           break;
-         }
+        for (i = num_expects, expect = expects; i > 0; i --, expect ++)
+        {
+          if (expect->if_defined && !getenv(expect->if_defined))
+            continue;
+
+          found = ippFindAttribute(response, expect->name, IPP_TAG_ZERO);
+
+          if ((found == NULL) != expect->not_expect ||
+              (found && !expect_matches(expect, found->value_tag)))
+          {
+           pass = 0;
+           break;          
+          }
+
+          if (found && expect->same_count_as)
+          {
+            attrptr = ippFindAttribute(response, expect->same_count_as,
+                                       IPP_TAG_ZERO);
+
+            if (!attrptr || attrptr->num_values != found->num_values)
+            {
+              pass = 0;
+              break;
+            }
+          }
+        }
       }
 
       if (pass)
@@ -629,21 +809,31 @@ do_tests(const char *uri,         /* I - URI to connect on */
 
         if (Verbosity)
        {
-         for (attrptr = response->attrs; attrptr != NULL; attrptr = attrptr->next)
+         for (attrptr = response->attrs;
+              attrptr != NULL;
+              attrptr = attrptr->next)
+         {
            print_attr(attrptr);
+          }
         }
         else if (num_displayed > 0)
        {
-         for (attrptr = response->attrs; attrptr != NULL; attrptr = attrptr->next)
+         for (attrptr = response->attrs;
+              attrptr != NULL;
+              attrptr = attrptr->next)
+         {
            if (attrptr->name)
            {
              for (i = 0; i < num_displayed; i ++)
+             {
                if (!strcmp(displayed[i], attrptr->name))
                {
                  print_attr(attrptr);
                  break;
                }
+             }
            }
+         }
         }
       }
       else
@@ -652,6 +842,10 @@ do_tests(const char *uri,          /* I - URI to connect on */
        printf("        RECEIVED: %lu bytes in response\n",
               (unsigned long)ippLength(response));
 
+        if (http->version != HTTP_1_1)
+          printf("        BAD HTTP VERSION (%d.%d)\n", http->version / 100,
+                 http->version % 100);
+
        for (i = 0; i < num_statuses; i ++)
           if (response->request.status.status_code == statuses[i])
            break;
@@ -662,9 +856,43 @@ do_tests(const char *uri,          /* I - URI to connect on */
        printf("        status-code = %04x (%s)\n",
               cupsLastError(), ippErrorString(cupsLastError()));
 
-        for (i = 0; i < num_expects; i ++)
-         if (ippFindAttribute(response, expects[i], IPP_TAG_ZERO) == NULL)
-           printf("        EXPECTED: %s\n", expects[i]);
+        for (i = num_expects, expect = expects; i > 0; i --, expect ++)
+        {
+          if (expect->if_defined && !getenv(expect->if_defined))
+            continue;
+
+          found = ippFindAttribute(response, expect->name, IPP_TAG_ZERO);
+
+          if ((found == NULL) != expect->not_expect)
+          {
+            if (expect->not_expect)
+             printf("        NOT EXPECTED: %s\n", expect->name);
+           else
+             printf("        EXPECTED: %s\n", expect->name);
+         }
+          else if (found)
+          {
+            if (!expect_matches(expect, found->value_tag))
+              printf("        EXPECTED: %s of type %s but got %s\n", 
+                     expect->name, expect->of_type,
+                     ippTagString(found->value_tag));
+           else if (expect->same_count_as)
+           {
+             attrptr = ippFindAttribute(response, expect->same_count_as,
+                                        IPP_TAG_ZERO);
+  
+             if (!attrptr)
+               printf("        EXPECTED: %s (%d values) same count as %s "
+                      "(not returned)\n", 
+                      expect->name, found->num_values, expect->same_count_as);
+             else if (attrptr->num_values != found->num_values)
+               printf("        EXPECTED: %s (%d values) same count as %s "
+                      "(%d values)\n", 
+                      expect->name, found->num_values, expect->same_count_as,
+                      attrptr->num_values);
+           }
+         }
+        }
 
        for (attrptr = response->attrs; attrptr != NULL; attrptr = attrptr->next)
          print_attr(attrptr);
@@ -673,9 +901,16 @@ do_tests(const char *uri,          /* I - URI to connect on */
       ippDelete(response);
     }
 
-    for (i = 0; i < num_expects; i ++)
-      free(expects[i]);
-
+    for (i = num_expects, expect = expects; i > 0; i --, expect ++)
+    {
+      free(expect->name);
+      if (expect->of_type)
+        free(expect->of_type);
+      if (expect->same_count_as)
+        free(expect->same_count_as);
+      if (expect->if_defined)
+        free(expect->if_defined);
+    }
     if (!pass)
       break;
   }
@@ -687,11 +922,71 @@ do_tests(const char *uri,         /* I - URI to connect on */
 }
 
 
+/*
+ * 'expect_matches()' - Return true if the tag matches the specification.
+ */
+static int                             /* O - 1 if matches, 0 otherwise */
+expect_matches(
+    _cups_expect_t *expect,            /* I - Expected attribute */
+    ipp_tag_t      value_tag)          /* I - Value tag for attribute */
+{
+  int  match;                          /* Match? */
+  char *of_type,                       /* Type name to match */
+       *next;                          /* Next name to match */
+
+
+ /*
+  * If we don't expect a particular type, return immediately...
+  */
+
+  if (!expect->of_type)
+    return (1);
+
+ /*
+  * Parse the "of_type" value since the string can contain multiple attribute
+  * types separated by "|"...
+  */
+
+  for (of_type = expect->of_type, match = 0; !match && of_type; of_type = next)
+  {
+   /*
+    * Find the next separator, and set it (temporarily) to nul if present.
+    */
+
+    if ((next = strchr(of_type, '|')) != NULL)
+      *next = '\0';
+  
+   /*
+    * Support some meta-types to make it easier to write the test file.
+    */
+
+    if (!strcmp(of_type, "text"))
+      match = value_tag == IPP_TAG_TEXTLANG || value_tag == IPP_TAG_TEXT;            
+    else if (!strcmp(of_type, "name"))
+      match = value_tag == IPP_TAG_NAMELANG || value_tag == IPP_TAG_NAME;    
+    else if (!strcmp(of_type, "collection"))
+      match = value_tag == IPP_TAG_BEGIN_COLLECTION;   
+    else
+      match = value_tag == ippTagValue(of_type);
+
+   /*
+    * Restore the separator if we have one...
+    */
+
+    if (next)
+      *next++ = '|';
+  }
+
+  return (match);
+}
+
+
 /*
  * 'get_token()' - Get a token from a file.
  */
 
-char *                                 /* O  - Token from file or NULL on EOF */
+static char *                          /* O  - Token from file or NULL on EOF */
 get_token(FILE *fp,                    /* I  - File to read from */
           char *buf,                   /* I  - Buffer to read into */
          int  buflen,                  /* I  - Length of buffer */
@@ -783,7 +1078,7 @@ get_token(FILE *fp,                        /* I  - File to read from */
  * 'print_attr()' - Print an attribute on the screen.
  */
 
-void
+static void
 print_attr(ipp_attribute_t *attr)      /* I - Attribute to print */
 {
   int          i;                      /* Looping var */
@@ -861,7 +1156,7 @@ print_attr(ipp_attribute_t *attr)  /* I - Attribute to print */
          print_col(attr->values[i].collection);
        }
        break;
-        
+
     default :
        break; /* anti-compiler-warning-code */
   }
@@ -874,7 +1169,7 @@ print_attr(ipp_attribute_t *attr)  /* I - Attribute to print */
  * 'print_col()' - Print a collection attribute on the screen.
  */
 
-void
+static void
 print_col(ipp_t *col)                  /* I - Collection attribute to print */
 {
   int                  i;              /* Looping var */
@@ -947,7 +1242,7 @@ print_col(ipp_t *col)                      /* I - Collection attribute to print */
            putchar(' ');
          }
          break;
-         
+
       default :
          break; /* anti-compiler-warning-code */
     }
@@ -961,17 +1256,18 @@ print_col(ipp_t *col)                    /* I - Collection attribute to print */
  * 'usage()' - Show program usage.
  */
 
-void
-usage(const char *option)              /* I - Option string or NULL */
+static void
+usage(void)
 {
-  if (option)
-    fprintf(stderr, "ipptest: Unknown option \"%s\"!\n", option);
-
   fputs("Usage: ipptest [options] URL testfile [ ... testfileN ]\n", stderr);
   fputs("Options:\n", stderr);
   fputs("\n", stderr);
-  fputs("-i N    Repeat the last test file once every N seconds.\n", stderr);
-  fputs("-v      Show all attributes in response, even on success.\n", stderr);
+  fputs("-c             Send requests using chunking.\n", stderr);
+  fputs("-d name=value  Define variable.\n", stderr);
+  fputs("-i seconds     Repeat the last test file with the given interval.\n",
+        stderr);
+  fputs("-v             Show all attributes in response, even on success.\n",
+        stderr);
 
   exit(1);
 }