]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/printers.c
Mirror 1.1.x changes.
[thirdparty/cups.git] / scheduler / printers.c
index 801ecdb4e59ace1943aea93f73380935c8e124b3..24be5a0fdb197f53e6a2a18a303676da00190227 100644 (file)
@@ -1,9 +1,9 @@
 /*
- * "$Id: printers.c,v 1.60 2000/03/30 05:19:29 mike Exp $"
+ * "$Id: printers.c,v 1.93.2.46 2003/04/03 03:33:41 mike Exp $"
  *
  *   Printer routines for the Common UNIX Printing System (CUPS).
  *
- *   Copyright 1997-2000 by Easy Software Products, all rights reserved.
+ *   Copyright 1997-2003 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
  *
  * Contents:
  *
- *   AddPrinter()        - Add a printer to the system.
- *   DeleteAllPrinters() - Delete all printers from the system.
- *   DeletePrinter()     - Delete a printer from the system.
- *   FindPrinter()       - Find a printer in the list.
- *   LoadAllPrinters()   - Load printers from the printers.conf file.
- *   SaveAllPrinters()   - Save all printer definitions to the printers.conf
- *   SetPrinterAttrs()   - Set printer attributes based upon the PPD file.
- *   SetPrinterState()   - Update the current state of a printer.
- *   SortPrinters()      - Sort the printer list when a printer name is
- *                         changed.
- *   StopPrinter()       - Stop a printer from printing any jobs...
- *   write_printcap()    - Write a pseudo-printcap file for older applications
- *                         that need it...
+ *   AddPrinter()           - Add a printer to the system.
+ *   AddPrinterFilter()     - Add a MIME filter for a printer.
+ *   AddPrinterHistory()    - Add the current printer state to the history.
+ *   AddPrinterUser()       - Add a user to the ACL.
+ *   DeleteAllPrinters()    - Delete all printers from the system.
+ *   DeletePrinter()        - Delete a printer from the system.
+ *   DeletePrinterFilters() - Delete all MIME filters for a printer.
+ *   FindPrinter()          - Find a printer in the list.
+ *   FreePrinterUsers()     - Free allow/deny users.
+ *   LoadAllPrinters()      - Load printers from the printers.conf file.
+ *   SaveAllPrinters()      - Save all printer definitions to the printers.conf
+ *   SetPrinterAttrs()      - Set printer attributes based upon the PPD file.
+ *   SetPrinterReasons()    - Set/update the reasons strings.
+ *   SetPrinterState()      - Update the current state of a printer.
+ *   SortPrinters()         - Sort the printer list when a printer name is
+ *                            changed.
+ *   StopPrinter()          - Stop a printer from printing any jobs...
+ *   ValidateDest()         - Validate a printer/class destination.
+ *   WritePrintcap()        - Write a pseudo-printcap file for older
+ *                            applications that need it...
+ *   write_irix_config()    - Update the config files used by the IRIX
+ *                            desktop tools.
+ *   write_irix_state()     - Update the status files used by IRIX printing
+ *                            desktop tools.
  */
 
 /*
@@ -49,7 +60,9 @@
  * Local functions...
  */
 
-static void    write_printcap(void);
+#ifdef __sgi
+static void    write_irix_state(printer_t *p);
+#endif /* __sgi */
 
 
 /*
@@ -64,12 +77,12 @@ AddPrinter(const char *name)        /* I - Name of printer */
                *prev;          /* Previous printer in list */
 
 
-  DEBUG_printf(("AddPrinter(\"%s\")\n", name));
-
  /*
   * Range check input...
   */
 
+  LogMessage(L_DEBUG2, "AddPrinter(\"%s\")", name ? name : "(null)");
+
   if (name == NULL)
     return (NULL);
 
@@ -77,26 +90,36 @@ AddPrinter(const char *name)        /* I - Name of printer */
   * Create a new printer entity...
   */
 
-  if ((p = calloc(sizeof(printer_t), 1)) == NULL)
+  if ((p = calloc(1, sizeof(printer_t))) == NULL)
+  {
+    LogMessage(L_ERROR, "Unable to allocate memory for printer - %s",
+               strerror(errno));
     return (NULL);
+  }
 
-  strcpy(p->name, name);
-  strcpy(p->hostname, ServerName);
-  sprintf(p->uri, "ipp://%s:%d/printers/%s", ServerName,
-          ntohs(Listeners[0].address.sin_port), name);
+  SetString(&p->name, name);
+  SetString(&p->info, name);
+  SetString(&p->hostname, ServerName);
+
+#ifdef AF_INET6
+  if (Listeners[0].address.addr.sa_family == AF_INET6)
+    SetStringf(&p->uri, "ipp://%s:%d/printers/%s", ServerName,
+               ntohs(Listeners[0].address.ipv6.sin6_port), name);
+  else
+#endif /* AF_INET6 */
+  SetStringf(&p->uri, "ipp://%s:%d/printers/%s", ServerName,
+             ntohs(Listeners[0].address.ipv4.sin_port), name);
+  SetStringf(&p->device_uri, "file:/dev/null");
 
   p->state     = IPP_PRINTER_STOPPED;
   p->accepting = 0;
   p->filetype  = mimeAddType(MimeDatabase, "printer", name);
 
-  strcpy(p->job_sheets[0], "none");
-  strcpy(p->job_sheets[1], "none");
-
- /*
-  * Setup required filters and IPP attributes...
-  */
-
-  SetPrinterAttrs(p);
+  SetString(&p->job_sheets[0], "none");
+  SetString(&p->job_sheets[1], "none");
+  if (MaxPrinterHistory)
+    p->history = calloc(MaxPrinterHistory, sizeof(ipp_t *));
 
  /*
   * Insert the printer in the printer list alphabetically...
@@ -123,7 +146,7 @@ AddPrinter(const char *name)        /* I - Name of printer */
   * Write a new /etc/printcap or /var/spool/lp/pstatus file.
   */
 
-  write_printcap();
+  WritePrintcap();
 
   return (p);
 }
@@ -134,8 +157,8 @@ AddPrinter(const char *name)        /* I - Name of printer */
  */
 
 void
-AddPrinterFilter(printer_t *p,         /* I - Printer to add to */
-                 char      *filter)    /* I - Filter to add */
+AddPrinterFilter(printer_t  *p,                /* I - Printer to add to */
+                 const char *filter)   /* I - Filter to add */
 {
   int          i;                      /* Looping var */
   char         super[MIME_MAX_SUPER],  /* Super-type for filter */
@@ -149,7 +172,7 @@ AddPrinterFilter(printer_t *p,              /* I - Printer to add to */
   * Range check input...
   */
 
-  if (p == NULL || filter == NULL)
+  if (p == NULL || p->filetype == NULL || filter == NULL)
     return;
 
  /*
@@ -172,11 +195,11 @@ AddPrinterFilter(printer_t *p,            /* I - Printer to add to */
   for (temptype = MimeDatabase->types, i = MimeDatabase->num_types;
        i > 0;
        i --, temptype ++)
-    if (((super[0] == '*' && strcmp((*temptype)->super, "printer") != 0) ||
-         strcmp((*temptype)->super, super) == 0) &&
-        (type[0] == '*' || strcmp((*temptype)->type, type) == 0))
+    if (((super[0] == '*' && strcasecmp((*temptype)->super, "printer") != 0) ||
+         strcasecmp((*temptype)->super, super) == 0) &&
+        (type[0] == '*' || strcasecmp((*temptype)->type, type) == 0))
     {
-      LogMessage(L_DEBUG, "Adding filter %s/%s %s/%s %d %s",
+      LogMessage(L_DEBUG2, "Adding filter %s/%s %s/%s %d %s",
                  (*temptype)->super, (*temptype)->type,
                 p->filetype->super, p->filetype->type,
                  cost, program);
@@ -185,6 +208,90 @@ AddPrinterFilter(printer_t *p,             /* I - Printer to add to */
 }
 
 
+/*
+ * 'AddPrinterHistory()' - Add the current printer state to the history.
+ */
+
+void
+AddPrinterHistory(printer_t *p)                /* I - Printer */
+{
+  ipp_t        *history;                       /* History collection */
+
+
+ /*
+  * Stop early if we aren't keeping history data...
+  */
+
+  if (MaxPrinterHistory <= 0)
+    return;
+
+ /*
+  * Retire old history data as needed...
+  */
+
+  if (p->num_history >= MaxPrinterHistory)
+  {
+    p->num_history --;
+    ippDelete(p->history[0]);
+    memmove(p->history, p->history + 1, p->num_history * sizeof(ipp_t *));
+  }
+
+ /*
+  * Create a collection containing the current printer-state, printer-up-time,
+  * printer-state-message, and printer-state-reasons attributes.
+  */
+
+  history = ippNew();
+  ippAddInteger(history, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
+                p->state);
+  ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-state-message",
+               NULL, p->state_message);
+  if (p->num_reasons == 0)
+    ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                 "printer-state-reasons", NULL,
+                p->state == IPP_PRINTER_STOPPED ? "paused" : "none");
+  else
+    ippAddStrings(history, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                  "printer-state-reasons", p->num_reasons, NULL,
+                 (const char * const *)p->reasons);
+  ippAddInteger(history, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state-time",
+                p->state_time);
+
+  p->history[p->num_history] = history;
+  p->num_history ++;
+}
+
+
+/*
+ * 'AddPrinterUser()' - Add a user to the ACL.
+ */
+
+void
+AddPrinterUser(printer_t  *p,          /* I - Printer */
+               const char *username)   /* I - User */
+{
+  const char   **temp;                 /* Temporary array pointer */
+
+
+  if (!p || !username)
+    return;
+
+  if (p->num_users == 0)
+    temp = malloc(sizeof(char **));
+  else
+    temp = realloc(p->users, sizeof(char **) * (p->num_users + 1));
+
+  if (!temp)
+    return;
+
+  p->users = temp;
+  temp     += p->num_users;
+
+  if ((*temp = strdup(username)) != NULL)
+    p->num_users ++;
+}
+
+
 /*
  * 'DeleteAllPrinters()' - Delete all printers from the system.
  */
@@ -203,6 +310,12 @@ DeleteAllPrinters(void)
     if (!(p->type & CUPS_PRINTER_CLASS))
       DeletePrinter(p);
   }
+
+  if (CommonData)
+  {
+    ippDelete(CommonData);
+    CommonData = NULL;
+  }
 }
 
 
