]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/printers.c
Merge changes from CUPS 1.5svn-r9022.
[thirdparty/cups.git] / scheduler / printers.c
index c6465aba955ac54f4b276bd72453974fdde1b54f..3a02ab6294b3c2d9773508db22a7d458afd455e4 100644 (file)
@@ -3,7 +3,7 @@
  *
  *   Printer routines for the Common UNIX Printing System (CUPS).
  *
- *   Copyright 2007-2009 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
@@ -118,8 +118,9 @@ cupsdAddPrinter(const char *name)   /* I - Name of printer */
   cupsdSetString(&p->info, name);
   cupsdSetString(&p->hostname, ServerName);
 
-  cupsdSetStringf(&p->uri, "ipp://%s:%d/printers/%s", ServerName, LocalPort, name);
-  cupsdSetDeviceURI(p, "file:/dev/null");
+  cupsdSetStringf(&p->uri, "ipp://%s:%d/printers/%s", ServerName, RemotePort,
+                  name);
+  cupsdSetDeviceURI(p, "file:///dev/null");
 
   p->state      = IPP_PRINTER_STOPPED;
   p->state_time = time(NULL);
@@ -204,15 +205,9 @@ 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,
-                p->state == IPP_PRINTER_STOPPED ? "paused" : "none");
+                 "printer-state-reasons", NULL, "none");
   else
     ippAddStrings(history, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
                   "printer-state-reasons", p->num_reasons, NULL,
@@ -371,13 +366,6 @@ cupsdCreateCommonData(void)
                  "separate-documents-uncollated-copies",
                  "separate-documents-collated-copies"
                };
-  static const char * const errors[] = /* printer-error-policy-supported values */
-               {
-                 "abort-job",
-                 "retry-current-job",
-                 "retry-job",
-                 "stop-printer"
-               };
   static const char * const notify_attrs[] =
                {                       /* notify-attributes-supported values */
                  "printer-state-change-time",
@@ -442,7 +430,7 @@ cupsdCreateCommonData(void)
 
   /* charset-configured */
   ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET | IPP_TAG_COPY,
-               "charset-configured", NULL, DefaultCharset);
+               "charset-configured", NULL, "utf-8");
 
   /* charset-supported */
   ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET | IPP_TAG_COPY,
@@ -462,8 +450,8 @@ cupsdCreateCommonData(void)
   ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_TEXT | IPP_TAG_COPY,
                "cups-version", NULL, CUPS_SVERSION + 6);
 
-  /* generated-natural-language-supported */
-  ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE | IPP_TAG_COPY,
+  /* generated-natural-language-supported (no IPP_TAG_COPY) */
+  ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
                "generated-natural-language-supported", NULL, DefaultLanguage);
 
   /* ipp-versions-supported */
@@ -546,8 +534,8 @@ cupsdCreateCommonData(void)
   ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
                 "multiple-operation-time-out", MultipleOperationTimeout);
 
-  /* natural-language-configured */
-  ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE | IPP_TAG_COPY,
+  /* natural-language-configured (no IPP_TAG_COPY) */
+  ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
                "natural-language-configured", NULL, DefaultLanguage);
 
   /* notify-attributes-supported */
@@ -622,11 +610,6 @@ cupsdCreateCommonData(void)
   ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
                "pdl-override-supported", NULL, "not-attempted");
 
-  /* printer-error-policy-supported */
-  ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY,
-                "printer-error-policy-supported",
-               sizeof(errors) / sizeof(errors[0]), NULL, errors);
-
   /* printer-op-policy-supported */
   attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY,
                        "printer-op-policy-supported", cupsArrayCount(Policies),
@@ -661,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);
+  }
 }
 
 
@@ -669,12 +655,13 @@ cupsdDeleteAllPrinters(void)
  * 'cupsdDeletePrinter()' - Delete a printer from the system.
  */
 
