]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/printers.c
Load cups into easysw/current.
[thirdparty/cups.git] / scheduler / printers.c
index 2ec838a3ee7d57c6ff7dd31269ff1b7ec796111d..9a33a22212940d56235a8c0ca380099536a64742 100644 (file)
@@ -1,9 +1,9 @@
 /*
- * "$Id: printers.c 5305 2006-03-18 03:05:12Z mike $"
+ * "$Id: printers.c 6318 2007-03-06 04:36:55Z mike $"
  *
  *   Printer routines for the Common UNIX Printing System (CUPS).
  *
- *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
  *   property of Easy Software Products and are protected by Federal
@@ -62,6 +62,7 @@
  */
 
 #include "cupsd.h"
+#include <cups/dir.h>
 
 
 /*
@@ -69,7 +70,8 @@
  */
 
 static void    add_printer_defaults(cupsd_printer_t *p);
-static void    add_printer_filter(cupsd_printer_t *p, const char *filter);
+static void    add_printer_filter(cupsd_printer_t *p, mime_type_t *type,
+                                  const char *filter);
 static void    add_printer_formats(cupsd_printer_t *p);
 static int     compare_printers(void *first, void *second, void *data);
 static void    delete_printer_filters(cupsd_printer_t *p);
@@ -257,6 +259,11 @@ cupsdCreateCommonData(void)
 {
   int                  i;              /* Looping var */
   ipp_attribute_t      *attr;          /* Attribute data */
+  cups_dir_t           *dir;           /* Notifier directory */
+  cups_dentry_t                *dent;          /* Notifier directory entry */
+  cups_array_t         *notifiers;     /* Notifier array */
+  char                 filename[1024], /* Filename */
+                       *notifier;      /* Current notifier */
   static const int nups[] =            /* number-up-supported values */
                { 1, 2, 4, 6, 9, 16 };
   static const ipp_orient_t orients[4] =/* orientation-requested-supported values */
@@ -406,10 +413,6 @@ cupsdCreateCommonData(void)
   /* copies-supported */
   ippAddRange(CommonData, IPP_TAG_PRINTER, "copies-supported", 1, MaxCopies);
 
-  /* document-format-default */
-  ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
-               "document-format-default", NULL, "application/octet-stream");
-
   /* generated-natural-language-supported */
   ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
                "generated-natural-language-supported", NULL, DefaultLanguage);
@@ -489,10 +492,6 @@ cupsdCreateCommonData(void)
                (int)(sizeof(notify_attrs) / sizeof(notify_attrs[0])),
                NULL, notify_attrs);
 
-  /* notify-lease-duration-default */
-  ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
-               "notify-lease-duration-default", DefaultLeaseDuration);
-
   /* notify-lease-duration-supported */
   ippAddRange(CommonData, IPP_TAG_PRINTER,
               "notify-lease-duration-supported", 0,
@@ -502,11 +501,7 @@ cupsdCreateCommonData(void)
   ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
                "notify-max-events-supported", MaxEvents);
 
-  /* notify-notify-events-default */
-  ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-               "notify-events-default", NULL, "job-completed");
-
-  /* notify-notify-events-supported */
+  /* notify-events-supported */
   ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
                 "notify-events-supported",
                (int)(sizeof(notify_events) / sizeof(notify_events[0])),
@@ -516,10 +511,32 @@ cupsdCreateCommonData(void)
   ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
                "notify-pull-method-supported", NULL, "ippget");
 
-  /* TODO: scan notifier directory */
   /* notify-schemes-supported */
-  ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-               "notify-schemes-supported", NULL, "mailto");
+  snprintf(filename, sizeof(filename), "%s/notifier", ServerBin);
+  if ((dir = cupsDirOpen(filename)) != NULL)
+  {
+    notifiers = cupsArrayNew((cups_array_func_t)strcmp, NULL);
+
+    while ((dent = cupsDirRead(dir)) != NULL)
+      if (S_ISREG(dent->fileinfo.st_mode) &&
+          (dent->fileinfo.st_mode & S_IXOTH) != 0)
+        cupsArrayAdd(notifiers, _cupsStrAlloc(dent->filename));
+
+    if (cupsArrayCount(notifiers) > 0)
+    {
+      attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                          "notify-schemes-supported",
+                          cupsArrayCount(notifiers), NULL, NULL);
+
+      for (i = 0, notifier = (char *)cupsArrayFirst(notifiers);
+           notifier;
+          i ++, notifier = (char *)cupsArrayNext(notifiers))
+       attr->values[i].string.text = notifier;
+    }
+
+    cupsArrayDelete(notifiers);
+    cupsDirClose(dir);
+  }
 
   /* number-up-supported */
   ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