@@ -213,6 +326,7 @@ DeleteAllPrinters(void)
 void
 DeletePrinter(printer_t *p)    /* I - Printer to delete */
 {
+  int          i;              /* Looping var */
   printer_t    *current,       /* Current printer in list */
                *prev;          /* Previous printer in list */
 #ifdef __sgi
@@ -229,12 +343,6 @@ DeletePrinter(printer_t *p)        /* I - Printer to delete */
   if (p == NULL)
     return;
 
- /*
-  * Stop printing on this printer...
-  */
-
-  StopPrinter(p);
-
  /*
   * Remove the printer from the list...
   */
@@ -257,42 +365,102 @@ DeletePrinter(printer_t *p)      /* I - Printer to delete */
   else
     prev->next = p->next;
 
-  if (p->printers != NULL)
-    free(p->printers);
+ /*
+  * Stop printing on this printer...
+  */
 
-  ippDelete(p->attrs);
+  StopPrinter(p);
 
-  free(p);
+ /*
+  * Remove the dummy interface/icon/option files under IRIX...
+  */
+
+#ifdef __sgi
+  snprintf(filename, sizeof(filename), "/var/spool/lp/interface/%s", p->name);
+  unlink(filename);
+
+  snprintf(filename, sizeof(filename), "/var/spool/lp/gui_interface/ELF/%s.gui",
+           p->name);
+  unlink(filename);
+
+  snprintf(filename, sizeof(filename), "/var/spool/lp/activeicons/%s", p->name);
+  unlink(filename);
+
+  snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.config", p->name);
+  unlink(filename);
+
+  snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.status", p->name);
+  unlink(filename);
+
+  snprintf(filename, sizeof(filename), "/var/spool/lp/member/%s", p->name);
+  unlink(filename);
+#endif /* __sgi */
 
  /*
   * If p is the default printer, assign the next one...
   */
 
   if (p == DefaultPrinter)
+  {
     DefaultPrinter = Printers;
 
+    WritePrintcap();
+  }
+
  /*
-  * Write a new /etc/printcap file, and delete the dummy interface and GUI
-  * scripts to fool SGI's stupid printing tools.
+  * Remove this printer from any classes...
   */
 
-  write_printcap();
+  if (!(p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)))
+    DeletePrinterFromClasses(p);
 
-#ifdef __sgi
-  sprintf(filename, "/var/spool/lp/interface/%s", p->name);
-  unlink(filename);
+ /*
+  * Free all memory used by the printer...
+  */
 
-  sprintf(filename, "/var/spool/lp/gui_interface/ELF/%s.gui", p->name);
-  unlink(filename);
+  if (p->printers != NULL)
+    free(p->printers);
 
-  sprintf(filename, "/var/spool/lp/activeicons/%s", p->name);
-  unlink(filename);
-#endif /* __sgi */
+  if (MaxPrinterHistory)
+  {
+    for (i = 0; i < p->num_history; i ++)
+      ippDelete(p->history[i]);
+
+    free(p->history);
+  }
+
+  for (i = 0; i < p->num_reasons; i ++)
+    free(p->reasons[i]);
+
+  ippDelete(p->attrs);
+
+  DeletePrinterFilters(p);
+
+  FreePrinterUsers(p);
+  FreeQuotas(p);
+
+  ClearString(&p->uri);
+  ClearString(&p->hostname);
+  ClearString(&p->name);
+  ClearString(&p->location);
+  ClearString(&p->make_model);
+  ClearString(&p->info);
+  ClearString(&p->job_sheets[0]);
+  ClearString(&p->job_sheets[1]);
+  ClearString(&p->device_uri);
+
+  free(p);
+
+ /*
+  * Write a new /etc/printcap file...
+  */
+
+  WritePrintcap();
 }
 
 
 /*
- * 'AddPrinterFilter()' - Add a MIME filter for a printer.
+ * 'DeletePrinterFilters()' - Delete all MIME filters for a printer.
  */
 
 void
@@ -333,6 +501,27 @@ DeletePrinterFilters(printer_t *p) /* I - Printer to remove from */
 }
 
 
+/*
+ * 'FindDest()' - Find a destination in the list.
+ */
+
+printer_t *                    /* O - Destination in list */
+FindDest(const char *name)     /* I - Name of printer or class to find */
+{
+  printer_t    *p;             /* Current destination */
+  int          diff;           /* Difference */
+
+
+  for (p = Printers; p != NULL; p = p->next)
+    if ((diff = strcasecmp(name, p->name)) == 0)/* name == p->name */
+      return (p);
+    else if (diff < 0)                         /* name < p->name */
+      return (NULL);
+
+  return (NULL);
+}
+
+
 /*
  * 'FindPrinter()' - Find a printer in the list.
  */
@@ -341,24 +530,43 @@ printer_t *                       /* O - Printer in list */
 FindPrinter(const char *name)  /* I - Name of printer to find */
 {
   printer_t    *p;             /* Current printer */
+  int          diff;           /* Difference */
 
 
   for (p = Printers; p != NULL; p = p->next)
-    switch (strcasecmp(name, p->name))
-    {
-      case 0 : /* name == p->name */
-          if (!(p->type & CUPS_PRINTER_CLASS))
-           return (p);
-      case 1 : /* name > p->name */
-          break;
-      case -1 : /* name < p->name */
-          return (NULL);
-    }
+    if ((diff = strcasecmp(name, p->name)) == 0 &&
+        !(p->type & CUPS_PRINTER_CLASS))       /* name == p->name */
+      return (p);
+    else if (diff < 0)                         /* name < p->name */
+      return (NULL);
 
   return (NULL);
 }
 
 
+/*
+ * 'FreePrinterUsers()' - Free allow/deny users.
+ */
+
+void
+FreePrinterUsers(printer_t *p) /* I - Printer */
+{
+  int  i;                      /* Looping var */
+
+
+  if (!p || !p->num_users)
+    return;
+
+  for (i = 0; i < p->num_users; i ++)
+    free((void *)p->users[i]);
+
+  free(p->users);
+
+  p->num_users = 0;
+  p->users     = NULL;
+}
+
+
 /*
  * 'LoadAllPrinters()' - Load printers from the printers.conf file.
  */
@@ -366,7 +574,7 @@ FindPrinter(const char *name)       /* I - Name of printer to find */
 void
 LoadAllPrinters(void)
 {
-  FILE         *fp;                    /* printers.conf file */
+  cups_file_t  *fp;                    /* printers.conf file */
   int          linenum;                /* Current line number */
   int          len;                    /* Length of line */
   char         line[1024],             /* Line from file */
@@ -378,12 +586,16 @@ LoadAllPrinters(void)
 
 
  /*
-  * Open the printer.conf file...
+  * Open the printers.conf file...
   */
 
-  sprintf(line, "%s/printers.conf", ServerRoot);
-  if ((fp = fopen(line, "r")) == NULL)
+  snprintf(line, sizeof(line), "%s/printers.conf", ServerRoot);
+  if ((fp = cupsFileOpen(line, "r")) == NULL)
+  {
+    LogMessage(L_ERROR, "LoadAllPrinters: Unable to open %s - %s", line,
+               strerror(errno));
     return;
+  }
 
  /*
   * Read printer configurations until we hit EOF...
@@ -392,7 +604,7 @@ LoadAllPrinters(void)
   linenum = 0;
   p       = NULL;
 
-  while (fgets(line, sizeof(line), fp) != NULL)
+  while (cupsFileGets(fp, line, sizeof(line)) != NULL)
   {
     linenum ++;
 
@@ -404,12 +616,12 @@ LoadAllPrinters(void)
       continue;
 
    /*
-    * Strip trailing newline, if any...
+    * Strip trailing whitespace, if any...
     */
 
     len = strlen(line);
 
-    if (line[len - 1] == '\n')
+    while (len > 0 && isspace(line[len - 1]))
     {
       len --;
       line[len] = '\0';
@@ -421,7 +633,8 @@ LoadAllPrinters(void)
 
     for (value = line; isspace(*value); value ++);
 
-    for (nameptr = name; *value != '\0' && !isspace(*value);)
+    for (nameptr = name; *value != '\0' && !isspace(*value) &&
+                             nameptr < (name + sizeof(name) - 1);)
       *nameptr++ = *value++;
     *nameptr = '\0';
 
@@ -450,6 +663,8 @@ LoadAllPrinters(void)
 
         line[len - 1] = '\0';
 
+        LogMessage(L_DEBUG, "LoadAllPrinters: Loading printer %s...", value);
+
         p = AddPrinter(value);
        p->accepting = 1;
        p->state     = IPP_PRINTER_IDLE;
@@ -473,6 +688,7 @@ LoadAllPrinters(void)
       if (p != NULL)
       {
         SetPrinterAttrs(p);
+       AddPrinterHistory(p);
         p = NULL;
       }
       else
@@ -488,15 +704,12 @@ LoadAllPrinters(void)
                 linenum);
       return;
     }