-void
+int                                    /* O - 1 if classes affected, 0 otherwise */
 cupsdDeletePrinter(
     cupsd_printer_t *p,                        /* I - Printer to delete */
     int             update)            /* I - Update printers.conf? */
 {
-  int  i;                              /* Looping var */
+  int  i,                              /* Looping var */
+       changed = 0;                    /* Class changed? */
 #ifdef __sgi
   char filename[1024];                 /* Interface script filename */
 #endif /* __sgi */
@@ -693,7 +680,12 @@ cupsdDeletePrinter(
   * Stop printing on this printer...
   */
 
-  cupsdStopPrinter(p, update);
+  cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, update);
+
+  if (p->job)
+    cupsdSetJobState(p->job, IPP_JOB_PENDING, CUPSD_JOB_FORCE,
+                     update ? "Job stopped due to printer being deleted." :
+                             "Job stopped.");
 
  /*
   * If this printer is the next for browsing, point to the next one...
@@ -780,7 +772,7 @@ cupsdDeletePrinter(
 
   if (!(p->type & CUPS_PRINTER_IMPLICIT))
   {
-    cupsdDeletePrinterFromClasses(p);
+    changed = cupsdDeletePrinterFromClasses(p);
 
    /*
     * Deregister from any browse protocols...
@@ -804,14 +796,14 @@ cupsdDeletePrinter(
     free(p->history);
   }
 
+  delete_printer_filters(p);
+
   for (i = 0; i < p->num_reasons; i ++)
     _cupsStrFree(p->reasons[i]);
 
   ippDelete(p->attrs);
   ippDelete(p->ppd_attrs);
 
-  delete_printer_filters(p);
-
   mimeDeleteType(MimeDatabase, p->filetype);
   mimeDeleteType(MimeDatabase, p->prefiltertype);
 
@@ -848,10 +840,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);
@@ -861,6 +849,8 @@ cupsdDeletePrinter(
   */
 
   cupsArrayRestore(Printers);
+
+  return (changed);
 }
 
 