@@ -618,6 +635,9 @@ cupsdDeletePrinter(
 
   cupsArrayRemove(Printers, p);
 
+  if (p->type & CUPS_PRINTER_IMPLICIT)
+    cupsArrayRemove(ImplicitPrinters, p);
+
  /*
   * Remove the dummy interface/icon/option files under IRIX...
   */
@@ -665,20 +685,25 @@ cupsdDeletePrinter(
           dp = (cupsd_printer_t *)cupsArrayNext(Printers))
        if (dp != p && (dp->type & CUPS_PRINTER_DEFAULT))
        {
-         DefaultPrinter = p;
+         DefaultPrinter = dp;
          break;
        }
     }
   }
 
  /*
-  * Remove this printer from any classes and send a browse delete message...
+  * Remove this printer from any classes...
   */
 
   if (!(p->type & CUPS_PRINTER_IMPLICIT))
   {
     cupsdDeletePrinterFromClasses(p);
-    cupsdSendBrowseDelete(p);
+
+   /*
+    * Deregister from any browse protocols...
+    */
+
+    cupsdDeregisterPrinter(p, 1);
   }
 
  /*
@@ -704,6 +729,7 @@ cupsdDeletePrinter(
   delete_printer_filters(p);
 
   mimeDeleteType(MimeDatabase, p->filetype);
+  mimeDeleteType(MimeDatabase, p->prefiltertype);
 
   cupsdFreePrinterUsers(p);
   cupsdFreeQuotas(p);
@@ -721,6 +747,13 @@ cupsdDeletePrinter(
   cupsdClearString(&p->op_policy);
   cupsdClearString(&p->error_policy);
 
+#ifdef HAVE_DNSSD
+  cupsdClearString(&p->product);
+  cupsdClearString(&p->pdl);
+#endif /* HAVE_DNSSD */
+
+  cupsArrayDelete(p->filetypes);
+
   if (p->browse_attrs)
     free(p->browse_attrs);
 
@@ -921,6 +954,13 @@ cupsdLoadAllPrinters(void)
                       "Syntax error on line %d of printers.conf.", linenum);
       return;
     }
+    else if (!strcasecmp(line, "AuthInfoRequired"))
+    {
+      if (!cupsdSetAuthInfoRequired(p, value, NULL))
+       cupsdLogMessage(CUPSD_LOG_ERROR,
+                       "Bad AuthInfoRequired on line %d of printers.conf.",
+                       linenum);
+    }
     else if (!strcasecmp(line, "Info"))
     {
       if (value)
@@ -1214,11 +1254,14 @@ cupsdRenamePrinter(
   mimeDeleteType(MimeDatabase, p->filetype);
   p->filetype = mimeAddType(MimeDatabase, "printer", name);
 
+  mimeDeleteType(MimeDatabase, p->prefiltertype);
+  p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", name);
+
  /*
   * Rename the printer...
   */
 
-  cupsdSetStringf(&p->name, name);
+  cupsdSetString(&p->name, name);
 
  /*
   * Reset printer attributes...
@@ -1231,6 +1274,7 @@ cupsdRenamePrinter(
   */
 
   cupsArrayAdd(Printers, p);
+
   if (p->type & CUPS_PRINTER_IMPLICIT)
     cupsArrayAdd(ImplicitPrinters, p);
 }
@@ -1252,6 +1296,7 @@ cupsdSaveAllPrinters(void)
   time_t               curtime;        /* Current time */
   struct tm            *curdate;       /* Current date */
   cups_option_t                *option;        /* Current option */
+  const char           *ptr;           /* Pointer into info/location */
 
 
  /*
@@ -1325,12 +1370,49 @@ cupsdSaveAllPrinters(void)
     else
       cupsFilePrintf(fp, "<Printer %s>\n", printer->name);
 
+    if (printer->num_auth_info_required > 0)
+    {
+      cupsFilePrintf(fp, "AuthInfoRequired %s", printer->auth_info_required[0]);
+      for (i = 1; i < printer->num_auth_info_required; i ++)
+        cupsFilePrintf(fp, ",%s", printer->auth_info_required[i]);
+      cupsFilePutChar(fp, '\n');
+    }
+
     if (printer->info)
-      cupsFilePrintf(fp, "Info %s\n", printer->info);
+    {
+      if ((ptr = strchr(printer->info, '#')) != NULL)
+      {
+       /*
+        * Need to quote the first # in the info string...
+       */
+
+        cupsFilePuts(fp, "Info ");
+       cupsFileWrite(fp, printer->info, ptr - printer->info);
+       cupsFilePutChar(fp, '\\');
+       cupsFilePuts(fp, ptr);
+       cupsFilePutChar(fp, '\n');
+      }
+      else
+        cupsFilePrintf(fp, "Info %s\n", printer->info);
+    }
 
     if (printer->location)