-    
     else if (strcmp(name, "Info") == 0)
-      strncpy(p->info, value, sizeof(p->info) - 1);
-    else if (strcmp(name, "MoreInfo") == 0)
-      strncpy(p->more_info, value, sizeof(p->more_info) - 1);
+      SetString(&p->info, value);
     else if (strcmp(name, "Location") == 0)
-      strncpy(p->location, value, sizeof(p->location) - 1);
+      SetString(&p->location, value);
     else if (strcmp(name, "DeviceURI") == 0)
-      strncpy(p->device_uri, value, sizeof(p->device_uri) - 1);
+      SetString(&p->device_uri, value);
     else if (strcmp(name, "State") == 0)
     {
      /*
@@ -517,7 +730,7 @@ LoadAllPrinters(void)
       while (isspace(*value))
         value ++;
 
-      strcpy(p->state_message, value);
+      strlcpy(p->state_message, value, sizeof(p->state_message));
     }
     else if (strcmp(name, "Accepting") == 0)
     {
@@ -541,7 +754,7 @@ LoadAllPrinters(void)
       if (*valueptr)
         *valueptr++ = '\0';
 
-      strncpy(p->job_sheets[0], value, sizeof(p->job_sheets[0]) - 1);
+      SetString(&p->job_sheets[0], value);
 
       while (isspace(*valueptr))
         valueptr ++;
@@ -553,9 +766,25 @@ LoadAllPrinters(void)
        if (*valueptr)
           *valueptr++ = '\0';
 
-       strncpy(p->job_sheets[1], value, sizeof(p->job_sheets[1]) - 1);
+       SetString(&p->job_sheets[1], value);
       }
     }
+    else if (strcmp(name, "AllowUser") == 0)
+    {
+      p->deny_users = 0;
+      AddPrinterUser(p, value);
+    }
+    else if (strcmp(name, "DenyUser") == 0)
+    {
+      p->deny_users = 1;
+      AddPrinterUser(p, value);
+    }
+    else if (strcmp(name, "QuotaPeriod") == 0)
+      p->quota_period = atoi(value);
+    else if (strcmp(name, "PageLimit") == 0)
+      p->page_limit = atoi(value);
+    else if (strcmp(name, "KLimit") == 0)
+      p->k_limit = atoi(value);
     else
     {
      /*
@@ -567,7 +796,7 @@ LoadAllPrinters(void)
     }
   }
 
-  fclose(fp);
+  cupsFileClose(fp);
 }
 
 
@@ -579,8 +808,10 @@ LoadAllPrinters(void)
 void
 SaveAllPrinters(void)
 {
-  FILE         *fp;                    /* printers.conf file */
+  int          i;                      /* Looping var */
+  cups_file_t  *fp;                    /* printers.conf file */
   char         temp[1024];             /* Temporary string */
+  char         backup[1024];           /* printers.conf.O file */
   printer_t    *printer;               /* Current printer class */
   time_t       curtime;                /* Current time */
   struct tm    *curdate;               /* Current date */
@@ -590,25 +821,40 @@ SaveAllPrinters(void)
   * Create the printers.conf file...
   */
 
-  sprintf(temp, "%s/printers.conf", ServerRoot);
-  if ((fp = fopen(temp, "w")) == NULL)
+  snprintf(temp, sizeof(temp), "%s/printers.conf", ServerRoot);
+  snprintf(backup, sizeof(backup), "%s/printers.conf.O", ServerRoot);
+
+  if (rename(temp, backup))
+    LogMessage(L_ERROR, "Unable to backup printers.conf - %s", strerror(errno));
+
+  if ((fp = cupsFileOpen(temp, "w")) == NULL)
   {
     LogMessage(L_ERROR, "Unable to save printers.conf - %s", strerror(errno));
+
+    if (rename(backup, temp))
+      LogMessage(L_ERROR, "Unable to restore printers.conf - %s", strerror(errno));
     return;
   }
   else
     LogMessage(L_INFO, "Saving printers.conf...");
 
+ /*
+  * Restrict access to the file...
+  */
+
+  fchown(cupsFileNumber(fp), User, Group);
+  fchmod(cupsFileNumber(fp), ConfigFilePerm);
+
  /*
   * Write a small header to the file...
   */
 
   curtime = time(NULL);
   curdate = gmtime(&curtime);
-  strftime(temp, sizeof(temp) - 1, "# Written by cupsd on %c\n", curdate);
+  strftime(temp, sizeof(temp) - 1, CUPS_STRFTIME_FORMAT, curdate);
 
-  fputs("# Printer configuration file for " CUPS_SVERSION "\n", fp);
-  fputs(temp, fp);
+  cupsFilePuts(fp, "# Printer configuration file for " CUPS_SVERSION "\n");
+  cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp);
 
  /*
   * Write each local printer known to the system...
@@ -621,7 +867,8 @@ SaveAllPrinters(void)
     */
 
     if ((printer->type & CUPS_PRINTER_REMOTE) ||
-        (printer->type & CUPS_PRINTER_CLASS))
+        (printer->type & CUPS_PRINTER_CLASS) ||
+       (printer->type & CUPS_PRINTER_IMPLICIT))
       continue;
 
    /*
@@ -629,36 +876,55 @@ SaveAllPrinters(void)
     */
 
     if (printer == DefaultPrinter)
-      fprintf(fp, "<DefaultPrinter %s>\n", printer->name);
+      cupsFilePrintf(fp, "<DefaultPrinter %s>\n", printer->name);
     else
-      fprintf(fp, "<Printer %s>\n", printer->name);
-
-    if (printer->info[0])
-      fprintf(fp, "Info %s\n", printer->info);
-    if (printer->more_info[0])
-      fprintf(fp, "MoreInfo %s\n", printer->more_info);
-    if (printer->location[0])
-      fprintf(fp, "Location %s\n", printer->location);
-    if (printer->device_uri[0])
-      fprintf(fp, "DeviceURI %s\n", printer->device_uri);
+      cupsFilePrintf(fp, "<Printer %s>\n", printer->name);
+
+    if (printer->info)
+      cupsFilePrintf(fp, "Info %s\n", printer->info);
+
+    if (printer->location)
+      cupsFilePrintf(fp, "Location %s\n", printer->location);
+
+    if (printer->device_uri)
+      cupsFilePrintf(fp, "DeviceURI %s\n", printer->device_uri);
+
     if (printer->state == IPP_PRINTER_STOPPED)
     {
-      fputs("State Stopped\n", fp);
-      fprintf(fp, "StateMessage %s\n", printer->state_message);
+      cupsFilePuts(fp, "State Stopped\n");
+      cupsFilePrintf(fp, "StateMessage %s\n", printer->state_message);
     }
     else
-      fputs("State Idle\n", fp);
+      cupsFilePuts(fp, "State Idle\n");
+
     if (printer->accepting)
-      fputs("Accepting Yes\n", fp);
+      cupsFilePuts(fp, "Accepting Yes\n");
     else
-      fputs("Accepting No\n", fp);
-    fprintf(fp, "JobSheets %s %s\n", printer->job_sheets[0],
+      cupsFilePuts(fp, "Accepting No\n");
+
+    cupsFilePrintf(fp, "JobSheets %s %s\n", printer->job_sheets[0],
             printer->job_sheets[1]);
 
-    fputs("</Printer>\n", fp);
+    cupsFilePrintf(fp, "QuotaPeriod %d\n", printer->quota_period);
+    cupsFilePrintf(fp, "PageLimit %d\n", printer->page_limit);
+    cupsFilePrintf(fp, "KLimit %d\n", printer->k_limit);
+
+    for (i = 0; i < printer->num_users; i ++)
+      cupsFilePrintf(fp, "%sUser %s\n", printer->deny_users ? "Deny" : "Allow",
+              printer->users[i]);
+
+    cupsFilePuts(fp, "</Printer>\n");
+
+#ifdef __sgi
+    /*
+     * Make IRIX desktop & printer status happy
+     */
+
+    write_irix_state(printer);
+#endif /* __sgi */
   }
 
-  fclose(fp);
+  cupsFileClose(fp);
 }
 
 
@@ -679,16 +945,19 @@ SetPrinterAttrs(printer_t *p)             /* I - Printer to setup */
   char         filename[1024];         /* Name of PPD file */
   int          num_media;              /* Number of media options */
   location_t   *auth;                  /* Pointer to authentication element */
-  int          auth_len;               /* Length of class or printer resource */
   const char   *auth_supported;        /* Authentication supported */
+  cups_ptype_t printer_type;           /* Printer type data */
   ppd_file_t   *ppd;                   /* PPD file data */
   ppd_option_t *input_slot,            /* InputSlot options */
                *media_type,            /* MediaType options */
-               *page_size;             /* PageSize options */
+               *page_size,             /* PageSize options */
+               *output_bin,            /* OutputBin options */
+               *media_quality;         /* EFMediaQualityMode options */
+  ppd_attr_t   *ppdattr;               /* PPD attribute */
   ipp_attribute_t *attr;               /* Attribute data */
   ipp_value_t  *val;                   /* Attribute value */