@@ -927,6 +917,7 @@ cupsdFreePrinterUsers(
 void
 cupsdLoadAllPrinters(void)
 {
+  int                  i;              /* Looping var */
   cups_file_t          *fp;            /* printers.conf file */
   int                  linenum;        /* Current line number */
   char                 line[4096],     /* Line from file */
@@ -1100,10 +1091,20 @@ cupsdLoadAllPrinters(void)
     else if (!strcasecmp(line, "Reason"))
     {
       if (value &&
-          p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
+          strcmp(value, "connecting-to-device") &&
+          strcmp(value, "cups-insecure-filter-warning") &&
+          strcmp(value, "cups-missing-filter-warning"))
       {
-        p->reasons[p->num_reasons] = _cupsStrAlloc(value);
-       p->num_reasons ++;
+        for (i = 0 ; i < p->num_reasons; i ++)
+         if (!strcmp(value, p->reasons[i]))
+           break;
+
+        if (i >= p->num_reasons &&
+           p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
+       {
+         p->reasons[p->num_reasons] = _cupsStrAlloc(value);
+         p->num_reasons ++;
+       }
       }
       else
        cupsdLogMessage(CUPSD_LOG_ERROR,
@@ -1118,7 +1119,20 @@ cupsdLoadAllPrinters(void)
       if (value && !strcasecmp(value, "idle"))
         p->state = IPP_PRINTER_IDLE;
       else if (value && !strcasecmp(value, "stopped"))
+      {
         p->state = IPP_PRINTER_STOPPED;
+
+        for (i = 0 ; i < p->num_reasons; i ++)
+         if (!strcmp("paused", p->reasons[i]))
+           break;
+
+        if (i >= p->num_reasons &&
+           p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
+       {
+         p->reasons[p->num_reasons] = _cupsStrAlloc("paused");
+         p->num_reasons ++;
+       }
+      }
       else
        cupsdLogMessage(CUPSD_LOG_ERROR,
                        "Syntax error on line %d of printers.conf.", linenum);
@@ -1500,6 +1514,7 @@ cupsdSaveAllPrinters(void)
 
   cupsFilePuts(fp, "# Printer configuration file for " CUPS_SVERSION "\n");
   cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp);
+  cupsFilePuts(fp, "# DO NOT EDIT THIS FILE WHEN CUPSD IS RUNNING\n");
 
  /*
   * Write each local printer known to the system...
@@ -1580,7 +1595,9 @@ cupsdSaveAllPrinters(void)
     cupsFilePrintf(fp, "StateTime %d\n", (int)printer->state_time);
 
     for (i = 0; i < printer->num_reasons; i ++)
-      if (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]);
 
     cupsFilePrintf(fp, "Type %d\n", printer->type);
@@ -1998,7 +2015,7 @@ cupsdSetPrinterAttr(
   * Don't allow empty values...
   */
 
-  if (!*value)
+  if (!*value && strcmp(name, "marker-message"))
   {
     cupsdLogMessage(CUPSD_LOG_ERROR, "Ignoring empty \"%s\" attribute", name);
     return;
@@ -2126,21 +2143,15 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
   ipp_attribute_t *attr;               /* Attribute data */
   cups_option_t        *option;                /* Current printer option */
   char         *filter;                /* Current filter */
+  static const char * const air_none[] =
+               {                       /* No authentication */
+                 "none"
+               };
   static const char * const air_userpass[] =
                {                       /* Basic/Digest authentication */
                  "username",
                  "password"
                };
-#ifdef HAVE_GSSAPI
-  static const char * const air_negotiate[] =
-               {                       /* Kerberos authentication */
-                 "negotiate"
-               };
-#endif /* HAVE_GSSAPI */
-  static const char * const air_none[] =
-               {                       /* No authentication */
-                 "none"
-               };
 
 
   DEBUG_printf(("cupsdSetPrinterAttrs: entering name = %s, type = %x\n", p->name,
@@ -2171,65 +2182,50 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
   {
     num_air = p->num_auth_info_required;
     air     = p->auth_info_required;
-
-    if (!strcmp(air[0], "username"))
-      auth_supported = "basic";
-    else
-      auth_supported = "negotiate";
   }
-  else if (!(p->type & CUPS_PRINTER_DISCOVERED))
+  else if ((p->type & CUPS_PRINTER_AUTHENTICATED) &&
+           (p->type & CUPS_PRINTER_DISCOVERED))
   {
-    if (p->type & CUPS_PRINTER_CLASS)
-      snprintf(resource, sizeof(resource), "/classes/%s", p->name);
-    else
-      snprintf(resource, sizeof(resource), "/printers/%s", p->name);
+    num_air = 2;
+    air     = air_userpass;
+  }
 
-    if ((auth = cupsdFindBest(resource, HTTP_POST)) == NULL ||
-        auth->type == CUPSD_AUTH_NONE)
-      auth = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB);
+  if (p->type & CUPS_PRINTER_CLASS)
+    snprintf(resource, sizeof(resource), "/classes/%s", p->name);
+  else
+    snprintf(resource, sizeof(resource), "/printers/%s", p->name);
 
-    if (auth)
-    {
-      int      auth_type;              /* Authentication type */
+  if ((auth = cupsdFindBest(resource, HTTP_POST)) == NULL ||
+      auth->type == CUPSD_AUTH_NONE)
+    auth = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB);
 
+  if (auth)
+  {
+    int        auth_type;              /* Authentication type */
 
-      if ((auth_type = auth->type) == CUPSD_AUTH_DEFAULT)
-        auth_type = DefaultAuthType;
 
-      if (auth_type == CUPSD_AUTH_BASIC || auth_type == CUPSD_AUTH_BASICDIGEST)
-      {
-       auth_supported = "basic";
-       num_air        = 2;
-       air            = air_userpass;
-      }
-      else if (auth_type == CUPSD_AUTH_DIGEST)
-      {
-       auth_supported = "digest";
-       num_air        = 2;
-       air            = air_userpass;
-      }
+    if ((auth_type = auth->type) == CUPSD_AUTH_DEFAULT)
+      auth_type = DefaultAuthType;
+
+    if (auth_type == CUPSD_AUTH_BASIC || auth_type == CUPSD_AUTH_BASICDIGEST)
+      auth_supported = "basic";
+    else if (auth_type == CUPSD_AUTH_DIGEST)
+      auth_supported = "digest";
 #ifdef HAVE_GSSAPI
-      else if (auth_type == CUPSD_AUTH_NEGOTIATE)
-      {
-       auth_supported = "negotiate";
-       num_air        = 1;
-       air            = air_negotiate;
-      }
+    else if (auth_type == CUPSD_AUTH_NEGOTIATE)
+      auth_supported = "negotiate";
 #endif /* HAVE_GSSAPI */
 
+    if (!(p->type & CUPS_PRINTER_DISCOVERED))
+    {
       if (auth_type != CUPSD_AUTH_NONE)
-        p->type |= CUPS_PRINTER_AUTHENTICATED;
+       p->type |= CUPS_PRINTER_AUTHENTICATED;
       else
-        p->type &= ~CUPS_PRINTER_AUTHENTICATED;
+       p->type &= ~CUPS_PRINTER_AUTHENTICATED;
     }
-    else
-      p->type &= ~CUPS_PRINTER_AUTHENTICATED;
-  }
-  else if (p->type & CUPS_PRINTER_AUTHENTICATED)
-  {
-    num_air = 2;
-    air     = air_userpass;
   }
+  else if (!(p->type & CUPS_PRINTER_DISCOVERED))
+    p->type &= ~CUPS_PRINTER_AUTHENTICATED;
 
  /*
   * Create the required IPP attributes for a printer...
@@ -2378,6 +2374,9 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
       * Add filters for printer...
       */
 
+      cupsdSetPrinterReasons(p, "-cups-missing-filter-warning,"
+                                "cups-insecure-filter-warning");
+
       for (filter = (char *)cupsArrayFirst(p->filters);
           filter;
           filter = (char *)cupsArrayNext(p->filters))
@@ -2429,6 +2428,35 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
       }
     }
 
+    if ((oldattr = ippFindAttribute(oldattrs, "marker-message",
+                                    IPP_TAG_TEXT)) != NULL)
+      ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "marker-message",
+                   NULL, oldattr->values[0].string.text);
+
+    if ((oldattr = ippFindAttribute(oldattrs, "marker-low-levels",
+                                    IPP_TAG_INTEGER)) != NULL)
+    {
+      if ((attr = ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                                 "marker-low-levels", oldattr->num_values,
+                                NULL)) != NULL)
+      {
+       for (i = 0; i < oldattr->num_values; i ++)
+         attr->values[i].integer = oldattr->values[i].integer;
+      }
+    }
+
+    if ((oldattr = ippFindAttribute(oldattrs, "marker-high-levels",
+                                    IPP_TAG_INTEGER)) != NULL)
+    {
+      if ((attr = ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                                 "marker-high-levels", oldattr->num_values,
+                                NULL)) != NULL)
+      {
+       for (i = 0; i < oldattr->num_values; i ++)
+         attr->values[i].integer = oldattr->values[i].integer;
+      }
+    }
+
     if ((oldattr = ippFindAttribute(oldattrs, "marker-names",
                                     IPP_TAG_NAME)) != NULL)
     {
@@ -2507,14 +2535,6 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
     if (BrowseLocalOptions)
       length += 12 + strlen(BrowseLocalOptions);
 
-    if (p->num_auth_info_required > 0)
-    {
-      length += 18;                    /* auth-info-required */
-
-      for (i = 0; i < p->num_auth_info_required; i ++)
-        length += strlen(p->auth_info_required[i]) + 1;
-    }
-
    /*
     * Allocate the new string...
     */
@@ -2560,21 +2580,6 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
          }
        }
       }