-      cupsFilePrintf(fp, "Location %s\n", printer->location);
+    {
+      if ((ptr = strchr(printer->info, '#')) != NULL)
+      {
+       /*
+        * Need to quote the first # in the location string...
+       */
 
+        cupsFilePuts(fp, "Location ");
+       cupsFileWrite(fp, printer->location, ptr - printer->location);
+       cupsFilePutChar(fp, '\\');
+       cupsFilePuts(fp, ptr);
+       cupsFilePutChar(fp, '\n');
+      }
+      else
+        cupsFilePrintf(fp, "Location %s\n", printer->location);
+    }
     if (printer->device_uri)
       cupsFilePrintf(fp, "DeviceURI %s\n", printer->device_uri);
 
@@ -1393,6 +1475,119 @@ cupsdSaveAllPrinters(void)
 }
 
 
+/*
+ * 'cupsdSetAuthInfoRequired()' - Set the required authentication info.
+ */
+
+int                                    /* O - 1 if value OK, 0 otherwise */
+cupsdSetAuthInfoRequired(
+    cupsd_printer_t *p,                        /* I - Printer */
+    const char      *values,           /* I - Plain text value (or NULL) */
+    ipp_attribute_t *attr)             /* I - IPP attribute value (or NULL) */
+{
+  int  i;                              /* Looping var */
+
+
+  p->num_auth_info_required = 0;
+
+ /*
+  * Do we have a plain text value?
+  */
+
+  if (values)
+  {
+   /*
+    * Yes, grab the keywords...
+    */
+
+    const char *end;                   /* End of current value */
+
+
+    while (*values && p->num_auth_info_required < 4)
+    {
+      if ((end = strchr(values, ',')) == NULL)
+        end = values + strlen(values);
+
+      if (!strncmp(values, "none", end - values))
+      {
+        if (p->num_auth_info_required != 0 || *end)
+         return (0);
+
+        p->auth_info_required[p->num_auth_info_required] = "none";
+       p->num_auth_info_required ++;
+
+       return (1);
+      }
+      else if (!strncmp(values, "domain", end - values))
+      {
+        p->auth_info_required[p->num_auth_info_required] = "domain";
+       p->num_auth_info_required ++;
+      }
+      else if (!strncmp(values, "password", end - values))
+      {
+        p->auth_info_required[p->num_auth_info_required] = "password";
+       p->num_auth_info_required ++;
+      }
+      else if (!strncmp(values, "username", end - values))
+      {
+        p->auth_info_required[p->num_auth_info_required] = "username";
+       p->num_auth_info_required ++;
+      }
+      else
+        return (0);
+    }
+
+    if (p->num_auth_info_required == 0)
+    {
+      p->auth_info_required[0]  = "none";
+      p->num_auth_info_required = 1;
+    }
+
+    return (1);
+  }
+
+ /*
+  * Grab values from an attribute instead...
+  */
+
+  if (!attr || attr->num_values > 4)
+    return (0);
+
+  for (i = 0; i < attr->num_values; i ++)
+  {
+    if (!strcmp(attr->values[i].string.text, "none"))
+    {
+      if (p->num_auth_info_required != 0 || attr->num_values != 1)
+       return (0);
+
+      p->auth_info_required[p->num_auth_info_required] = "none";
+      p->num_auth_info_required ++;
+
+      return (1);
+    }
+    else if (!strcmp(attr->values[i].string.text, "domain"))
+    {
+      p->auth_info_required[p->num_auth_info_required] = "domain";
+      p->num_auth_info_required ++;
+    }
+    else if (!strcmp(attr->values[i].string.text, "password"))
+    {
+      p->auth_info_required[p->num_auth_info_required] = "password";
+      p->num_auth_info_required ++;
+    }
+    else if (!strcmp(attr->values[i].string.text, "username"))
+    {
+      p->auth_info_required[p->num_auth_info_required] = "username";
+      p->num_auth_info_required ++;
+    }
+    else
+      return (0);
+  }
+
+  return (1);
+}
+
+
 /*
  * 'cupsdSetPrinterAttrs()' - Set printer attributes based upon the PPD file.
  */