-  int          nups[3] =               /* number-up-supported values */
-               { 1, 2, 4 };
+  int          nups[] =                /* number-up-supported values */
+               { 1, 2, 4, 6, 9, 16 };
   ipp_orient_t orients[4] =            /* orientation-requested-supported values */
                {
                  IPP_PORTRAIT,
@@ -723,6 +992,8 @@ SetPrinterAttrs(printer_t *p)               /* I - Printer to setup */
                  IPP_RESUME_PRINTER,
                  IPP_PURGE_JOBS,
                  IPP_SET_JOB_ATTRIBUTES,
+                 IPP_ENABLE_PRINTER,
+                 IPP_DISABLE_PRINTER,
                  CUPS_GET_DEFAULT,
                  CUPS_GET_PRINTERS,
                  CUPS_ADD_PRINTER,
@@ -749,25 +1020,131 @@ SetPrinterAttrs(printer_t *p)           /* I - Printer to setup */
                  "iso-8859-8",
                  "iso-8859-9",
                  "iso-8859-10",
-                 "utf-8"
+                 "iso-8859-13",
+                 "iso-8859-14",
+                 "iso-8859-15",
+                 "utf-8",
+                 "windows-874",
+                 "windows-1250",
+                 "windows-1251",
+                 "windows-1252",
+                 "windows-1253",
+                 "windows-1254",
+                 "windows-1255",
+                 "windows-1256",
+                 "windows-1257",
+                 "windows-1258",
+                 "koi8-r",
+                 "koi8-u",
+               };
+  const char   *compressions[] =
+               {
+#ifdef HAVE_LIBZ
+                 "none",
+                 "gzip"
+#else
+                 "none"
+#endif /* HAVE_LIBZ */
                };
   int          num_finishings;
   ipp_finish_t finishings[5];
   const char   *multiple_document_handling[] =
                {
-                 "single-document",
                  "separate-documents-uncollated-copies",
-                 "separate-documents-collated-copies",
-                 "single-document-new-sheet"
+                 "separate-documents-collated-copies"
                };
 #ifdef __sgi
-  FILE         *fp;            /* Interface script file */
+  cups_file_t  *fp;            /* Interface script file */
 #endif /* __sgi */
 
 
   DEBUG_printf(("SetPrinterAttrs: entering name = %s, type = %x\n", p->name,
                 p->type));
 
+ /*
+  * Make sure that we have the common attributes defined...
+  */
+
+  if (!CommonData)
+  {
+    CommonData = ippNew();
+
+    ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                "pdl-override-supported", NULL, "not-attempted");
+    ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                  "ipp-versions-supported", sizeof(versions) / sizeof(versions[0]),
+                 NULL, versions);
+    ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM, "operations-supported",
+                   sizeof(ops) / sizeof(ops[0]) + JobFiles - 1, (int *)ops);
+    ippAddBoolean(CommonData, IPP_TAG_PRINTER, "multiple-document-jobs-supported", 1);
+    ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                  "multiple-operation-time-out", 60);
+    ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                  "multiple-document-handling-supported",
+                  sizeof(multiple_document_handling) /
+                     sizeof(multiple_document_handling[0]), NULL,
+                 multiple_document_handling);
+    ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET, "charset-configured",
+                NULL, DefaultCharset);
+    ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET, "charset-supported",
+                  sizeof(charsets) / sizeof(charsets[0]), NULL, charsets);
+    ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
+                "natural-language-configured", NULL, DefaultLanguage);
+    ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
+                "generated-natural-language-supported", NULL, DefaultLanguage);
+    ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
+                "document-format-default", NULL, "application/octet-stream");
+    ippAddStrings(CommonData, IPP_TAG_PRINTER,
+                  (ipp_tag_t)(IPP_TAG_MIMETYPE | IPP_TAG_COPY),
+                  "document-format-supported", NumMimeTypes, NULL, MimeTypes);
+    ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                 "compression-supported",
+                 sizeof(compressions) / sizeof(compressions[0]),
+                 NULL, compressions);
+    ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                  "job-priority-supported", 100);
+    ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                  "job-priority-default", 50);
+    ippAddRange(CommonData, IPP_TAG_PRINTER, "copies-supported", 1, MaxCopies);
+    ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                  "copies-default", 1);
+    ippAddBoolean(CommonData, IPP_TAG_PRINTER, "page-ranges-supported", 1);
+    ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                   "number-up-supported", sizeof(nups) / sizeof(nups[0]), nups);
+    ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                  "number-up-default", 1);
+    ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM,
+                   "orientation-requested-supported", 4, (int *)orients);
+    ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM,
+                  "orientation-requested-default", IPP_PORTRAIT);
+
+    if (NumBanners > 0)
+    {
+     /*
+      * Setup the job-sheets-supported and job-sheets-default attributes...
+      */
+
+      if (Classification && !ClassifyOverride)
+       attr = ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME,
+                           "job-sheets-supported", NULL, Classification);
+      else
+       attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME,
+                            "job-sheets-supported", NumBanners + 1, NULL, NULL);
+
+      if (attr == NULL)
+       LogMessage(L_EMERG, "SetPrinterAttrs: Unable to allocate memory for "
+                            "job-sheets-supported attribute: %s!",
+                  strerror(errno));
+      else if (!Classification || ClassifyOverride)
+      {
+       attr->values[0].string.text = strdup("none");
+
+       for (i = 0; i < NumBanners; i ++)
+         attr->values[i + 1].string.text = strdup(Banners[i].name);
+      }
+    }
+  }
+
  /*
   * Clear out old filters and add a filter from application/vnd.cups-raw to
   * printer/name to handle "raw" printing by users.
@@ -784,43 +1161,17 @@ SetPrinterAttrs(printer_t *p)            /* I - Printer to setup */
   if (!(p->type & CUPS_PRINTER_REMOTE))
   {
     if (p->type & CUPS_PRINTER_CLASS)
-    {
-      auth_len = 8;
-      sprintf(resource, "/classes/%s", p->name);
-    }
+      snprintf(resource, sizeof(resource), "/classes/%s", p->name);
     else
+      snprintf(resource, sizeof(resource), "/printers/%s", p->name);
+
+    if ((auth = FindBest(resource, HTTP_POST)) != NULL)
     {
-      auth_len = 9;
-      sprintf(resource, "/printers/%s", p->name);
+      if (auth->type == AUTH_BASIC || auth->type == AUTH_BASICDIGEST)
+       auth_supported = "basic";
+      else if (auth->type == AUTH_DIGEST)
+       auth_supported = "digest";
     }
-
-    for (i = NumLocations, auth = Locations; i > 0; i --, auth ++)
-      if (strcmp(auth->location, resource) == 0)
-      {
-       /*
-        * Exact match...
-       */
-
-       if (auth->type == AUTH_BASIC)
-         auth_supported = "basic";
-       else if (auth->type == AUTH_DIGEST)
-         auth_supported = "digest";
-       break;
-      }
-      else if (strcmp(auth->location, "/") == 0 ||
-               (strncmp(auth->location, resource, auth_len) == 0 &&
-                (strlen(auth->location) == auth_len ||
-                strlen(auth->location) == (auth_len + 1))))
-      {
-       /*
-        * Matches base printer or class resources...
-       */
-
-       if (auth->type == AUTH_BASIC)
-         auth_supported = "basic";
-       else if (auth->type == AUTH_DIGEST)
-         auth_supported = "digest";
-      }
   }
 
  /*
@@ -841,73 +1192,53 @@ SetPrinterAttrs(printer_t *p)            /* I - Printer to setup */
   ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-name", NULL,
                p->name);
   ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
-               NULL, p->location);
+               NULL, p->location ? p->location : "");
   ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
-               NULL, p->info);
+               NULL, p->info ? p->info : "");
   ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-more-info",
-               NULL, p->more_info);
-  ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-               "pdl-override-supported", NULL, "not-attempted");
-  ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-                "ipp-versions-supported", sizeof(versions) / sizeof(versions[0]),
-               NULL, versions);
-  ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "operations-supported",
-                 sizeof(ops) / sizeof(ops[0]) + JobFiles - 1, (int *)ops);
-  ippAddBoolean(p->attrs, IPP_TAG_PRINTER, "multiple-document-jobs-supported", 1);
-  ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-                "multiple-document-handling-supported",
-                sizeof(multiple_document_handling) /
-                   sizeof(multiple_document_handling[0]), NULL,
-               multiple_document_handling);
-  ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_CHARSET, "charset-configured",
-               NULL, DefaultCharset);
-  ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_CHARSET, "charset-supported",
-                sizeof(charsets) / sizeof(charsets[0]), NULL, charsets);
-  ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
-               "natural-language-configured", NULL, DefaultLanguage);
-  ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
-               "generated-natural-language-supported", NULL, DefaultLanguage);
-  ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
-               "document-format-default", NULL, "application/octet-stream");
-  ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
-               "document-format-supported", NULL, "application/octet-stream");
-  ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-               "compression-supported", NULL, "none");
-  ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
-                "job-priority-supported", 100);
+               NULL, p->uri);
+
+  if (p->num_users)
+  {
+    if (p->deny_users)
+      ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
+                    "requesting-user-name-denied", p->num_users, NULL,
+                   p->users);
+    else
+      ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
+                    "requesting-user-name-allowed", p->num_users, NULL,
+                   p->users);
+  }
+
   ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
