/* * "$Id: printers.c,v 1.3.2.1 2002/08/23 19:56:30 jlovell Exp $" * * Printer routines for the Common UNIX Printing System (CUPS). * * Copyright 1997-2002 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 * copyright law. Distribution and use rights are outlined in the file * "LICENSE.txt" which should have been included with this file. If this * file is missing or damaged please contact Easy Software Products * at: * * Attn: CUPS Licensing Information * Easy Software Products * 44141 Airport View Drive, Suite 204 * Hollywood, Maryland 20636-3111 USA * * Voice: (301) 373-9603 * EMail: cups-info@cups.org * WWW: http://www.cups.org * * Contents: * * AddPrinter() - Add a printer to the system. * AddPrinterFilter() - Add a MIME filter for a printer. * 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. * 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. * 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. * write_printcap() - Write a pseudo-printcap file for older * applications that need it... */ /* * Include necessary headers... */ #include "cupsd.h" /* * Local functions... */ static void write_printcap(void); #ifdef __sgi static void write_irix_config(printer_t *p); static void write_irix_state(printer_t *p); #endif /* __sgi */ /* * 'AddPrinter()' - Add a printer to the system. */ printer_t * /* O - New printer */ AddPrinter(const char *name) /* I - Name of printer */ { printer_t *p, /* New printer */ *current, /* Current printer in list */ *prev; /* Previous printer in list */ DEBUG_printf(("AddPrinter(\"%s\")\n", name)); /* * Range check input... */ if (name == NULL) return (NULL); /* * Create a new printer entity... */ if ((p = calloc(1, sizeof(printer_t))) == NULL) return (NULL); strlcpy(p->name, name, sizeof(p->name)); strlcpy(p->info, name, sizeof(p->info)); strlcpy(p->hostname, ServerName, sizeof(p->hostname)); snprintf(p->uri, sizeof(p->uri), "ipp://%s:%d/printers/%s", ServerName, ntohs(Listeners[0].address.sin_port), name); 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); /* * Insert the printer in the printer list alphabetically... */ for (prev = NULL, current = Printers; current != NULL; prev = current, current = current->next) if (strcasecmp(p->name, current->name) < 0) break; /* * Insert this printer before the current one... */ if (prev == NULL) Printers = p; else prev->next = p; p->next = current; /* * Write a new /etc/printcap or /var/spool/lp/pstatus file. */ write_printcap(); return (p); } /* * 'AddPrinterFilter()' - Add a MIME filter for a printer. */ void 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 */ type[MIME_MAX_TYPE], /* Type for filter */ program[1024]; /* Program/filter name */ int cost; /* Cost of filter */ mime_type_t **temptype; /* MIME type looping var */ /* * Range check input... */ if (p == NULL || filter == NULL) return; /* * Parse the filter string; it should be in the following format: * * super/type cost program */ if (sscanf(filter, "%15[^/]/%31s%d%1023s", super, type, &cost, program) != 4) { LogMessage(L_ERROR, "AddPrinterFilter: Invalid filter string \"%s\"!", filter); return; } /* * Add the filter to the MIME database, supporting wildcards as needed... */ 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)) { LogMessage(L_DEBUG2, "Adding filter %s/%s %s/%s %d %s", (*temptype)->super, (*temptype)->type, p->filetype->super, p->filetype->type, cost, program); mimeAddFilter(MimeDatabase, *temptype, p->filetype, cost, program); } } /* * '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. */ void DeleteAllPrinters(void) { printer_t *p, /* Pointer to current printer/class */ *next; /* Pointer to next printer in list */ for (p = Printers; p != NULL; p = next) { next = p->next; if (!(p->type & CUPS_PRINTER_CLASS)) DeletePrinter(p); } } /* * 'DeletePrinter()' - Delete a printer from the system. */ void DeletePrinter(printer_t *p) /* I - Printer to delete */ { printer_t *current, /* Current printer in list */ *prev; /* Previous printer in list */ #ifdef __sgi char filename[1024]; /* Interface script filename */ #endif /* __sgi */ DEBUG_printf(("DeletePrinter(%08x): p->name = \"%s\"...\n", p, p->name)); /* * Range check input... */ if (p == NULL) return; /* * Remove the printer from the list... */ for (prev = NULL, current = Printers; current != NULL; prev = current, current = current->next) if (p == current) break; if (current == NULL) { LogMessage(L_ERROR, "Tried to delete a non-existent printer %s!\n", p->name); return; } if (prev == NULL) Printers = p->next; else prev->next = p->next; /* * Stop printing on this printer... */ StopPrinter(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; #ifdef __sgi /* * Update the IRIX printer state for the new default printer; if * no printers remain, then the default printer file will be * removed... */ write_irix_state(DefaultPrinter); #endif /* __sgi */ } /* * Remove this printer from any classes... */ if (!(p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))) DeletePrinterFromClasses(p); /* * Free all memory used by the printer... */ if (p->printers != NULL) free(p->printers); ippDelete(p->attrs); DeletePrinterFilters(p); FreePrinterUsers(p); FreeQuotas(p); free(p); /* * Write a new /etc/printcap file... */ write_printcap(); } /* * 'DeletePrinterFilters()' - Delete all MIME filters for a printer. */ void DeletePrinterFilters(printer_t *p) /* I - Printer to remove from */ { int i; /* Looping var */ mime_filter_t *filter; /* MIME filter looping var */ /* * Range check input... */ if (p == NULL) return; /* * Remove all filters from the MIME database that have a destination * type == printer... */ for (filter = MimeDatabase->filters, i = MimeDatabase->num_filters; i > 0; i --, filter ++) if (filter->dst == p->filetype) { /* * Delete the current filter... */ MimeDatabase->num_filters --; if (i > 1) memcpy(filter, filter + 1, sizeof(mime_filter_t) * (i - 1)); filter --; } } /* * 'FindPrinter()' - Find a printer in the list. */ printer_t * /* O - Printer in list */ FindPrinter(const char *name) /* I - Name of printer to find */ { printer_t *p; /* Current printer */ 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); } 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. */ void LoadAllPrinters(void) { FILE *fp; /* printers.conf file */ int linenum; /* Current line number */ int len; /* Length of line */ char line[1024], /* Line from file */ name[256], /* Parameter name */ *nameptr, /* Pointer into name */ *value, /* Pointer to value */ *valueptr; /* Pointer into value */ printer_t *p; /* Current printer */ /* * Open the printers.conf file... */ snprintf(line, sizeof(line), "%s/printers.conf", ServerRoot); if ((fp = fopen(line, "r")) == NULL) return; /* * Read printer configurations until we hit EOF... */ linenum = 0; p = NULL; while (fgets(line, sizeof(line), fp) != NULL) { linenum ++; /* * Skip comment lines... */ if (line[0] == '#') continue; /* * Strip trailing whitespace, if any... */ len = strlen(line); while (len > 0 && isspace(line[len - 1])) { len --; line[len] = '\0'; } /* * Extract the name from the beginning of the line... */ for (value = line; isspace(*value); value ++); for (nameptr = name; *value != '\0' && !isspace(*value) && nameptr < (name + sizeof(name) - 1);) *nameptr++ = *value++; *nameptr = '\0'; while (isspace(*value)) value ++; if (name[0] == '\0') continue; /* * Decode the directive... */ if (strcmp(name, " or */ if (line[len - 1] == '>' && p == NULL) { /* * Add the printer and a base file type... */ line[len - 1] = '\0'; p = AddPrinter(value); p->accepting = 1; p->state = IPP_PRINTER_IDLE; /* * Set the default printer as needed... */ if (strcmp(name, "") == 0) { if (p != NULL) { SetPrinterAttrs(p); p = NULL; } else { LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.", linenum); return; } } else if (p == NULL) { LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.", linenum); return; } else if (strcmp(name, "Info") == 0) strlcpy(p->info, value, sizeof(p->info)); else if (strcmp(name, "Location") == 0) strlcpy(p->location, value, sizeof(p->location)); else if (strcmp(name, "DeviceURI") == 0) strlcpy(p->device_uri, value, sizeof(p->device_uri)); else if (strcmp(name, "State") == 0) { /* * Set the initial queue state... */ if (strcasecmp(value, "idle") == 0) p->state = IPP_PRINTER_IDLE; else if (strcasecmp(value, "stopped") == 0) p->state = IPP_PRINTER_STOPPED; } else if (strcmp(name, "StateMessage") == 0) { /* * Set the initial queue state message... */ while (isspace(*value)) value ++; strlcpy(p->state_message, value, sizeof(p->state_message)); } else if (strcmp(name, "Accepting") == 0) { /* * Set the initial accepting state... */ if (strcasecmp(value, "yes") == 0) p->accepting = 1; else p->accepting = 0; } else if (strcmp(name, "JobSheets") == 0) { /* * Set the initial job sheets... */ for (valueptr = value; *valueptr && !isspace(*valueptr); valueptr ++); if (*valueptr) *valueptr++ = '\0'; strlcpy(p->job_sheets[0], value, sizeof(p->job_sheets[0])); while (isspace(*valueptr)) valueptr ++; if (*valueptr) { for (value = valueptr; *valueptr && !isspace(*valueptr); valueptr ++); if (*valueptr) *valueptr++ = '\0'; strlcpy(p->job_sheets[1], value, sizeof(p->job_sheets[1])); } } 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 { /* * Something else we don't understand... */ LogMessage(L_ERROR, "Unknown configuration directive %s on line %d of printers.conf.", name, linenum); } } fclose(fp); } /* * 'SaveAllPrinters()' - Save all printer definitions to the printers.conf * file. */ void SaveAllPrinters(void) { int i; /* Looping var */ FILE *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 */ /* * Create the printers.conf file... */ 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 = fopen(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(fileno(fp), User, Group); fchmod(fileno(fp), 0600); /* * Write a small header to the file... */ curtime = time(NULL); curdate = gmtime(&curtime); strftime(temp, sizeof(temp) - 1, CUPS_STRFTIME_FORMAT, curdate); fputs("# Printer configuration file for " CUPS_SVERSION "\n", fp); fprintf(fp, "# Written by cupsd on %s\n", temp); /* * Write each local printer known to the system... */ for (printer = Printers; printer != NULL; printer = printer->next) { /* * Skip remote destinations and printer classes... */ if ((printer->type & CUPS_PRINTER_REMOTE) || (printer->type & CUPS_PRINTER_CLASS) || (printer->type & CUPS_PRINTER_IMPLICIT)) continue; /* * Write printers as needed... */ if (printer == DefaultPrinter) fprintf(fp, "\n", printer->name); else fprintf(fp, "\n", printer->name); if (printer->info[0]) fprintf(fp, "Info %s\n", printer->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); if (printer->state == IPP_PRINTER_STOPPED) { fputs("State Stopped\n", fp); fprintf(fp, "StateMessage %s\n", printer->state_message); } else fputs("State Idle\n", fp); if (printer->accepting) fputs("Accepting Yes\n", fp); else fputs("Accepting No\n", fp); fprintf(fp, "JobSheets %s %s\n", printer->job_sheets[0], printer->job_sheets[1]); fprintf(fp, "QuotaPeriod %d\n", printer->quota_period); fprintf(fp, "PageLimit %d\n", printer->page_limit); fprintf(fp, "KLimit %d\n", printer->k_limit); for (i = 0; i < printer->num_users; i ++) fprintf(fp, "%sUser %s\n", printer->deny_users ? "Deny" : "Allow", printer->users[i]); fputs("\n", fp); #ifdef __sgi /* * Make IRIX desktop & printer status happy */ write_irix_state(printer); #endif /* __sgi */ } fclose(fp); } /* * 'SetPrinterAttrs()' - Set printer attributes based upon the PPD file. */ void SetPrinterAttrs(printer_t *p) /* I - Printer to setup */ { char uri[HTTP_MAX_URI]; /* URI for printer */ char method[HTTP_MAX_URI], /* Method portion of URI */ username[HTTP_MAX_URI], /* Username portion of URI */ host[HTTP_MAX_URI], /* Host portion of URI */ resource[HTTP_MAX_URI]; /* Resource portion of URI */ int port; /* Port portion of URI */ int i; /* Looping var */ char filename[1024]; /* Name of PPD file */ int num_media; /* Number of media options */ location_t *auth; /* Pointer to authentication element */ 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 */ *output_bin; /* OutputBin options */ ipp_attribute_t *attr; /* Attribute data */ ipp_value_t *val; /* Attribute value */ int nups[] = /* number-up-supported values */ { 1, 2, 4, 6, 9, 16 }; ipp_orient_t orients[4] = /* orientation-requested-supported values */ { IPP_PORTRAIT, IPP_LANDSCAPE, IPP_REVERSE_LANDSCAPE, IPP_REVERSE_PORTRAIT }; const char *sides[3] = /* sides-supported values */ { "one", "two-long-edge", "two-short-edge" }; const char *versions[] = /* ipp-versions-supported values */ { "1.0", "1.1" }; ipp_op_t ops[] = /* operations-supported values */ { IPP_PRINT_JOB, IPP_VALIDATE_JOB, IPP_CREATE_JOB, IPP_SEND_DOCUMENT, IPP_CANCEL_JOB, IPP_GET_JOB_ATTRIBUTES, IPP_GET_JOBS, IPP_GET_PRINTER_ATTRIBUTES, IPP_HOLD_JOB, IPP_RELEASE_JOB, IPP_PAUSE_PRINTER, 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, CUPS_DELETE_PRINTER, CUPS_GET_CLASSES, CUPS_ADD_CLASS, CUPS_DELETE_CLASS, CUPS_ACCEPT_JOBS, CUPS_REJECT_JOBS, CUPS_GET_DEVICES, CUPS_GET_PPDS, IPP_RESTART_JOB }; const char *charsets[] = /* charset-supported values */ { "us-ascii", "iso-8859-1", "iso-8859-2", "iso-8859-3", "iso-8859-4", "iso-8859-5", "iso-8859-6", "iso-8859-7", "iso-8859-8", "iso-8859-9", "iso-8859-10", "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", }; int num_finishings; ipp_finish_t finishings[5]; const char *multiple_document_handling[] = { "separate-documents-uncollated-copies", "separate-documents-collated-copies" }; DEBUG_printf(("SetPrinterAttrs: entering name = %s, type = %x\n", p->name, p->type)); /* * Clear out old filters and add a filter from application/vnd.cups-raw to * printer/name to handle "raw" printing by users. */ DeletePrinterFilters(p); AddPrinterFilter(p, "application/vnd.cups-raw 0 -"); /* * Figure out the authentication that is required for the printer. */ auth_supported = "requesting-user-name"; if (!(p->type & CUPS_PRINTER_REMOTE)) { if (p->type & CUPS_PRINTER_CLASS) snprintf(resource, sizeof(resource), "/classes/%s", p->name); else snprintf(resource, sizeof(resource), "/printers/%s", p->name); if ((auth = FindBest(resource, HTTP_POST)) != NULL) { if (auth->type == AUTH_BASIC || auth->type == AUTH_BASICDIGEST) auth_supported = "basic"; else if (auth->type == AUTH_DIGEST) auth_supported = "digest"; } } /* * Create the required IPP attributes for a printer... */ if (p->attrs) ippDelete(p->attrs); p->attrs = ippNew(); ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uri-supported", NULL, p->uri); ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "uri-authentication-supported", NULL, auth_supported); ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "uri-security-supported", NULL, "none"); 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); ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info", NULL, p->info); ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-more-info", NULL, p->uri); 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); ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "multiple-operation-time-out", 60); 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"); ippAddStrings(p->attrs, IPP_TAG_PRINTER, (ipp_tag_t)(IPP_TAG_MIMETYPE | IPP_TAG_COPY), "document-format-supported", NumMimeTypes, NULL, MimeTypes); 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); ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "job-priority-default", 50); ippAddRange(p->attrs, IPP_TAG_PRINTER, "copies-supported", 1, 65535); 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", sizeof(nups) / sizeof(nups[0]), nups); 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); 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-quota-period", p->quota_period); ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "job-k-limit", p->k_limit); ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "job-page-limit", p->page_limit); if (NumBanners > 0) { /* * Setup the job-sheets-supported and job-sheets-default attributes... */ if (Classification[0] && !ClassifyOverride) attr = ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "job-sheets-supported", NULL, Classification); else attr = ippAddStrings(p->attrs, 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[0] || ClassifyOverride) { attr->values[0].string.text = strdup("none"); for (i = 0; i < NumBanners; i ++) attr->values[i + 1].string.text = strdup(Banners[i].name); } if (!(p->type & CUPS_PRINTER_REMOTE)) { attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "job-sheets-default", 2, NULL, NULL); if (attr != NULL) { attr->values[0].string.text = strdup(Classification[0] ? Classification : p->job_sheets[0]); attr->values[1].string.text = strdup(Classification[0] ? Classification : p->job_sheets[1]); } } } printer_type = p->type; if (p->type & CUPS_PRINTER_REMOTE) { /* * Tell the client this is a remote printer of some type... */ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-make-and-model", NULL, p->make_model); } else { /* * Assign additional attributes depending on whether this is a printer * or class... */ p->type &= ~CUPS_PRINTER_OPTIONS; if (p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)) { /* * Add class-specific attributes... */ if ((p->type & CUPS_PRINTER_IMPLICIT) && p->num_printers > 0) ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-make-and-model", NULL, p->printers[0]->make_model); else ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-make-and-model", NULL, "Local Printer Class"); if (p->num_printers > 0) { /* * Add a list of member URIs and names... */ 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 ++) { if (attr != NULL) attr->values[i].string.text = strdup(p->printers[i]->uri); p->type &= ~CUPS_PRINTER_OPTIONS | p->printers[i]->type; } attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "member-names", p->num_printers, NULL, NULL); if (attr != NULL) { for (i = 0; i < p->num_printers; i ++) attr->values[i].string.text = strdup(p->printers[i]->name); } } } else { /* * Add printer-specific attributes... Start by sanitizing the device * URI so it doesn't have a username or password in it... */ if (strstr(p->device_uri, "://") != NULL) { /* * http://..., ipp://..., etc. */ httpSeparate(p->device_uri, method, username, host, &port, resource); if (port) snprintf(uri, sizeof(uri), "%s://%s:%d%s", method, host, port, resource); else snprintf(uri, sizeof(uri), "%s://%s%s", method, host, resource); } else { /* * file:..., serial:..., etc. */ strcpy(uri, p->device_uri); } ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL, uri); /* * Assign additional attributes from the PPD file (if any)... */ p->type |= CUPS_PRINTER_BW; finishings[0] = IPP_FINISHINGS_NONE; num_finishings = 1; snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot, p->name); if ((ppd = ppdOpenFile(filename)) != NULL) { /* * Add make/model and other various attributes... */ if (ppd->color_device) p->type |= CUPS_PRINTER_COLOR; if (ppd->variable_sizes) p->type |= CUPS_PRINTER_VARIABLE; if (!ppd->manual_copies) p->type |= CUPS_PRINTER_COPIES; 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); if (ppd->nickname) strlcpy(p->make_model, ppd->nickname, sizeof(p->make_model)); else if (ppd->modelname) strlcpy(p->make_model, ppd->modelname, sizeof(p->make_model)); else strcpy(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... */ if ((input_slot = ppdFindOption(ppd, "InputSlot")) != NULL) num_media = input_slot->num_choices; else num_media = 0; if ((media_type = ppdFindOption(ppd, "MediaType")) != NULL) num_media += media_type->num_choices; 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); 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 (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 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default", NULL, "none"); } /* * Output bin... */ 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); } } /* * Duplexing, etc... */ if (ppdFindOption(ppd, "Duplex") != NULL) { p->type |= CUPS_PRINTER_DUPLEX; ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "sides-supported", 3, NULL, sides); ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "sides-default", NULL, "one"); } if (ppdFindOption(ppd, "Collate") != NULL) p->type |= CUPS_PRINTER_COLLATE; if (ppdFindOption(ppd, "StapleLocation") != NULL) { p->type |= CUPS_PRINTER_STAPLE; finishings[num_finishings++] = IPP_FINISHINGS_STAPLE; } if (ppdFindOption(ppd, "BindEdge") != NULL) { p->type |= CUPS_PRINTER_BIND; finishings[num_finishings++] = IPP_FINISHINGS_BIND; } for (i = 0; i < ppd->num_sizes; i ++) if (ppd->sizes[i].length > 1728) p->type |= CUPS_PRINTER_LARGE; else if (ppd->sizes[i].length > 1008) p->type |= CUPS_PRINTER_MEDIUM; else p->type |= CUPS_PRINTER_SMALL; /* * Add any filters in the PPD file... */ DEBUG_printf(("ppd->num_filters = %d\n", ppd->num_filters)); for (i = 0; i < ppd->num_filters; i ++) { DEBUG_printf(("ppd->filters[%d] = \"%s\"\n", i, ppd->filters[i])); AddPrinterFilter(p, ppd->filters[i]); } if (ppd->num_filters == 0) AddPrinterFilter(p, "application/vnd.cups-postscript 0 -"); ppdClose(ppd); printer_type = p->type; } else if (access(filename, 0) == 0) { LogMessage(L_ERROR, "PPD file for %s cannot be loaded!", p->name); AddPrinterFilter(p, "application/vnd.cups-postscript 0 -"); } else { /* * If we have an interface script, add a filter entry for it... */ snprintf(filename, sizeof(filename), "%s/interfaces/%s", ServerRoot, p->name); if (access(filename, X_OK) == 0) { /* * Yes, we have a System V style interface script; use it! */ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-make-and-model", NULL, "Local System V Printer"); snprintf(filename, sizeof(filename), "*/* 0 %s/interfaces/%s", ServerRoot, p->name); AddPrinterFilter(p, filename); } else if (strncmp(p->device_uri, "ipp://", 6) == 0 && (strstr(p->device_uri, "/printers/") != NULL || strstr(p->device_uri, "/classes/") != NULL)) { /* * Tell the client this is really a hard-wired remote printer. */ printer_type |= CUPS_PRINTER_REMOTE; /* * 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... */ AddPrinterFilter(p, "*/* 0 -"); } 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"); AddPrinterFilter(p, "*/* 0 -"); } } 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_FINISHINGS_NONE); } } /* * Add the CUPS-specific printer-type attribute... */ 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 /* * Write the IRIX printer config and status files... */ write_irix_config(p); write_irix_state(p); #endif /* __sgi */ } /* * 'SetPrinterState()' - Update the current state of a printer. */ void SetPrinterState(printer_t *p, /* I - Printer to change */ ipp_pstate_t s) /* I - New state */ { ipp_pstate_t old_state; /* Old printer state */ /* * Can't set status of remote printers... */ if (p->type & CUPS_PRINTER_REMOTE) return; /* * Set the new state... */ old_state = p->state; p->state = s; p->state_time = time(NULL); if (old_state != s) { p->browse_time = 0; #ifdef __sgi write_irix_state(p); #endif /* __sgi */ } /* * Save the printer configuration if a printer goes from idle or processing * to stopped (or visa-versa)... */ if ((old_state == IPP_PRINTER_STOPPED) != (s == IPP_PRINTER_STOPPED)) SaveAllPrinters(); /* * Check to see if any pending jobs can now be printed... */ CheckJobs(); } /* * 'SortPrinters()' - Sort the printer list when a printer name is changed. */ void SortPrinters(void) { printer_t *current, /* Current printer */ *prev, /* Previous printer */ *next; /* Next printer */ int did_swap; /* Non-zero if we did a swap */ do { for (did_swap = 0, current = Printers, prev = NULL; current != NULL;) if (current->next == NULL) break; else if (strcasecmp(current->name, current->next->name) > 0) { DEBUG_printf(("Swapping %s and %s...\n", current->name, current->next->name)); /* * Need to swap these two printers... */ did_swap = 1; if (prev == NULL) Printers = current->next; else prev->next = current->next; /* * Yes, we can all get a headache from the next bunch of pointer * swapping... */ next = current->next; current->next = next->next; next->next = current; prev = next; } else { prev = current; current = current->next; } } while (did_swap); } /* * 'StopPrinter()' - Stop a printer from printing any jobs... */ void StopPrinter(printer_t *p) /* I - Printer to stop */ { job_t *job; /* Active print job */ 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); } } /* * 'ValidateDest()' - Validate a printer/class destination. */ 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) */ { 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; 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_REMOTE); return (p->name); } return (NULL); } /* * 'write_printcap()' - Write a pseudo-printcap file for older applications * that need it... */ static void write_printcap(void) { FILE *fp; /* printcap file */ printer_t *p; /* Current printer */ /* * See if we have a printcap file; if not, don't bother writing it. */ if (!Printcap[0]) return; /* * Open the printcap file... */ if ((fp = fopen(Printcap, "w")) == NULL) return; /* * Put a comment header at the top so that users will know where the * data has come from... */ fputs("# This file was automatically generated by cupsd(1m) from the\n", fp); fprintf(fp, "# %s/printers.conf file. All changes to this file\n", ServerRoot); fputs("# will be lost.\n", fp); /* * 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) fprintf(fp, "%s:\n", DefaultPrinter->name); for (p = Printers; p != NULL; p = p->next) if (p != DefaultPrinter) fprintf(fp, "%s:\n", 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: */ fputs("_all:all=", fp); for (p = Printers; p != NULL; p = p->next) fprintf(fp, "%s%c", p->name, p->next ? ',' : '\n'); if (DefaultPrinter) fprintf(fp, "_default:use=%s\n", DefaultPrinter->name); for (p = Printers; p != NULL; p = p->next) fprintf(fp, "%s:\\\n" "\t:bsdaddr=%s,%s:\\\n" "\t:description=%s:\n", p->name, ServerName, p->name, p->info); break; } /* * Close the file... */ fclose(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 */ FILE *fp; /* Interface script file */ ipp_attribute_t *attr; /* Attribute 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 = fopen(filename, "w")) != NULL) { fputs("#!/bin/sh\n", fp); 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=MonoPostScript\n", fp); fprintf(fp, "HOSTNAME=%s\n", ServerName); fprintf(fp, "HOSTPRINTER=%s\n", p->name); fclose(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 = fopen(filename, "w")) != NULL) { fputs("/dev/null\n", fp); fclose(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 = fopen(filename, "w")) != NULL) { fputs("#!/bin/sh\n", fp); fprintf(fp, "%s -d %s -o \"$3\"\n", PrintcapGUI, p->name); fclose(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 = fopen(filename, "w")) != NULL) { fprintf(fp, "Printer Class | %s\n", (p->type & CUPS_PRINTER_COLOR) ? "ColorPostScript" : "MonoPostScript"); fprintf(fp, "Printer Model | %s\n", p->make_model); fprintf(fp, "Location Code | %s\n", p->location); fprintf(fp, "Physical Location | %s\n", p->info); fprintf(fp, "Port Path | %s\n", p->device_uri); fprintf(fp, "Config Path | /var/spool/lp/pod/%s.config\n", p->name); fprintf(fp, "Active Status Path | /var/spool/lp/pod/%s.status\n", p->name); fputs("Status Update Wait | 10 seconds\n", fp); fclose(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 */ FILE *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 = fopen(filename, "w")) != NULL) { fprintf(fp, "Operational Status | %s\n", (p->state == IPP_PRINTER_IDLE) ? "Idle" : (p->state == IPP_PRINTER_PROCESSING) ? "Busy" : "Faulted"); fprintf(fp, "Information | 01 00 00 | %s\n", CUPS_SVERSION); fprintf(fp, "Information | 02 00 00 | Device URI: %s\n", p->device_uri); fprintf(fp, "Information | 03 00 00 | %s jobs\n", p->accepting ? "Accepting" : "Not accepting"); fprintf(fp, "Information | 04 00 00 | %s\n", p->state_message); fclose(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 = fopen(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; fputs("#!/bin/sh\n", fp); fprintf(fp, "#Tag %d\n", tag); fclose(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 = fopen(filename, "w")) != NULL) { fprintf(fp, "%s\n", DefaultPrinter->name); fclose(fp); chmod(filename, 0644); chown(filename, User, Group); } } else unlink(filename); } #endif /* __sgi */ /* * End of "$Id: printers.c,v 1.3.2.1 2002/08/23 19:56:30 jlovell Exp $". */