@@ -1458,7 +1653,8 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
     else
       snprintf(resource, sizeof(resource), "/printers/%s", p->name);
 
-    if ((auth = cupsdFindBest(resource, HTTP_POST)) == NULL)
+    if ((auth = cupsdFindBest(resource, HTTP_POST)) == NULL ||
+        auth->type == AUTH_NONE)
       auth = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB);
 
     if (auth)
@@ -1517,6 +1713,13 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
                 "job-k-limit", p->k_limit);
   ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
                 "job-page-limit", p->page_limit);
+  if (p->num_auth_info_required)
+    ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                 "auth-info-required", p->num_auth_info_required,
+                 NULL, p->auth_info_required);
+  else
+    ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                "auth-info-required", NULL, "none");
 
   if (cupsArrayCount(Banners) > 0 && !(p->type & CUPS_PRINTER_REMOTE))
   {
@@ -1538,7 +1741,8 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
 
   printer_type = p->type;
 
-  p->raw = 0;
+  p->raw    = 0;
+  p->remote = 0;
 
   if (p->type & CUPS_PRINTER_REMOTE)
   {
@@ -1556,7 +1760,8 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
     ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
                 p->uri);
 
-    p->raw = 1;
+    p->raw    = 1;
+    p->remote = 1;
   }
   else
   {
@@ -1843,7 +2048,20 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
        * handle "raw" printing by users.
        */
 
-        add_printer_filter(p, "application/vnd.cups-raw 0 -");
+        add_printer_filter(p, p->filetype, "application/vnd.cups-raw 0 -");
+
+       /*
+       * Add any pre-filters in the PPD file...
+       */
+
+       if ((ppdattr = ppdFindAttr(ppd, "cupsPreFilter", NULL)) != NULL)
+       {
+         p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", p->name);
+
+         for (; ppdattr; ppdattr = ppdFindNextAttr(ppd, "cupsPreFilter", NULL))
+           if (ppdattr->value)
+             add_printer_filter(p, p->prefiltertype, ppdattr->value);
+       }
 
        /*
        * Add any filters in the PPD file...
@@ -1853,7 +2071,7 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
        for (i = 0; i < ppd->num_filters; i ++)
        {
           DEBUG_printf(("ppd->filters[%d] = \"%s\"\n", i, ppd->filters[i]));
-          add_printer_filter(p, ppd->filters[i]);
+          add_printer_filter(p, p->filetype, ppd->filters[i]);
        }
 
        if (ppd->num_filters == 0)
@@ -1862,7 +2080,8 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
          * If there are no filters, add a PostScript printing filter.
          */
 
-          add_printer_filter(p, "application/vnd.cups-postscript 0 -");
+          add_printer_filter(p, p->filetype,
+                            "application/vnd.cups-postscript 0 -");
         }
 
        /*
@@ -1903,6 +2122,10 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
            attr->values[i].string.text = _cupsStrAlloc("bcp");
        }
 
+#ifdef HAVE_DNSSD
+       cupsdSetString(&p->product, ppd->product);
+#endif /* HAVE_DNSSD */
+
        /*
         * Close the PPD and set the type...
        */
@@ -1937,13 +2160,14 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
        * handle "raw" printing by users.
        */
 
-        add_printer_filter(p, "application/vnd.cups-raw 0 -");
+        add_printer_filter(p, p->filetype, "application/vnd.cups-raw 0 -");
 
        /*
         * Add a PostScript filter, since this is still possibly PS printer.
        */
 
-       add_printer_filter(p, "application/vnd.cups-postscript 0 -");
+       add_printer_filter(p, p->filetype,
+                          "application/vnd.cups-postscript 0 -");
       }
       else
       {
@@ -1960,11 +2184,12 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
          */
 
          ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
-                       "printer-make-and-model", NULL, "Local System V Printer");
+                       "printer-make-and-model", NULL,
+                      "Local System V Printer");
 
          snprintf(filename, sizeof(filename), "*/* 0 %s/interfaces/%s",
                   ServerRoot, p->name);