-                "job-priority-default", 50);
-  ippAddRange(p->attrs, IPP_TAG_PRINTER, "copies-supported", 1, 65535);
+                "job-quota-period", p->quota_period);
   ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
-                "copies-default", 1);
-  ippAddBoolean(p->attrs, IPP_TAG_PRINTER, "page-ranges-supported", 1);
-  ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
-                 "number-up-supported", 3, nups);
+                "job-k-limit", p->k_limit);
   ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
-                "number-up-default", 1);
-  ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
-                 "orientation-requested-supported", 4, (int *)orients);
-  ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
-                "orientation-requested-default", IPP_PORTRAIT);
+                "job-page-limit", p->page_limit);
 
-  if (NumBanners > 0)
+  if (NumBanners > 0 && !(p->type & CUPS_PRINTER_REMOTE))
   {
    /*
-    * Setup the job-sheets-supported and job-sheets-default attributes...
+    * Setup the job-sheets-default attribute...
     */
 
-    attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
-                        "job-sheets-supported", NumBanners + 1, NULL, NULL);
-    attr->values[0].string.text = strdup("none");
-    for (i = 0; i < NumBanners; i ++)
-      attr->values[i + 1].string.text = strdup(Banners[i].name);
-
     attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
                         "job-sheets-default", 2, NULL, NULL);
-    attr->values[0].string.text = strdup(p->job_sheets[0]);
-    attr->values[1].string.text = strdup(p->job_sheets[1]);
+
+    if (attr != NULL)
+    {
+      attr->values[0].string.text = strdup(Classification ?
+                                          Classification : p->job_sheets[0]);
+      attr->values[1].string.text = strdup(Classification ?
+                                          Classification : p->job_sheets[1]);
+    }
   }
 
+  printer_type = p->type;
+
+  p->raw = 0;
+
   if (p->type & CUPS_PRINTER_REMOTE)
   {
    /*
@@ -916,6 +1247,8 @@ SetPrinterAttrs(printer_t *p)              /* I - Printer to setup */
 
     ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
                  "printer-make-and-model", NULL, p->make_model);
+
+    p->raw = 1;
   }
   else
   {
@@ -947,12 +1280,12 @@ SetPrinterAttrs(printer_t *p)            /* I - Printer to setup */
 
        attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
                              "member-uris", p->num_printers, NULL, NULL);
-
         p->type |= CUPS_PRINTER_OPTIONS;
 
        for (i = 0; i < p->num_printers; i ++)
        {
-          attr->values[i].string.text = strdup(p->printers[i]->uri);
+          if (attr != NULL)
+            attr->values[i].string.text = strdup(p->printers[i]->uri);
 
          p->type &= ~CUPS_PRINTER_OPTIONS | p->printers[i]->type;
         }
@@ -960,8 +1293,11 @@ SetPrinterAttrs(printer_t *p)             /* I - Printer to setup */
        attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
                              "member-names", p->num_printers, NULL, NULL);
 
-       for (i = 0; i < p->num_printers; i ++)
-          attr->values[i].string.text = strdup(p->printers[i]->name);
+       if (attr != NULL)
+       {
+         for (i = 0; i < p->num_printers; i ++)
+            attr->values[i].string.text = strdup(p->printers[i]->name);
+        }
       }
     }
     else
@@ -971,7 +1307,9 @@ SetPrinterAttrs(printer_t *p)              /* I - Printer to setup */
       * URI so it doesn't have a username or password in it...
       */
 
-      if (strstr(p->device_uri, "://") != NULL)
+      if (!p->device_uri)
+        strcpy(uri, "file:/dev/null");
+      else if (strstr(p->device_uri, "://") != NULL)
       {
        /*
         * http://..., ipp://..., etc.
@@ -979,9 +1317,10 @@ SetPrinterAttrs(printer_t *p)             /* I - Printer to setup */
 
         httpSeparate(p->device_uri, method, username, host, &port, resource);
        if (port)
-         sprintf(uri, "%s://%s:%d%s", method, host, port, resource);
+         snprintf(uri, sizeof(uri), "%s://%s:%d%s", method, host, port,
+                  resource);
        else
-         sprintf(uri, "%s://%s%s", method, host, resource);
+         snprintf(uri, sizeof(uri), "%s://%s%s", method, host, resource);
       }
       else
       {
@@ -989,7 +1328,7 @@ SetPrinterAttrs(printer_t *p)              /* I - Printer to setup */
         * file:..., serial:..., etc.
        */
 
-        strcpy(uri, p->device_uri);
+        strlcpy(uri, p->device_uri, sizeof(uri));
       }
 
       ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
@@ -1000,10 +1339,12 @@ SetPrinterAttrs(printer_t *p)           /* I - Printer to setup */
       */
 
       p->type        |= CUPS_PRINTER_BW;
-      finishings[0]  = IPP_FINISH_NONE;
+      finishings[0]  = IPP_FINISHINGS_NONE;
       num_finishings = 1;
 
-      sprintf(filename, "%s/ppd/%s.ppd", ServerRoot, p->name);
+      snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot,
+               p->name);
+
       if ((ppd = ppdOpenFile(filename)) != NULL)
       {
        /*
@@ -1016,16 +1357,25 @@ SetPrinterAttrs(printer_t *p)           /* I - Printer to setup */
          p->type |= CUPS_PRINTER_VARIABLE;
        if (!ppd->manual_copies)
          p->type |= CUPS_PRINTER_COPIES;
+        if ((ppdattr = ppdFindAttr(ppd, "cupsFax", NULL)) != NULL)
+         if (ppdattr->value && !strcasecmp(ppdattr->value, "true"))
+           p->type |= CUPS_PRINTER_FAX;
 
        ippAddBoolean(p->attrs, IPP_TAG_PRINTER, "color-supported",
                       ppd->color_device);
        if (ppd->throughput)
          ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
                        "pages-per-minute", ppd->throughput);
-       ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
-                     "printer-make-and-model", NULL, ppd->nickname);
 
-        strncpy(p->make_model, ppd->nickname, sizeof(p->make_model) - 1);
+        if (ppd->nickname)
+          SetString(&p->make_model, ppd->nickname);
+       else if (ppd->modelname)
+          SetString(&p->make_model, ppd->modelname);
+       else
+         SetString(&p->make_model, "Bad PPD File");
+
+       ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+                     "printer-make-and-model", NULL, p->make_model);
 
        /*
        * Add media options from the PPD file...
@@ -1042,24 +1392,80 @@ SetPrinterAttrs(printer_t *p)           /* I - Printer to setup */
        if ((page_size = ppdFindOption(ppd, "PageSize")) != NULL)
          num_media += page_size->num_choices;
 
-       attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-                             "media-supported", num_media, NULL, NULL);
-       val  = attr->values;
+       if ((media_quality = ppdFindOption(ppd, "EFMediaQualityMode")) != NULL)
+         num_media += media_quality->num_choices;
 
-       if (input_slot != NULL)
-         for (i = 0; i < input_slot->num_choices; i ++, val ++)
-           val->string.text = strdup(input_slot->choices[i].choice);
+        if (num_media == 0)
+       {
+         LogMessage(L_CRIT, "SetPrinterAttrs: The PPD file for printer %s "
+                            "contains no media options and is therefore "
+                            "invalid!", p->name);
+       }
+       else
+       {
+         attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                               "media-supported", num_media, NULL, NULL);
+          if (attr != NULL)
+         {
+           val = attr->values;
+
+           if (input_slot != NULL)
+             for (i = 0; i < input_slot->num_choices; i ++, val ++)
+               val->string.text = strdup(input_slot->choices[i].choice);
+
+           if (media_type != NULL)
+             for (i = 0; i < media_type->num_choices; i ++, val ++)
+               val->string.text = strdup(media_type->choices[i].choice);
+
+           if (media_quality != NULL)
+             for (i = 0; i < media_quality->num_choices; i ++, val ++)
+               val->string.text = strdup(media_quality->choices[i].choice);
+
+           if (page_size != NULL)
+           {
+             for (i = 0; i < page_size->num_choices; i ++, val ++)
+               val->string.text = strdup(page_size->choices[i].choice);
+
+             ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
+                          NULL, page_size->defchoice);
+            }
+           else if (input_slot != NULL)
+             ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
+                          NULL, input_slot->defchoice);
+           else if (media_type != NULL)
+             ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
+                          NULL, media_type->defchoice);
+           else if (media_quality != NULL)
+             ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
+                          NULL, media_quality->defchoice);
+           else
+             ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
+                          NULL, "none");
+          }
+        }
 
-       if (media_type != NULL)
-         for (i = 0; i < media_type->num_choices; i ++, val ++)
-           val->string.text = strdup(media_type->choices[i].choice);
+       /*
+        * Output bin...
+       */
 
-       if (page_size != NULL)
-         for (i = 0; i < page_size->num_choices; i ++, val ++)
-           val->string.text = strdup(page_size->choices[i].choice);
+       if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL)
+       {
+         attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                               "output-bin-supported", output_bin->num_choices,
+                              NULL, NULL);
+
+          if (attr != NULL)
+         {
+           for (i = 0, val = attr->values;
+                i < output_bin->num_choices;
+                i ++, val ++)
+             val->string.text = strdup(output_bin->choices[i].choice);
+          }
+       }
 