-
-      if (p->num_auth_info_required > 0)
-      {
-        strcpy(attrptr, "auth-info-required");
-       attrptr += 18;
-
-       for (i = 0; i < p->num_auth_info_required; i ++)
-       {
-         *attrptr++ = i ? ',' : '=';
-         strcpy(attrptr, p->auth_info_required[i]);
-         attrptr += strlen(attrptr);
-       }
-      }
-      else
-       *attrptr = '\0';
     }
   }
 
@@ -2614,35 +2619,20 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
  * 'cupsdSetPrinterReasons()' - Set/update the reasons strings.
  */
 
-void
+int                                    /* O - 1 if something changed, 0 otherwise */
 cupsdSetPrinterReasons(
     cupsd_printer_t  *p,               /* I - Printer */
     const char *s)                     /* I - Reasons strings */
 {
-  int          i;                      /* Looping var */
+  int          i,                      /* Looping var */
+               changed = 0;            /* Did something change? */
   const char   *sptr;                  /* Pointer into reasons */
   char         reason[255],            /* Reason string */
                *rptr;                  /* Pointer into reason */
 
 
-  if (!p || !s)
-  {
-    cupsdLogMessage(CUPSD_LOG_EMERG,
-                    "cupsdSetPrinterReasons called with p=%p and s=%p!", p, s);
-    return;
-  }
-
-  if (LogLevel == CUPSD_LOG_DEBUG2)
-  {
-    cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                   "cupsdSetPrinterReasons(p=%p(%s),s=\"%s\"", p, p->name, s);
-    cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdSetPrinterReasons: num_reasons=%d",
-                    p->num_reasons);
-    for (i = 0; i < p->num_reasons; i ++)
-      cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                      "cupsdSetPrinterReasons: reasons[%d]=%p(\"%s\")", i,
-                     p->reasons[i], p->reasons[i]);
-  }
+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                 "cupsdSetPrinterReasons(p=%p(%s),s=\"%s\"", p, p->name, s);
 
   if (s[0] == '-' || s[0] == '+')
   {
@@ -2664,6 +2654,7 @@ cupsdSetPrinterReasons(
       _cupsStrFree(p->reasons[i]);
 
     p->num_reasons = 0;
+    changed        = 1;
 
     cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
 
@@ -2672,7 +2663,7 @@ cupsdSetPrinterReasons(
   }
 
   if (!strcmp(s, "none"))
-    return;
+    return (changed);
 
  /*
   * Loop through all of the reasons...
@@ -2709,11 +2700,8 @@ cupsdSetPrinterReasons(
          * Found a match, so remove it...
          */
 
-         cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                         "cupsdSetPrinterReasons: Removing \"%s\" at index %d",
-                         reason, i);
-
          p->num_reasons --;
+          changed = 1;
          _cupsStrFree(p->reasons[i]);
 
          if (i < p->num_reasons)
@@ -2724,11 +2712,12 @@ cupsdSetPrinterReasons(
            cupsdSetPrinterState(p, IPP_PRINTER_IDLE, 1);
 
           if (strcmp(reason, "connecting-to-device"))
+         {
            cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
 
-         if (PrintcapFormat == PRINTCAP_PLIST)
-           cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
-
+           if (PrintcapFormat == PRINTCAP_PLIST)
+             cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
+          }
          break;
        }
     }