-         add_printer_filter(p, filename);
+         add_printer_filter(p, p->filetype, filename);
        }
        else if (p->device_uri &&
                 !strncmp(p->device_uri, "ipp://", 6) &&
@@ -1996,7 +2221,8 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
          * Print all files directly...
          */
 
-         p->raw = 1;
+         p->raw    = 1;
+         p->remote = 1;
        }
        else
        {
@@ -2060,12 +2286,12 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
     length += 13 + strlen(p->job_sheets[0]) + strlen(p->job_sheets[1]);
     length += 32;
     if (BrowseLocalOptions)
-      length += 12 + strlen(BrowseLocalOptions); 
+      length += 12 + strlen(BrowseLocalOptions);
 
    /*
     * Allocate the new string...
     */
+
     if ((p->browse_attrs = calloc(1, length)) == NULL)
       cupsdLogMessage(CUPSD_LOG_ERROR,
                       "Unable to allocate %d bytes for browse data!",
@@ -2135,6 +2361,12 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
   write_irix_config(p);
   write_irix_state(p);
 #endif /* __sgi */
+
+ /*
+  * Let the browse protocols reflect the change
+  */
+
+  cupsdRegisterPrinter(p);
 }
 
 
@@ -2269,6 +2501,11 @@ cupsdSetPrinterState(
 
   if (old_state != s)
   {
+    cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE_CHANGED, p, NULL,
+                 "%s \"%s\" state changed.",
+                 (p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer",
+                 p->name);
+
    /*
     * Let the browse code know this needs to be updated...
     */
@@ -2284,6 +2521,12 @@ cupsdSetPrinterState(
 
   cupsdAddPrinterHistory(p);
 
+ /*
+  * Let the browse protocols reflect the change...
+  */
+
+  cupsdRegisterPrinter(p);
+
  /*
   * Save the printer configuration if a printer goes from idle or processing
   * to stopped (or visa-versa)...
@@ -2343,6 +2586,9 @@ cupsdStopPrinter(cupsd_printer_t *p,      /* I - Printer to stop */
     job->state_value              = IPP_JOB_PENDING;
 
     cupsdSaveJob(job);
+
+    cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, p, job,
+                 "Job stopped due to printer being paused");
   }
 }
 
@@ -2368,6 +2614,10 @@ cupsdUpdatePrinters(void)
        p;
        p = (cupsd_printer_t *)cupsArrayNext(Printers))
   {
+   /*
+    * Remove remote printers if we are no longer browsing...
+    */
+
     if (!Browsing && (p->type & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_REMOTE)))
     {
       if (p->type & CUPS_PRINTER_IMPLICIT)
@@ -2378,8 +2628,6 @@ cupsdUpdatePrinters(void)
       cupsArrayRestore(Printers);
       continue;
     }
-    else if (!(p->type & CUPS_PRINTER_REMOTE))
-      cupsdSetPrinterAttrs(p);
 
    /*
     * Update the operation policy pointer...
@@ -2387,6 +2635,13 @@ cupsdUpdatePrinters(void)
 
     if ((p->op_policy_ptr = cupsdFindPolicy(p->op_policy)) == NULL)
       p->op_policy_ptr = DefaultPolicyPtr;
+
+   /*
+    * Update printer attributes as needed...
+    */
+
+    if (!(p->type & CUPS_PRINTER_REMOTE))
+      cupsdSetPrinterAttrs(p);
   }
 }
 