-       ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
-                     NULL, page_size->defchoice);
+       /*
+        * Duplexing, etc...
+       */
 
        if (ppdFindOption(ppd, "Duplex") != NULL)
        {
@@ -1077,13 +1483,13 @@ SetPrinterAttrs(printer_t *p)           /* I - Printer to setup */
        if (ppdFindOption(ppd, "StapleLocation") != NULL)
        {
          p->type |= CUPS_PRINTER_STAPLE;
-         finishings[num_finishings++] = IPP_FINISH_STAPLE;
+         finishings[num_finishings++] = IPP_FINISHINGS_STAPLE;
        }
 
        if (ppdFindOption(ppd, "BindEdge") != NULL)
        {
          p->type |= CUPS_PRINTER_BIND;
-         finishings[num_finishings++] = IPP_FINISH_BIND;
+         finishings[num_finishings++] = IPP_FINISHINGS_BIND;
        }
 
        for (i = 0; i < ppd->num_sizes; i ++)
@@ -1109,11 +1515,28 @@ SetPrinterAttrs(printer_t *p)           /* I - Printer to setup */
           AddPrinterFilter(p, "application/vnd.cups-postscript 0 -");
 
        ppdClose(ppd);
+
+        printer_type = p->type;
       }
       else if (access(filename, 0) == 0)
       {
+        int            pline;                  /* PPD line number */
+       ppd_status_t    pstatus;                /* PPD load status */
+
+
+        pstatus = ppdLastError(&pline);
+
        LogMessage(L_ERROR, "PPD file for %s cannot be loaded!", p->name);
 
+       if (pstatus <= PPD_ALLOC_ERROR)
+         LogMessage(L_ERROR, "%s", strerror(errno));
+        else
+         LogMessage(L_ERROR, "%s on line %d.", ppdErrorString(pstatus),
+                    pline);
+
+        LogMessage(L_INFO, "Hint: Run \"cupstestppd %s\" and fix any errors.",
+                  filename);
+
        AddPrinterFilter(p, "application/vnd.cups-postscript 0 -");
       }
       else
@@ -1122,7 +1545,8 @@ SetPrinterAttrs(printer_t *p)             /* I - Printer to setup */
        * If we have an interface script, add a filter entry for it...
        */
 
-       sprintf(filename, "%s/interfaces/%s", ServerRoot, p->name);
+       snprintf(filename, sizeof(filename), "%s/interfaces/%s", ServerRoot,
+                p->name);
        if (access(filename, X_OK) == 0)
        {
         /*
@@ -1132,27 +1556,61 @@ SetPrinterAttrs(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");
 
-         sprintf(filename, "*/* 0 %s/interfaces/%s", ServerRoot, p->name);
+         snprintf(filename, sizeof(filename), "*/* 0 %s/interfaces/%s",
+                  ServerRoot, p->name);
          AddPrinterFilter(p, filename);
        }
-       else
-       {
+       else if (p->device_uri &&
+                strncmp(p->device_uri, "ipp://", 6) == 0 &&
+                (strstr(p->device_uri, "/printers/") != NULL ||
+                 strstr(p->device_uri, "/classes/") != NULL))
+        {
         /*
-          * Otherwise we have neither - treat this as a "dumb" printer
-         * with no PPD file...
+         * Tell the client this is really a hard-wired remote printer.
          */
 
-         ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
-                       "printer-make-and-model", NULL, "Local Raw Printer");
+          printer_type |= CUPS_PRINTER_REMOTE;
 
-         AddPrinterFilter(p, "*/* 0 -");
-       }
-      }
+         /*
+         * Reset the printer-uri-supported attribute to point at the
+         * remote printer...
+         */
+
+         attr = ippFindAttribute(p->attrs, "printer-uri-supported", IPP_TAG_URI);
+         free(attr->values[0].string.text);
+         attr->values[0].string.text = strdup(p->device_uri);
+
+         /*
+         * Then set the make-and-model accordingly...
+         */
+
+         ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+                       "printer-make-and-model", NULL, "Remote Printer");
+
+         /*
+         * Print all files directly...
+         */
+
+         p->raw = 1;
+       }
+       else
+       {
+        /*
+          * Otherwise we have neither - treat this as a "dumb" printer
+         * with no PPD file...
+         */
+
+         ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+                       "printer-make-and-model", NULL, "Local Raw Printer");
+
+         p->raw = 1;
+       }
+      }
 
       ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
                      "finishings-supported", num_finishings, (int *)finishings);
       ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
-                    "finishings-default", IPP_FINISH_NONE);
+                    "finishings-default", IPP_FINISHINGS_NONE);
     }
   }
 
@@ -1160,68 +1618,122 @@ SetPrinterAttrs(printer_t *p)          /* I - Printer to setup */
   * Add the CUPS-specific printer-type attribute...
   */
 
-  ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-type", p->type);
+  ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-type",
+                printer_type);
 
   DEBUG_printf(("SetPrinterAttrs: leaving name = %s, type = %x\n", p->name,
                 p->type));
 
 #ifdef __sgi
  /*
-  * Add dummy interface and GUI scripts to fool SGI's "challenged" printing
-  * tools.
+  * Write the IRIX printer config and status files...
   */
 
-  sprintf(filename, "/var/spool/lp/interface/%s", p->name);
-  if ((fp = fopen(filename, "w")) != NULL)
-  {
-    fputs("#!/bin/sh\n", fp);
+  write_irix_config(p);
+  write_irix_state(p);
+#endif /* __sgi */
+}
 
-    if ((attr = ippFindAttribute(p->attrs, "printer-make-and-model",
-                                 IPP_TAG_TEXT)) != NULL)
-      fprintf(fp, "NAME=\"%s\"\n", attr->values[0].string.text);
-    else if (p->type & CUPS_PRINTER_CLASS)
-      fputs("NAME=\"Printer Class\"\n", fp);
-    else
-      fputs("NAME=\"Remote Destination\"\n", fp);
 
-    if (p->type & CUPS_PRINTER_COLOR)
-      fputs("TYPE=ColorPostScript\n", fp);
-    else
-      fputs("TYPE=PostScript\n", fp);
+/*
+ * 'SetPrinterReasons()' - Set/update the reasons strings.
+ */
+
+void
+SetPrinterReasons(printer_t  *p,       /* I - Printer */
+                  const char *s)       /* I - Reasons strings */
+{
+  int          i;                      /* Looping var */
+  const char   *sptr;                  /* Pointer into reasons */
+  char         reason[255],            /* Reason string */
+               *rptr;                  /* Pointer into reason */
 
-    fclose(fp);
-    chmod(filename, 0755);
-  }
 
-  sprintf(filename, "/var/spool/lp/member/%s", p->name);
-  if ((fp = fopen(filename, "w")) != NULL)
+  if (s[0] == '-' || s[0] == '+')
   {
-    fputs("/dev/null\n", fp);
-    fclose(fp);
-    chmod(filename, 0644);
-  }
+   /*
+    * Add/remove reasons...
+    */
 
-  sprintf(filename, "/var/spool/lp/gui_interface/ELF/%s.gui", p->name);
-  if ((fp = fopen(filename, "w")) != NULL)
+    sptr = s + 1;
+  }
+  else
   {
-    fputs("#!/bin/sh\n", fp);
-    fprintf(fp, "/usr/bin/glpoptions -d %s -o \"$3\"\n", p->name);
-    fclose(fp);
-    chmod(filename, 0755);
+   /*
+    * Replace reasons...
+    */
+
+    sptr = s;
+
+    for (i = 0; i < p->num_reasons; i ++)
+      free(p->reasons[i]);
+
+    p->num_reasons = 0;
   }
 
-  sprintf(filename, "/var/spool/lp/activeicons/%s", p->name);
-  if ((fp = fopen(filename, "w")) != NULL)
+ /*
+  * Loop through all of the reasons...
+  */
+
+  while (*sptr)
   {
-    fputs("#!/bin/sh\n", fp);
-    if (p->type & CUPS_PRINTER_COLOR)
-      fputs("#Tag 66240\n", fp);
-    else
-      fputs("#Tag 66208\n", fp);
-    fclose(fp);
-    chmod(filename, 0755);
+   /*
+    * Skip leading whitespace and commas...
+    */
+
+    while (isspace(*sptr) || *sptr == ',')
+      sptr ++;
+
+    for (rptr = reason; *sptr && !isspace(*sptr) && *sptr != ','; sptr ++)
+      if (rptr < (reason + sizeof(reason) - 1))
+        *rptr++ = *sptr;
+
+    if (rptr == reason)
+      break;
+
+    *rptr = '\0';
+
+    if (s[0] == '-')
+    {
+     /*
+      * Remove reason...
+      */
+
+      for (i = 0; i < p->num_reasons; i ++)
+        if (!strcasecmp(reason, p->reasons[i]))
+       {
+        /*
+         * Found a match, so remove it...
+         */
+
+         p->num_reasons --;
+         free(p->reasons[i]);
+
+         if (i < p->num_reasons)
+           memmove(p->reasons + i, p->reasons + i + 1,
+                   (p->num_reasons - i) * sizeof(char *));
+
+         i --;
+       }
+    }
+    else if (s[0] == '+' &&
+             p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
+    {
+     /*
+      * Add reason...
+      */
+
+      for (i = 0; i < p->num_reasons; i ++)
+        if (!strcasecmp(reason, p->reasons[i]))
+         break;
+
+      if (i >= p->num_reasons)
+      {
+        p->reasons[i] = strdup(reason);
+       p->num_reasons ++;
+      }
+    }
   }
-#endif /* __sgi */
 }
 
 