@@ -2749,38 +2738,28 @@ cupsdSetPrinterReasons(
          cupsdLogMessage(CUPSD_LOG_ALERT,
                          "Too many printer-state-reasons values for %s (%d)",
                          p->name, i + 1);
-          return;
+          return (changed);
         }
 
-       cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                       "cupsdSetPrinterReasons: Adding \"%s\" at index %d",
-                       reason, i);
-
         p->reasons[i] = _cupsStrAlloc(reason);
        p->num_reasons ++;
+        changed = 1;
 
        if (!strcmp(reason, "paused") && p->state != IPP_PRINTER_STOPPED)
          cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, 1);
 
        if (strcmp(reason, "connecting-to-device"))
+       {
          cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
 
-       if (PrintcapFormat == PRINTCAP_PLIST)
-         cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
+         if (PrintcapFormat == PRINTCAP_PLIST)
+           cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
+       }
       }
     }
   }
 
-  if (LogLevel == CUPSD_LOG_DEBUG2)
-  {
-    cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                    "cupsdSetPrinterReasons: NEW num_reasons=%d",
-                    p->num_reasons);
-    for (i = 0; i < p->num_reasons; i ++)
-      cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                      "cupsdSetPrinterReasons: NEW reasons[%d]=%p(\"%s\")", i,
-                     p->reasons[i], p->reasons[i]);
-  }
+  return (changed);
 }
 
 
@@ -2795,6 +2774,12 @@ cupsdSetPrinterState(
     int             update)            /* I - Update printers.conf? */
 {
   ipp_pstate_t old_state;              /* Old printer state */
+  static const char * const printer_states[] =
+  {                                    /* State strings */
+    "idle",
+    "processing",
+    "stopped"
+  };
 
 
  /*
@@ -2818,9 +2803,9 @@ cupsdSetPrinterState(
   {
     cupsdAddEvent(s == IPP_PRINTER_STOPPED ? CUPSD_EVENT_PRINTER_STOPPED :
                       CUPSD_EVENT_PRINTER_STATE, p, NULL,
-                 "%s \"%s\" state changed.",
+                 "%s \"%s\" state changed to %s.",
                  (p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer",
-                 p->name);
+                 p->name, printer_states[p->state]);
 
    /*
     * Let the browse code know this needs to be updated...
@@ -2835,6 +2820,26 @@ cupsdSetPrinterState(
 #endif /* __sgi */
   }
 
+ /*
+  * Set/clear the paused reason as needed...
+  */
+
+  if (s == IPP_PRINTER_STOPPED)
+    cupsdSetPrinterReasons(p, "+paused");
+  else
+    cupsdSetPrinterReasons(p, "-paused");
+
+ /*
+  * Clear the message for the queue when going to processing...
+  */
+
+  if (s == IPP_PRINTER_PROCESSING)
+    p->state_message[0] = '\0';
+
+ /*
+  * Update the printer history...
+  */
+
   cupsdAddPrinterHistory(p);
 
  /*
@@ -2849,8 +2854,8 @@ cupsdSetPrinterState(
   * to stopped (or visa-versa)...
   */
 