@@ -2397,18 +2652,25 @@ cupsdUpdatePrinters(void)
 
 const char *                           /* O - Printer or class name */
 cupsdValidateDest(
-    const char      *hostname,         /* I - Host name */
-    const char      *resource,         /* I - Resource name */
+    const char      *uri,              /* I - Printer URI */
     cups_ptype_t    *dtype,            /* O - Type (printer or class) */
     cupsd_printer_t **printer)         /* O - Printer pointer */
 {
   cupsd_printer_t      *p;             /* Current printer */
   char                 localname[1024],/* Localized hostname */
                        *lptr,          /* Pointer into localized hostname */
-                       *sptr;          /* Pointer into server name */
-
-
-  DEBUG_printf(("cupsdValidateDest(\"%s\", \"%s\", %p, %p)\n", hostname, resource,
+                       *sptr,          /* Pointer into server name */
+                       *rptr,          /* Pointer into resource */
+                       scheme[32],     /* Scheme portion of URI */
+                       username[64],   /* Username portion of URI */
+                       hostname[HTTP_MAX_HOST],
+                                       /* Host portion of URI */
+                       resource[HTTP_MAX_URI];
+                                       /* Resource portion of URI */
+  int                  port;           /* Port portion of URI */
+
+
+  DEBUG_printf(("cupsdValidateDest(uri=\"%s\", dtype=%p, printer=%p)\n", uri,
                 dtype, printer));
 
  /*
@@ -2418,7 +2680,16 @@ cupsdValidateDest(
   if (printer)
     *printer = NULL;
 
-  *dtype = (cups_ptype_t)0;
+  if (dtype)
+    *dtype = (cups_ptype_t)0;
+
+ /*
+  * Pull the hostname and resource from the URI...
+  */
+
+  httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
+                  username, sizeof(username), hostname, sizeof(hostname),
+                 &port, resource, sizeof(resource));
 
  /*
   * See if the resource is a class or printer...
@@ -2430,7 +2701,7 @@ cupsdValidateDest(
     * Class...
     */
 
-    resource += 9;
+    rptr = resource + 9;
   }
   else if (!strncmp(resource, "/printers/", 10))
   {
@@ -2438,7 +2709,7 @@ cupsdValidateDest(
     * Printer...
     */
 
-    resource += 10;
+    rptr = resource + 10;
   }
   else
   {
@@ -2453,17 +2724,19 @@ cupsdValidateDest(
   * See if the printer or class name exists...
   */
 
-  p = cupsdFindDest(resource);
+  p = cupsdFindDest(rptr);
 
-  if (p == NULL && strchr(resource, '@') == NULL)
+  if (p == NULL && strchr(rptr, '@') == NULL)
     return (NULL);
   else if (p != NULL)
   {
     if (printer)
       *printer = p;
 
-    *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT |
-                        CUPS_PRINTER_REMOTE);
+    if (dtype)
+      *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT |
+                          CUPS_PRINTER_REMOTE);
+
     return (p->name);
   }
 
@@ -2472,7 +2745,7 @@ cupsdValidateDest(
   */
 
   if (!strcasecmp(hostname, "localhost"))
-    hostname = ServerName;
+    strlcpy(hostname, ServerName, sizeof(hostname));
 
   strlcpy(localname, hostname, sizeof(localname));
 
@@ -2514,13 +2787,15 @@ cupsdValidateDest(
        p;
        p = (cupsd_printer_t *)cupsArrayNext(Printers))
     if (!strcasecmp(p->hostname, localname) &&
-        !strcasecmp(p->name, resource))
+        !strcasecmp(p->name, rptr))
     {
       if (printer)
         *printer = p;
 
-      *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT |
-                          CUPS_PRINTER_REMOTE);
+      if (dtype)
+       *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT |
+                            CUPS_PRINTER_REMOTE);
+
       return (p->name);
     }
 
@@ -2737,6 +3012,27 @@ add_printer_defaults(cupsd_printer_t *p)/* I - Printer */
   char         name[256];              /* name-default */
 
 
+ /*
+  * Maintain a common array of default attribute names...
+  */
+
+  if (!CommonDefaults)
+  {
+    CommonDefaults = cupsArrayNew((cups_array_func_t)strcmp, NULL);
+
+    cupsArrayAdd(CommonDefaults, _cupsStrAlloc("copies-default"));
+    cupsArrayAdd(CommonDefaults, _cupsStrAlloc("document-format-default"));
+    cupsArrayAdd(CommonDefaults, _cupsStrAlloc("finishings-default"));
+    cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-hold-until-default"));
+    cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-priority-default"));
+    cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-sheets-default"));
+    cupsArrayAdd(CommonDefaults, _cupsStrAlloc("media-default"));
+    cupsArrayAdd(CommonDefaults, _cupsStrAlloc("number-up-default"));
+    cupsArrayAdd(CommonDefaults,
+                 _cupsStrAlloc("orientation-requested-default"));
+    cupsArrayAdd(CommonDefaults, _cupsStrAlloc("sides-default"));
+  }
+
  /*
   * Add all of the default options from the .conf files...
   */
@@ -2751,6 +3047,9 @@ add_printer_defaults(cupsd_printer_t *p)/* I - Printer */
     {
       snprintf(name, sizeof(name), "%s-default", option->name);
       num_options = cupsAddOption(name, option->value, num_options, &options);
+
+      if (!cupsArrayFind(CommonDefaults, name))
+        cupsArrayAdd(CommonDefaults, _cupsStrAlloc(name));
     }
   }
 