@@ -1247,13 +1759,21 @@ SetPrinterState(printer_t    *p,        /* I - Printer to change */
   * Set the new state...
   */
 
-  old_state      = p->state;
-  p->state       = s;
-  p->state_time  = time(NULL);
+  old_state = p->state;
+  p->state  = s;
 
   if (old_state != s)
+  {
+    p->state_time  = time(NULL);
     p->browse_time = 0;
 
+#ifdef __sgi
+    write_irix_state(p);
+#endif /* __sgi */
+  }
+
+  AddPrinterHistory(p);
+
  /*
   * Save the printer configuration if a printer goes from idle or processing
   * to stopped (or visa-versa)...
@@ -1261,12 +1781,6 @@ SetPrinterState(printer_t    *p, /* I - Printer to change */
 
   if ((old_state == IPP_PRINTER_STOPPED) != (s == IPP_PRINTER_STOPPED))
     SaveAllPrinters();
-
- /*
-  * Check to see if any pending jobs can now be printed...
-  */
-
-  CheckJobs();
 }
 
 
@@ -1312,9 +1826,13 @@ SortPrinters(void)
        next          = current->next;
        current->next = next->next;
        next->next    = current;
+       prev          = next;
       }
       else
+      {
+        prev    = current;
        current = current->next;
+      }
   }
   while (did_swap);
 }
@@ -1327,25 +1845,184 @@ SortPrinters(void)
 void
 StopPrinter(printer_t *p)      /* I - Printer to stop */
 {
-  if (p->job)
-    StopJob(((job_t *)p->job)->id);
+  job_t        *job;                   /* Active print job */
+
+
+ /*
+  * Set the printer state...
+  */
 
   p->state = IPP_PRINTER_STOPPED;
+
+ /*
+  * See if we have a job printing on this printer...
+  */
+
+  if (p->job)
+  {
+   /*
+    * Get pointer to job...
+    */
+
+    job = (job_t *)p->job;
+
+   /*
+    * Stop it...
+    */
+
+    StopJob(job->id, 0);
+
+   /*
+    * Reset the state to pending...
+    */
+
+    job->state->values[0].integer = IPP_JOB_PENDING;
+
+    SaveJob(job->id);
+  }
 }
 
 
 /*
- * 'write_printcap()' - Write a pseudo-printcap file for older applications
- *                      that need it...
+ * 'ValidateDest()' - Validate a printer/class destination.
  */
 
-static void
-write_printcap(void)
+const char *                           /* O - Printer or class name */
+ValidateDest(const char   *hostname,   /* I - Host name */
+             const char   *resource,   /* I - Resource name */
+             cups_ptype_t *dtype)      /* O - Type (printer or class) */
 {
-  FILE         *fp;            /* printcap file */
+  printer_t    *p;                     /* Current printer */
+  char         localname[1024],        /* Localized hostname */
+               *lptr,                  /* Pointer into localized hostname */
+               *sptr;                  /* Pointer into server name */
+
+
+  DEBUG_printf(("ValidateDest(\"%s\", \"%s\", %p)\n", hostname, resource, dtype));
+
+ /*
+  * See if the resource is a class or printer...
+  */
+
+  if (strncmp(resource, "/classes/", 9) == 0)
+  {
+   /*
+    * Class...
+    */
+
+    resource += 9;
+  }
+  else if (strncmp(resource, "/printers/", 10) == 0)
+  {
+   /*
+    * Printer...
+    */
+
+    resource += 10;
+  }
+  else
+  {
+   /*
+    * Bad resource name...
+    */
+
+    return (NULL);
+  }
+
+ /*
+  * See if the printer or class name exists...
+  */
+
+  if ((p = FindPrinter(resource)) == NULL)
+    p = FindClass(resource);
+
+  if (p == NULL && strchr(resource, '@') == NULL)
+    return (NULL);
+  else if (p != NULL)
+  {
+    *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT |
+                        CUPS_PRINTER_REMOTE);
+    return (p->name);
+  }
+
+ /*
+  * Change localhost to the server name...
+  */
+
+  if (strcasecmp(hostname, "localhost") == 0)
+    hostname = ServerName;
+
+  strlcpy(localname, hostname, sizeof(localname));
+
+  if (strcasecmp(hostname, ServerName) != 0)
+  {
+   /*
+    * Localize the hostname...
+    */
+
+    lptr = strchr(localname, '.');
+    sptr = strchr(ServerName, '.');
+
+    if (sptr != NULL && lptr != NULL)
+    {
+     /*
+      * Strip the common domain name components...
+      */
+
+      while (lptr != NULL)
+      {
+       if (strcasecmp(lptr, sptr) == 0)
+       {
+          *lptr = '\0';
+         break;
+       }
+       else
+          lptr = strchr(lptr + 1, '.');
+      }
+    }
+  }
+
+  DEBUG_printf(("localized hostname is \"%s\"...\n", localname));
+
+ /*
+  * Find a matching printer or class...
+  */
+
+  for (p = Printers; p != NULL; p = p->next)
+    if (strcasecmp(p->hostname, localname) == 0 &&
+        strcasecmp(p->name, resource) == 0)
+    {
+      *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT |
+                          CUPS_PRINTER_REMOTE);
+      return (p->name);
+    }
+
+  return (NULL);
+}
+
+
+/*
+ * 'WritePrintcap()' - Write a pseudo-printcap file for older applications
+ *                     that need it...
+ */
+
+void
+WritePrintcap(void)
+{
+  cups_file_t  *fp;            /* printcap file */
   printer_t    *p;             /* Current printer */
 
 
+#ifdef __sgi
+ /*
+  * Update the IRIX printer state for the default printer; if
+  * no printers remain, then the default printer file will be
+  * removed...
+  */
+
+  write_irix_state(DefaultPrinter);
+#endif /* __sgi */
+
  /*
   * See if we have a printcap file; if not, don't bother writing it.
   */
@@ -1354,30 +2031,348 @@ write_printcap(void)
     return;
 
  /*
-  * Write a new printcap with the current list of printers. Each printer
-  * is put in the file as:
-  *
-  *    Printer1:
-  *    Printer2:
-  *    Printer3:
-  *    ...
-  *    PrinterN:
+  * Open the printcap file...
   */
 
-  if ((fp = fopen(Printcap, "w")) == NULL)
+  if ((fp = cupsFileOpen(Printcap, "w")) == NULL)
     return;
 
-  for (p = Printers; p != NULL; p = p->next)
-    fprintf(fp, "%s:\n", p->name);
+ /*
+  * Put a comment header at the top so that users will know where the
+  * data has come from...
+  */
+
+  cupsFilePuts(fp, "# This file was automatically generated by cupsd(8) from the\n");
+  cupsFilePrintf(fp, "# %s/printers.conf file.  All changes to this file\n",
+          ServerRoot);
+  cupsFilePuts(fp, "# will be lost.\n");
+
+ /*
+  * Write a new printcap with the current list of printers.
+  */
+
+  switch (PrintcapFormat)
+  {
+    case PRINTCAP_BSD:
+       /*
+        * Each printer is put in the file as:
+       *
+       *    Printer1:
+       *    Printer2:
+       *    Printer3:
+       *    ...
+       *    PrinterN:
+       */
+
+        if (DefaultPrinter)
+         cupsFilePrintf(fp, "%s|%s:rm=%s:rp=%s:\n", DefaultPrinter->name,
+                 DefaultPrinter->info, ServerName, DefaultPrinter->name);
+
+       for (p = Printers; p != NULL; p = p->next)
+         if (p != DefaultPrinter)
+           cupsFilePrintf(fp, "%s|%s:rm=%s:rp=%s:\n", p->name, p->info,
+                   ServerName, p->name);
+        break;
+
+    case PRINTCAP_SOLARIS:
+       /*
+        * Each printer is put in the file as:
+       *
+       *    _all:all=Printer1,Printer2,Printer3,...,PrinterN
+       *    _default:use=DefaultPrinter
+       *    Printer1:\
+       *            :bsdaddr=ServerName,Printer1:\
+       *            :description=Description:
+       *    Printer2:
+       *            :bsdaddr=ServerName,Printer2:\
+       *            :description=Description:
+       *    Printer3:
+       *            :bsdaddr=ServerName,Printer3:\
+       *            :description=Description:
+       *    ...
+       *    PrinterN:
+       *            :bsdaddr=ServerName,PrinterN:\
+       *            :description=Description:
+       */
+
+        cupsFilePuts(fp, "_all:all=");
+       for (p = Printers; p != NULL; p = p->next)
+         cupsFilePrintf(fp, "%s%c", p->name, p->next ? ',' : '\n');
+
+        if (DefaultPrinter)
+         cupsFilePrintf(fp, "_default:use=%s\n", DefaultPrinter->name);
+
+       for (p = Printers; p != NULL; p = p->next)
+         cupsFilePrintf(fp, "%s:\\\n"
+                     "\t:bsdaddr=%s,%s:\\\n"
+                     "\t:description=%s:\n",
+                 p->name, ServerName, p->name, p->info ? p->info : "");
+        break;
+  }
 
  /*
   * Close the file...
   */
 
-  fclose(fp);
+  cupsFileClose(fp);
 }
 
 