-  if ((old_state == IPP_PRINTER_STOPPED) != (s == IPP_PRINTER_STOPPED) &&
-      update)
+  if (update &&
+      (old_state == IPP_PRINTER_STOPPED) != (s == IPP_PRINTER_STOPPED))
   {
     if (p->type & CUPS_PRINTER_CLASS)
       cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
@@ -2868,9 +2873,6 @@ void
 cupsdStopPrinter(cupsd_printer_t *p,   /* I - Printer to stop */
                  int             update)/* I - Update printers.conf? */
 {
-  cupsd_job_t  *job;                   /* Active print job */
-
-
  /*
   * Set the printer state...
   */
@@ -2881,33 +2883,9 @@ cupsdStopPrinter(cupsd_printer_t *p,     /* I - Printer to stop */
   * See if we have a job printing on this printer...
   */
 
-  if (p->job)
-  {
-   /*
-    * Get pointer to job...
-    */
-
-    job = (cupsd_job_t *)p->job;
-
-   /*
-    * Stop it...
-    */
-
-    cupsdStopJob(job, 0);
-
-   /*
-    * Reset the state to pending...
-    */
-
-    job->state->values[0].integer = IPP_JOB_PENDING;
-    job->state_value              = IPP_JOB_PENDING;
-    job->dirty                    = 1;
-
-    cupsdMarkDirty(CUPSD_DIRTY_JOBS);
-
-    cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, p, job,
-                 "Job stopped due to printer being paused");
-  }
+  if (p->job && p->job->state_value == IPP_JOB_PROCESSING)
+    cupsdSetJobState(p->job, IPP_JOB_PENDING, CUPSD_JOB_DEFAULT,
+                     "Job stopped due to printer being paused.");
 }
 
 
@@ -3264,6 +3242,8 @@ cupsdWritePrintcap(void)
   if (!Printcap || !*Printcap)
     return;
 
+  cupsdLogMessage(CUPSD_LOG_INFO, "Generating printcap %s...", Printcap);
+
  /*
   * Open the printcap file...
   */
@@ -3538,7 +3518,9 @@ add_printer_filter(
                program[1024];          /* Program/filter name */
   int          cost;                   /* Cost of filter */
   mime_type_t  *temptype;              /* MIME type looping var */
-  char         filename[1024];         /* Full filter filename */
+  char         filename[1024],         /* Full filter filename */
+               *dirsep;                /* Pointer to directory separator */
+  struct stat  fileinfo;               /* File information */
 
 
  /*
@@ -3567,16 +3549,74 @@ add_printer_filter(
     else
       snprintf(filename, sizeof(filename), "%s/filter/%s", ServerBin, program);
 
-    if (access(filename, X_OK))
+    if (stat(filename, &fileinfo))
     {
+      memset(&fileinfo, 0, sizeof(fileinfo));
+
       snprintf(p->state_message, sizeof(p->state_message),
                "Filter \"%s\" for printer \"%s\" not available: %s",
-              program, p->name, strerror(errno));
-      cupsdSetPrinterReasons(p, "+cups-missing-filter-error");
-      cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, 0);
+              filename, p->name, strerror(errno));
+      cupsdSetPrinterReasons(p, "+cups-missing-filter-warning");
 
       cupsdLogMessage(CUPSD_LOG_ERROR, "%s", p->state_message);
     }
+
+   /*
+    * When running as root, do additional security checks...
+    */
+
+    if (!RunUser)
+    {
+     /*
+      * Only use filters that are owned by root and do not have group or world
+      * write permissions.
+      */
+
+      if (fileinfo.st_uid ||
+          (fileinfo.st_mode & (S_ISUID | S_IWGRP | S_IWOTH)) != 0)
+      {
+       if (fileinfo.st_uid)
+         snprintf(p->state_message, sizeof(p->state_message),
+                  "Filter \"%s\" for printer \"%s\" not owned by root",
+                  filename, p->name);
+       else
+         snprintf(p->state_message, sizeof(p->state_message),
+                  "Filter \"%s\" for printer \"%s\" has insecure permissions "
+                  "(0%o)", filename, p->name, fileinfo.st_mode);
+
+       cupsdSetPrinterReasons(p, "+cups-insecure-filter-warning");
+
+       cupsdLogMessage(CUPSD_LOG_ERROR, "%s", p->state_message);
+      }
+      else if (fileinfo.st_mode)
+      {
+       /*
+       * Similarly, check that the parent directory is also owned by root and
+       * does not have world write permissions.
+       */
+
+       if ((dirsep = strrchr(filename, '/')) != NULL)
+         *dirsep = '\0';
+
+       if (!stat(filename, &fileinfo) &&
+           (fileinfo.st_uid ||
+            (fileinfo.st_mode & (S_ISUID | S_IWGRP | S_IWOTH)) != 0))
+       {
+         if (fileinfo.st_uid)
+           snprintf(p->state_message, sizeof(p->state_message),
+                    "Filter directory \"%s\" for printer \"%s\" not owned by "
+                    "root", filename, p->name);
+         else
+           snprintf(p->state_message, sizeof(p->state_message),
+                    "Filter directory \"%s\" for printer \"%s\" has insecure "
+                    "permissions (0%o)", filename, p->name, fileinfo.st_mode);
+
+         cupsdSetPrinterReasons(p, "+cups-insecure-filter-warning");
+
+         cupsdLogMessage(CUPSD_LOG_ERROR, "%s", p->state_message);
+       }
+      }
+    }
   }
 
  /*
@@ -3662,10 +3702,6 @@ add_printer_formats(cupsd_printer_t *p)  /* I - Printer */
                       p->name, mimetype);
   }
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                  "add_printer_formats: %s: %d supported types",
-                 p->name, cupsArrayCount(p->filetypes) + 1);
-
  /*
   * Add the file formats that can be filtered...
   */