@@ -2769,6 +3068,10 @@ add_printer_defaults(cupsd_printer_t *p)/* I - Printer */
     ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "copies-default",
                   1);
 
+  if (!cupsGetOption("document-format", p->num_options, p->options))
+    ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
+                "document-format-default", NULL, "application/octet-stream");
+
   if (!cupsGetOption("job-hold-until", p->num_options, p->options))
     ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
                  "job-hold-until-default", NULL, "no-hold");
@@ -2784,6 +3087,14 @@ add_printer_defaults(cupsd_printer_t *p)/* I - Printer */
   if (!cupsGetOption("orientation-requested", p->num_options, p->options))
     ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
                   "orientation-requested-default", IPP_PORTRAIT);
+
+  if (!cupsGetOption("notify-lease-duration", p->num_options, p->options))
+    ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                 "notify-lease-duration-default", DefaultLeaseDuration);
+
+  if (!cupsGetOption("notify-events", p->num_options, p->options))
+    ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                "notify-events-default", NULL, "job-completed");
 }
 
 
@@ -2794,6 +3105,7 @@ add_printer_defaults(cupsd_printer_t *p)/* I - Printer */
 static void
 add_printer_filter(
     cupsd_printer_t  *p,               /* I - Printer to add to */
+    mime_type_t             *filtertype,       /* I - Filter or prefilter MIME type */
     const char       *filter)          /* I - Filter to add */
 {
   char         super[MIME_MAX_SUPER],  /* Super-type for filter */
@@ -2834,9 +3146,8 @@ add_printer_filter(
       snprintf(p->state_message, sizeof(p->state_message),
                "Filter \"%s\" for printer \"%s\" not available: %s",
               program, p->name, strerror(errno));
-      cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, 0);
       cupsdSetPrinterReasons(p, "+cups-missing-filter-error");
-      cupsdAddPrinterHistory(p);
+      cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, 0);
 
       cupsdLogMessage(CUPSD_LOG_ERROR, "%s", p->state_message);
     }
@@ -2865,9 +3176,9 @@ add_printer_filter(
       cupsdLogMessage(CUPSD_LOG_DEBUG2,
                       "add_printer_filter: %s: adding filter %s/%s %s/%s %d %s",
                       p->name, temptype->super, temptype->type,
-                     p->filetype->super, p->filetype->type,
+                     filtertype->super, filtertype->type,
                       cost, program);
-      mimeAddFilter(MimeDatabase, temptype, p->filetype, cost, program);
+      mimeAddFilter(MimeDatabase, temptype, filtertype, cost, program);
     }
 }
 
@@ -2882,8 +3193,7 @@ add_printer_formats(cupsd_printer_t *p)   /* I - Printer */
   int          i;                      /* Looping var */
   mime_type_t  *type;                  /* Current MIME type */
   cups_array_t *filters;               /* Filters */
-  int          num_types;              /* Number of supported types */
-  const char   **types;                /* Array of supported type names */
+  ipp_attribute_t *attr;               /* document-format-supported attribute */
   char         mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2];
                                        /* MIME type name */
 
@@ -2893,6 +3203,9 @@ add_printer_formats(cupsd_printer_t *p)   /* I - Printer */
   * types...
   */
 
+  cupsArrayDelete(p->filetypes);
+  p->filetypes = NULL;
+
   if (p->raw)
   {
     ippAddStrings(p->attrs, IPP_TAG_PRINTER,
@@ -2906,27 +3219,15 @@ add_printer_formats(cupsd_printer_t *p) /* I - Printer */
   * are filters for them...
   */
 
-  if ((types = calloc(NumMimeTypes, sizeof(char *))) == NULL)
-  {
-    cupsdLogMessage(CUPSD_LOG_EMERG,
-                    "Unable to allocate memory for \"%s\" MIME type list!",
-                   p->name);
-    return;
-  }
-
   cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_printer_formats: %d types, %d filters",
                   mimeNumTypes(MimeDatabase), mimeNumFilters(MimeDatabase));
 
-  types[0] = _cupsStrAlloc("application/octet-stream");
+  p->filetypes = cupsArrayNew(NULL, NULL);
 
-  for (num_types = 1, type = mimeFirstType(MimeDatabase);
+  for (type = mimeFirstType(MimeDatabase);
        type;
        type = mimeNextType(MimeDatabase))
   {
-    if (!strcasecmp(type->super, "application") &&
-       !strcasecmp(type->type, "octet-stream"))
-      continue;
-
     snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type);
 
     if ((filters = mimeFilter(MimeDatabase, type, p->filetype, NULL)) != NULL)
@@ -2936,8 +3237,7 @@ add_printer_formats(cupsd_printer_t *p)   /* I - Printer */
                       p->name, mimetype, cupsArrayCount(filters));
 
       cupsArrayDelete(filters);
-      types[num_types] = _cupsStrAlloc(mimetype);
-      num_types ++;
+      cupsArrayAdd(p->filetypes, type);
     }
     else
       cupsdLogMessage(CUPSD_LOG_DEBUG2,
@@ -2947,23 +3247,81 @@ add_printer_formats(cupsd_printer_t *p) /* I - Printer */
 
   cupsdLogMessage(CUPSD_LOG_DEBUG2,
                   "add_printer_formats: %s: %d supported types",
-                 p->name, num_types);
+                 p->name, cupsArrayCount(p->filetypes) + 1);
 
  /*
   * Add the file formats that can be filtered...
   */
 