+#ifdef __sgi
+/*
+ * 'write_irix_config()' - Update the config files used by the IRIX
+ *                         desktop tools.
+ */
+
+static void
+write_irix_config(printer_t *p)                /* I - Printer to update */
+{
+  char         filename[1024];         /* Interface script filename */
+  cups_file_t  *fp;                    /* Interface script file */
+  int          tag;                    /* Status tag value */
+
+
+
+ /*
+  * Add dummy interface and GUI scripts to fool SGI's "challenged" printing
+  * tools.  First the interface script that tells the tools what kind of
+  * printer we have...
+  */
+
+  snprintf(filename, sizeof(filename), "/var/spool/lp/interface/%s", p->name);
+
+  if (p->type & CUPS_PRINTER_CLASS)
+    unlink(filename);
+  else if ((fp = cupsFileOpen(filename, "w")) != NULL)
+  {
+    cupsFilePuts(fp, "#!/bin/sh\n");
+
+    if ((attr = ippFindAttribute(p->attrs, "printer-make-and-model",
+                                 IPP_TAG_TEXT)) != NULL)
+      cupsFilePrintf(fp, "NAME=\"%s\"\n", attr->values[0].string.text);
+    else if (p->type & CUPS_PRINTER_CLASS)
+      cupsFilePuts(fp, "NAME=\"Printer Class\"\n");
+    else
+      cupsFilePuts(fp, "NAME=\"Remote Destination\"\n");
+
+    if (p->type & CUPS_PRINTER_COLOR)
+      cupsFilePuts(fp, "TYPE=ColorPostScript\n");
+    else
+      cupsFilePuts(fp, "TYPE=MonoPostScript\n");
+
+    cupsFilePrintf(fp, "HOSTNAME=%s\n", ServerName);
+    cupsFilePrintf(fp, "HOSTPRINTER=%s\n", p->name);
+
+    cupsFileClose(fp);
+
+    chmod(filename, 0755);
+    chown(filename, User, Group);
+  }
+
+ /*
+  * Then the member file that tells which device file the queue is connected
+  * to...  Networked printers use "/dev/null" in this file, so that's what
+  * we use (the actual device URI can confuse some apps...)
+  */
+
+  snprintf(filename, sizeof(filename), "/var/spool/lp/member/%s", p->name);
+
+  if (p->type & CUPS_PRINTER_CLASS)
+    unlink(filename);
+  else if ((fp = cupsFileOpen(filename, "w")) != NULL)
+  {
+    cupsFilePuts(fp, "/dev/null\n");
+
+    cupsFileClose(fp);
+
+    chmod(filename, 0644);
+    chown(filename, User, Group);
+  }
+
+ /*
+  * The gui_interface file is a script or program that launches a GUI
+  * option panel for the printer, using options specified on the
+  * command-line in the third argument.  The option panel must send
+  * any printing options to stdout on a single line when the user
+  * accepts them, or nothing if the user cancels the dialog.
+  *
+  * The default options panel program is /usr/bin/glpoptions, from
+  * the ESP Print Pro software.  You can select another using the
+  * PrintcapGUI option.
+  */
+
+  snprintf(filename, sizeof(filename), "/var/spool/lp/gui_interface/ELF/%s.gui", p->name);
+
+  if (p->type & CUPS_PRINTER_CLASS)
+    unlink(filename);
+  else if ((fp = cupsFileOpen(filename, "w")) != NULL)
+  {
+    cupsFilePuts(fp, "#!/bin/sh\n");
+    cupsFilePrintf(fp, "%s -d %s -o \"$3\"\n", PrintcapGUI, p->name);
+
+    cupsFileClose(fp);
+
+    chmod(filename, 0755);
+    chown(filename, User, Group);
+  }
+
+ /*
+  * The POD config file is needed by the printstatus command to show
+  * the printer location and device.
+  */
+
+  snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.config", p->name);
+
+  if (p->type & CUPS_PRINTER_CLASS)
+    unlink(filename);
+  else if ((fp = cupsFileOpen(filename, "w")) != NULL)
+  {
+    cupsFilePrintf(fp, "Printer Class      | %s\n",
+            (p->type & CUPS_PRINTER_COLOR) ? "ColorPostScript" : "MonoPostScript");
+    cupsFilePrintf(fp, "Printer Model      | %s\n", p->make_model ? p->make_model : "");
+    cupsFilePrintf(fp, "Location Code      | %s\n", p->location ? p->location : "");
+    cupsFilePrintf(fp, "Physical Location  | %s\n", p->info ? p->info : "");
+    cupsFilePrintf(fp, "Port Path          | %s\n", p->device_uri ? p->device_uri : "");
+    cupsFilePrintf(fp, "Config Path        | /var/spool/lp/pod/%s.config\n", p->name);
+    cupsFilePrintf(fp, "Active Status Path | /var/spool/lp/pod/%s.status\n", p->name);
+    cupsFilePuts(fp, "Status Update Wait | 10 seconds\n");
+
+    cupsFileClose(fp);
+
+    chmod(filename, 0664);
+    chown(filename, User, Group);
+  }
+
+
+/*
+ * 'write_irix_state()' - Update the status files used by IRIX printing
+ *                        desktop tools.
+ */
+
+static void
+write_irix_state(printer_t *p)         /* I - Printer to update */
+{
+  char         filename[1024];         /* Interface script filename */
+  cups_file_t  *fp;                    /* Interface script file */
+  int          tag;                    /* Status tag value */
+
+
+  if (p)
+  {
+   /*
+    * The POD status file is needed for the printstatus window to
+    * provide the current status of the printer.
+    */
+
+    snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.status", p->name);
+
+    if (p->type & CUPS_PRINTER_CLASS)
+      unlink(filename);
+    else if ((fp = cupsFileOpen(filename, "w")) != NULL)
+    {
+      cupsFilePrintf(fp, "Operational Status | %s\n",
+              (p->state == IPP_PRINTER_IDLE)       ? "Idle" :
+              (p->state == IPP_PRINTER_PROCESSING) ? "Busy" :
+                                                     "Faulted");
+      cupsFilePrintf(fp, "Information        | 01 00 00 | %s\n", CUPS_SVERSION);
+      cupsFilePrintf(fp, "Information        | 02 00 00 | Device URI: %s\n",
+              p->device_uri ? p->device_uri : "");
+      cupsFilePrintf(fp, "Information        | 03 00 00 | %s jobs\n",
+              p->accepting ? "Accepting" : "Not accepting");
+      cupsFilePrintf(fp, "Information        | 04 00 00 | %s\n", p->state_message);
+
+      cupsFileClose(fp);
+
+      chmod(filename, 0664);
+      chown(filename, User, Group);
+    }
+
+   /*
+    * The activeicons file is needed to provide desktop icons for printers:
+    *
+    * [ quoted from /usr/lib/print/tagit ]
+    *
+    * --- Type of printer tags (base values)
+    *
+    * Dumb=66048                       # 0x10200
+    * DumbColor=66080          # 0x10220
+    * Raster=66112             # 0x10240
+    * ColorRaster=66144                # 0x10260
+    * Plotter=66176            # 0x10280
+    * PostScript=66208         # 0x102A0
+    * ColorPostScript=66240    # 0x102C0
+    * MonoPostScript=66272     # 0x102E0
+    *
+    * --- Printer state modifiers for local printers
+    *
+    * Idle=0                   # 0x0
+    * Busy=1                   # 0x1
+    * Faulted=2                        # 0x2
+    * Unknown=3                        # 0x3 (Faulted due to unknown reason)
+    *
+    * --- Printer state modifiers for network printers
+    *
+    * NetIdle=8                        # 0x8
+    * NetBusy=9                        # 0x9
+    * NetFaulted=10            # 0xA
+    * NetUnknown=11            # 0xB (Faulted due to unknown reason)
+    */
+
+    snprintf(filename, sizeof(filename), "/var/spool/lp/activeicons/%s", p->name);
+
+    if (p->type & CUPS_PRINTER_CLASS)
+      unlink(filename);
+    else if ((fp = cupsFileOpen(filename, "w")) != NULL)
+    {
+      if (p->type & CUPS_PRINTER_COLOR)
+       tag = 66240;
+      else
+       tag = 66272;
+
+      if (p->type & CUPS_PRINTER_REMOTE)
+       tag |= 8;
+
+      if (p->state == IPP_PRINTER_PROCESSING)
+       tag |= 1;
+
+      else if (p->state == IPP_PRINTER_STOPPED)
+       tag |= 2;
+
+      cupsFilePuts(fp, "#!/bin/sh\n");
+      cupsFilePrintf(fp, "#Tag %d\n", tag);
+
+      cupsFileClose(fp);
+
+      chmod(filename, 0755);
+      chown(filename, User, Group);
+    }
+  }
+
+ /*
+  * The default file is needed by the printers window to show
+  * the default printer.
+  */
+
+  snprintf(filename, sizeof(filename), "/var/spool/lp/default");
+
+  if (DefaultPrinter != NULL)
+  {
+    if ((fp = cupsFileOpen(filename, "w")) != NULL)
+    {
+      cupsFilePrintf(fp, "%s\n", DefaultPrinter->name);
+
+      cupsFileClose(fp);
+
+      chmod(filename, 0644);
+      chown(filename, User, Group);
+    }
+  }
+  else
+    unlink(filename);
+}
+#endif /* __sgi */
+
+
 /*
- * End of "$Id: printers.c,v 1.60 2000/03/30 05:19:29 mike Exp $".
+ * End of "$Id: printers.c,v 1.93.2.46 2003/04/03 03:33:41 mike Exp $".
  */