@@ -3676,9 +3712,13 @@ add_printer_formats(cupsd_printer_t *p)  /* I - Printer */
   else
     i = 0;
 
+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                  "add_printer_formats: %s: %d supported types",
+                  p->name, cupsArrayCount(p->filetypes) + i);
+
   attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
                        "document-format-supported",
-                      cupsArrayCount(p->filetypes) + 1, NULL, NULL);
+                       cupsArrayCount(p->filetypes) + i, NULL, NULL);
 
   if (i)
     attr->values[0].string.text = _cupsStrAlloc("application/octet-stream");
@@ -3717,7 +3757,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;
     }
@@ -3797,7 +3837,7 @@ delete_printer_filters(
   for (filter = mimeFirstFilter(MimeDatabase);
        filter;
        filter = mimeNextFilter(MimeDatabase))
-    if (filter->dst == p->filetype)
+    if (filter->dst == p->filetype || filter->dst == p->prefiltertype)
     {
      /*
       * Delete the current filter...
@@ -3805,6 +3845,9 @@ delete_printer_filters(
 
       mimeDeleteFilter(MimeDatabase, filter);
     }
+
+  cupsdSetPrinterReasons(p, "-cups-insecure-filter-warning"
+                            ",cups-missing-filter-warning");
 }
 
 
@@ -3846,9 +3889,14 @@ load_ppd(cupsd_printer_t *p)             /* I - Printer */
   char         custom_in[256],         /* Custom size name in inches */
                custom_mm[256];         /* Custom size name in millimeters */
   ppd_size_t   *size;                  /* Current size */
-  ppd_option_t *output_bin,            /* OutputBin options */
-               *duplex;                /* Duplex options */
+  ppd_option_t *duplex,                /* Duplex option */
+               *output_bin,            /* OutputBin option */
+               *resolution;            /* (Set|JCL|)Resolution option */
+  ppd_choice_t *choice;                /* Current PPD choice */
   ppd_attr_t   *ppd_attr;              /* PPD attribute */
+  int          xdpi,                   /* Horizontal resolution */
+               ydpi;                   /* Vertical resolution */
+  const char   *resptr;                /* Pointer into resolution keyword */
   _cups_pwg_media_t *pwgmedia;         /* Matching PWG size name */
   ipp_attribute_t *attr;               /* Attribute data */
   ipp_t                *media_col_default,     /* media-col-default collection value */
@@ -3976,9 +4024,13 @@ load_ppd(cupsd_printer_t *p)             /* I - Printer */
 
     if (ppd->num_sizes == 0)
     {
-      cupsdLogMessage(CUPSD_LOG_CRIT,
-                     "The PPD file for printer %s contains no media "
-                     "options and is therefore invalid!", p->name);
+      if (!ppdFindAttr(ppd, "APScannerOnly", NULL))
+       cupsdLogMessage(CUPSD_LOG_CRIT,
+                       "The PPD file for printer %s contains no media "
+                       "options and is therefore invalid!", p->name);
+
+      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                  "media-supported", NULL, "unknown");
     }
     else
     {
@@ -4097,8 +4149,104 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
          val->string.text = _cupsStrAlloc(output_bin->choices[i].choice);
       }
 
-      attr = ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-                         "output-bin-default", NULL, output_bin->defchoice);
+      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                  "output-bin-default", NULL, output_bin->defchoice);
+    }
+
+   /*
+    * Printer resolutions...
+    */
+
+    if ((resolution = ppdFindOption(ppd, "Resolution")) == NULL)
+      if ((resolution = ppdFindOption(ppd, "JCLResolution")) == NULL)
+        if ((resolution = ppdFindOption(ppd, "SetResolution")) == NULL)
+         resolution = ppdFindOption(ppd, "CNRes_PGP");
+
+    if (resolution)
+    {
+     /*
+      * Report all supported resolutions...
+      */
+
+      attr = ippAddResolutions(p->ppd_attrs, IPP_TAG_PRINTER,
+                               "printer-resolution-supported",
+                               resolution->num_choices, IPP_RES_PER_INCH,
+                              NULL, NULL);
+
+      for (i = 0, choice = resolution->choices;
+           i < resolution->num_choices;
+          i ++, choice ++)
+      {
+        xdpi = (int)strtol(choice->choice, (char **)&resptr, 10);
+       if (resptr > choice->choice && xdpi > 0)
+       {
+         if (*resptr == 'x')
+           ydpi = (int)strtol(resptr + 1, (char **)&resptr, 10);
+         else
+           ydpi = xdpi;
+        }
+
+       if (xdpi <= 0 || ydpi <= 0)
+       {
+         cupsdLogMessage(CUPSD_LOG_WARN,
+                         "Bad resolution \"%s\" for printer %s.",
+                         choice->choice, p->name);
+         xdpi = ydpi = 72;
+       }
+
+        attr->values[i].resolution.xres  = xdpi;
+        attr->values[i].resolution.yres  = xdpi;
+        attr->values[i].resolution.units = IPP_RES_PER_INCH;
+
+        if (choice->marked)
+         ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
+                          "printer-resolution-default", IPP_RES_PER_INCH,
+                          xdpi, ydpi);
+      }
+    }
+    else if ((ppd_attr = ppdFindAttr(ppd, "DefaultResolution", NULL)) != NULL &&
+             ppd_attr->value)
+    {
+     /*
+      * Just the DefaultResolution to report...
+      */
+
+      xdpi = (int)strtol(ppd_attr->value, (char **)&resptr, 10);
+      if (resptr > ppd_attr->value && xdpi > 0)
+      {
+       if (*resptr == 'x')
+         ydpi = (int)strtol(resptr + 1, (char **)&resptr, 10);
+       else
+         ydpi = xdpi;
+      }
+
+      if (xdpi <= 0 || ydpi <= 0)
+      {
+       cupsdLogMessage(CUPSD_LOG_WARN,
+                       "Bad default resolution \"%s\" for printer %s.",
+                       ppd_attr->value, p->name);
+       xdpi = ydpi = 72;
+      }
+
+      ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
+                      "printer-resolution-default", IPP_RES_PER_INCH,
+                      xdpi, ydpi);
+      ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
+                      "printer-resolution-supported", IPP_RES_PER_INCH,
+                      xdpi, ydpi);
+    }
+    else
+    {
+     /*
+      * No resolutions in PPD - make one up...
+      */
+
+      ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
+                      "printer-resolution-default", IPP_RES_PER_INCH,
+                      72, 72);
+      ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
+                      "printer-resolution-supported", IPP_RES_PER_INCH,
+                      72, 72);
     }
 
    /*
@@ -4153,6 +4301,16 @@ load_ppd(cupsd_printer_t *p)             /* I - Printer */
       else
        p->type |= CUPS_PRINTER_SMALL;
 
+    if ((ppd_attr = ppdFindAttr(ppd, "APICADriver", NULL)) != NULL &&
+        ppd_attr->value && !strcasecmp(ppd_attr->value, "true"))
+    {
+      if ((ppd_attr = ppdFindAttr(ppd, "APScannerOnly", NULL)) != NULL &&
+         ppd_attr->value && !strcasecmp(ppd_attr->value, "true"))
+        p->type |= CUPS_PRINTER_SCANNER;
+      else
+        p->type |= CUPS_PRINTER_MFP;
+    }
+
    /*
     * Add a filter from application/vnd.cups-raw to printer/name to
     * handle "raw" printing by users.