-  ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
-                "document-format-supported", num_types, NULL, types);
+  if ((type = mimeType(MimeDatabase, "application", "octet-stream")) == NULL ||
+      !cupsArrayFind(p->filetypes, type))
+    i = 1;
+  else
+    i = 0;
+
+  attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
+                       "document-format-supported",
+                      cupsArrayCount(p->filetypes) + 1, NULL, NULL);
+
+  if (i)
+    attr->values[0].string.text = _cupsStrAlloc("application/octet-stream");
+
+  for (type = (mime_type_t *)cupsArrayFirst(p->filetypes);
+       type;
+       i ++, type = (mime_type_t *)cupsArrayNext(p->filetypes))
+  {
+    snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type);
+
+    attr->values[i].string.text = _cupsStrAlloc(mimetype);
+  }
+
+#ifdef HAVE_DNSSD
+  {
+    char               pdl[1024];      /* Buffer to build pdl list */
+    mime_filter_t      *filter;        /* MIME filter looping var */
 
- /*
-  * Free the temporary data...
-  */
 
-  for (i = 0; i < num_types; i ++)
-    _cupsStrFree(types[i]);
+    pdl[0] = '\0';
+
+    if (mimeType(MimeDatabase, "application", "pdf"))
+      strlcat(pdl, "application/pdf,", sizeof(pdl));
+
+    if (mimeType(MimeDatabase, "application", "postscript"))
+      strlcat(pdl, "application/postscript,", sizeof(pdl));
+
+    if (mimeType(MimeDatabase, "application", "vnd.cups-raster"))
+      strlcat(pdl, "application/vnd.cups-raster,", sizeof(pdl));
+
+   /*
+    * Determine if this is a Tioga PrintJobMgr based queue...
+    */
 
-  free(types);
+    for (filter = (mime_filter_t *)cupsArrayFirst(MimeDatabase->filters);
+        filter;
+        filter = (mime_filter_t *)cupsArrayNext(MimeDatabase->filters))
+    {
+      if (filter->dst == p->filetype && filter->filter && 
+         strstr(filter->filter, "PrintJobMgr"))
+       break;
+    }
+
+   /*
+    * We only support raw printing if this is not a Tioga PrintJobMgr based
+    * queue and if application/octet-stream is a known conversion...
+    */
+
+    if (!filter && mimeType(MimeDatabase, "application", "octet-stream"))
+      strlcat(pdl, "application/octet-stream,", sizeof(pdl));
+
+    if (mimeType(MimeDatabase, "image", "png"))
+      strlcat(pdl, "image/png,", sizeof(pdl));
+
+    if (pdl[0])
+      pdl[strlen(pdl) - 1] = '\0';     /* Remove trailing comma */
+
+    cupsdSetString(&p->pdl, pdl);
+  }
+#endif /* HAVE_DNSSD */
 }
 
 
@@ -3029,7 +3387,7 @@ write_irix_config(cupsd_printer_t *p)     /* I - Printer to update */
 {
   char         filename[1024];         /* Interface script filename */
   cups_file_t  *fp;                    /* Interface script file */
-
+  ipp_attribute_t *attr;               /* Attribute data */
 
 
  /*
@@ -3274,5 +3632,5 @@ write_irix_state(cupsd_printer_t *p)      /* I - Printer to update */
 
 
 /*
- * End of "$Id: printers.c 5305 2006-03-18 03:05:12Z mike $".
+ * End of "$Id: printers.c 6318 2007-03-06 04:36:55Z mike $".
  */