void cupsdSaveAllSubscriptions(void) { int i; /* Looping var */ cups_file_t *fp; /* subscriptions.conf file */ char filename[1024], /* subscriptions.conf filename */ temp[1024]; /* Temporary string */ cupsd_subscription_t *sub; /* Current subscription */ time_t curtime; /* Current time */ struct tm *curdate; /* Current date */ unsigned mask; /* Current event mask */ const char *name; /* Current event name */ int hex; /* Non-zero if we are writing hex data */ /* * Create the subscriptions.conf file... */ snprintf(filename, sizeof(filename), "%s/subscriptions.conf", ServerRoot); if ((fp = cupsdCreateConfFile(filename, ConfigFilePerm)) == NULL) return; cupsdLogMessage(CUPSD_LOG_INFO, "Saving subscriptions.conf..."); /* * Write a small header to the file... */ curtime = time(NULL); curdate = localtime(&curtime); strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate); cupsFilePuts(fp, "# Subscription configuration file for " CUPS_SVERSION "\n"); cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp); cupsFilePrintf(fp, "NextSubscriptionId %d\n", NextSubscriptionId); /* * Write every subscription known to the system... */ for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions); sub; sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions)) { cupsFilePrintf(fp, "<Subscription %d>\n", sub->id); if ((name = cupsdEventName((cupsd_eventmask_t)sub->mask)) != NULL) { /* * Simple event list... */ cupsFilePrintf(fp, "Events %s\n", name); } else { /* * Complex event list... */ cupsFilePuts(fp, "Events"); for (mask = 1; mask < CUPSD_EVENT_ALL; mask <<= 1) if (sub->mask & mask) cupsFilePrintf(fp, " %s", cupsdEventName((cupsd_eventmask_t)mask)); cupsFilePuts(fp, "\n"); } if (sub->owner) cupsFilePrintf(fp, "Owner %s\n", sub->owner); if (sub->recipient) cupsFilePrintf(fp, "Recipient %s\n", sub->recipient); if (sub->job) cupsFilePrintf(fp, "JobId %d\n", sub->job->id); if (sub->dest) cupsFilePrintf(fp, "PrinterName %s\n", sub->dest->name); if (sub->user_data_len > 0) { cupsFilePuts(fp, "UserData "); for (i = 0, hex = 0; i < sub->user_data_len; i ++) { if (sub->user_data[i] < ' ' || sub->user_data[i] > 0x7f || sub->user_data[i] == '<') { if (!hex) { cupsFilePrintf(fp, "<%02X", sub->user_data[i]); hex = 1; } else cupsFilePrintf(fp, "%02X", sub->user_data[i]); } else { if (hex) { cupsFilePrintf(fp, ">%c", sub->user_data[i]); hex = 0; } else cupsFilePutChar(fp, sub->user_data[i]); } } if (hex) cupsFilePuts(fp, ">\n"); else cupsFilePutChar(fp, '\n'); } cupsFilePrintf(fp, "LeaseDuration %d\n", sub->lease); cupsFilePrintf(fp, "Interval %d\n", sub->interval); cupsFilePrintf(fp, "ExpirationTime %ld\n", (long)sub->expire); cupsFilePrintf(fp, "NextEventId %d\n", sub->next_event_id); cupsFilePuts(fp, "</Subscription>\n"); } cupsdCloseCreatedConfFile(fp, filename); }
static void cupsd_send_notification( cupsd_subscription_t *sub, /* I - Subscription object */ cupsd_event_t *event) /* I - Event to send */ { ipp_state_t state; /* IPP event state */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsd_send_notification(sub=%p(%d), event=%p(%s))", sub, sub->id, event, cupsdEventName(event->event)); /* * Allocate the events array as needed... */ if (!sub->events) { sub->events = cupsArrayNew3((cups_array_func_t)NULL, NULL, (cups_ahash_func_t)NULL, 0, (cups_acopy_func_t)NULL, (cups_afree_func_t)cupsd_delete_event); if (!sub->events) { cupsdLogMessage(CUPSD_LOG_CRIT, "Unable to allocate memory for subscription #%d!", sub->id); return; } } /* * Purge an old event as needed... */ if (cupsArrayCount(sub->events) >= MaxEvents) { /* * Purge the oldest event in the cache... */ cupsArrayRemove(sub->events, cupsArrayFirst(sub->events)); sub->first_event_id ++; } /* * Add the event to the subscription. Since the events array is * always MaxEvents in length, and since we will have already * removed an event from the subscription cache if we hit the * event cache limit, we don't need to check for overflow here... */ cupsArrayAdd(sub->events, event); /* * Deliver the event... */ if (sub->recipient) { for (;;) { if (sub->pipe < 0) cupsd_start_notifier(sub); cupsdLogMessage(CUPSD_LOG_DEBUG2, "sub->pipe=%d", sub->pipe); if (sub->pipe < 0) break; event->attrs->state = IPP_IDLE; while ((state = ippWriteFile(sub->pipe, event->attrs)) != IPP_DATA) if (state == IPP_ERROR) break; if (state == IPP_ERROR) { if (errno == EPIPE) { /* * Notifier died, try restarting it... */ cupsdLogMessage(CUPSD_LOG_WARN, "Notifier for subscription %d (%s) went away, " "retrying!", sub->id, sub->recipient); cupsdEndProcess(sub->pid, 0); close(sub->pipe); sub->pipe = -1; continue; } cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to send event for subscription %d (%s)!", sub->id, sub->recipient); } /* * If we get this far, break out of the loop... */ break; } } /* * Bump the event sequence number... */ sub->next_event_id ++; }
int /* O - 1 on success, 0 on error */ translate_messages(cups_array_t *cat, /* I - Message catalog */ const char *lang) /* I - Output language... */ { /* * Google provides a simple translation/language tool for translating * from one language to another. It is far from perfect, however it * can be used to get a basic translation done or update an existing * translation when no other resources are available. * * Translation requests are sent as HTTP POSTs to * "http://translate.google.com/translate_t" with the following form * variables: * * Name Description Value * -------- ---------------------------------- ---------------- * hl Help language? "en" * ie Input encoding "UTF8" * langpair Language pair "en|" + language * oe Output encoding "UTF8" * text Text to translate translation string */ int ret; /* Return value */ _cups_message_t *m; /* Current message */ int tries; /* Number of tries... */ http_t *http; /* HTTP connection */ http_status_t status; /* Status of POST request */ char *idptr, /* Pointer into msgid */ buffer[65536], /* Input/output buffer */ *bufptr, /* Pointer into buffer */ *bufend, /* Pointer to end of buffer */ length[16]; /* Content length */ int bytes; /* Number of bytes read */ /* * Connect to translate.google.com... */ puts("Connecting to translate.google.com..."); if ((http = httpConnect("translate.google.com", 80)) == NULL) { perror("Unable to connect to translate.google.com"); return (0); } /* * Scan the current messages, requesting a translation of any untranslated * messages... */ for (m = (_cups_message_t *)cupsArrayFirst(cat), ret = 1; m; m = (_cups_message_t *)cupsArrayNext(cat)) { /* * Skip messages that are already translated... */ if (m->str && m->str[0]) continue; /* * Encode the form data into the buffer... */ snprintf(buffer, sizeof(buffer), "hl=en&ie=UTF8&langpair=en|%s&oe=UTF8&text=", lang); bufptr = buffer + strlen(buffer); bufend = buffer + sizeof(buffer) - 5; for (idptr = m->id; *idptr && bufptr < bufend; idptr ++) if (*idptr == ' ') *bufptr++ = '+'; else if (*idptr < ' ' || *idptr == '%') { sprintf(bufptr, "%%%02X", *idptr & 255); bufptr += 3; } else if (*idptr != '&') *bufptr++ = *idptr; *bufptr++ = '&'; *bufptr = '\0'; sprintf(length, "%d", (int)(bufptr - buffer)); /* * Send the request... */ printf("\"%s\" = ", m->id); fflush(stdout); tries = 0; do { httpClearFields(http); httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/x-www-form-urlencoded"); httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, length); if (httpPost(http, "/translate_t")) { httpReconnect(http); httpPost(http, "/translate_t"); } httpWrite2(http, buffer, bufptr - buffer); while ((status = httpUpdate(http)) == HTTP_CONTINUE); if (status != HTTP_OK && status != HTTP_ERROR) httpFlush(http); tries ++; } while (status == HTTP_ERROR && tries < 10); if (status == HTTP_OK) { /* * OK, read the translation back... */ bufptr = buffer; bufend = buffer + sizeof(buffer) - 1; while ((bytes = httpRead2(http, bufptr, bufend - bufptr)) > 0) bufptr += bytes; if (bytes < 0) { /* * Read error, abort! */ puts("READ ERROR!"); ret = 0; break; } *bufptr = '\0'; /* * Find the div containing translation */ if ((bufptr = strstr(buffer, "<div id=result_box")) == NULL) { /* * No textarea, abort! */ puts("NO div id=result_box!"); ret = 0; break; } if ((bufptr = strchr(bufptr, '>')) == NULL) { /* * textarea doesn't end, abort! */ puts("DIV SHORT DATA!"); ret = 0; break; } bufptr ++; if ((bufend = strstr(bufptr, "</div>")) == NULL) { /* * textarea doesn't close, abort! */ puts("/DIV SHORT DATA!"); ret = 0; break; } *bufend = '\0'; /* * Copy the translation... */ m->str = strdup(bufptr); /* * Convert character entities to regular chars... */ for (bufptr = strchr(m->str, '&'); bufptr; bufptr = strchr(bufptr + 1, '&')) { if (!strncmp(bufptr, "<", 4)) { *bufptr = '<'; _cups_strcpy(bufptr + 1, bufptr + 4); } else if (!strncmp(bufptr, ">", 4)) { *bufptr = '>'; _cups_strcpy(bufptr + 1, bufptr + 4); } else if (!strncmp(bufptr, "&", 5)) _cups_strcpy(bufptr + 1, bufptr + 5); } printf("\"%s\"\n", m->str); } else if (status == HTTP_ERROR) { printf("NETWORK ERROR (%s)!\n", strerror(httpError(http))); ret = 0; break; } else { printf("HTTP ERROR %d!\n", status); ret = 0; break; } } httpClose(http); return (ret); }
static void write_nodes(const char *path, /* I - File to write */ help_index_t *hi) /* I - Index of files */ { cups_file_t *fp; /* Output file */ int id; /* Current node ID */ help_node_t *node; /* Current help node */ int subnodes; /* Currently in Subnodes for file? */ int needclose; /* Need to close the current node? */ if ((fp = cupsFileOpen(path, "w")) == NULL) { fprintf(stderr, "makedocset: Unable to create %s: %s\n", path, strerror(errno)); exit(1); } cupsFilePuts(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" "<DocSetNodes version=\"1.0\">\n" "<TOC>\n" "<Node id=\"0\">\n" "<Name>CUPS Documentation</Name>\n" "<Path>Documentation/index.html</Path>\n" "</Node>\n"); for (node = (help_node_t *)cupsArrayFirst(hi->nodes), id = 1, subnodes = 0, needclose = 0; node; node = (help_node_t *)cupsArrayNext(hi->nodes), id ++) { if (node->anchor) { if (!subnodes) { cupsFilePuts(fp, "<Subnodes>\n"); subnodes = 1; } cupsFilePrintf(fp, "<Node id=\"%d\">\n" "<Path>Documentation/%s</Path>\n" "<Anchor>%s</Anchor>\n" "<Name>%s</Name>\n" "</Node>\n", id, node->filename, node->anchor, node->text); } else { if (subnodes) { cupsFilePuts(fp, "</Subnodes>\n"); subnodes = 0; } if (needclose) cupsFilePuts(fp, "</Node>\n"); cupsFilePrintf(fp, "<Node id=\"%d\">\n" "<Path>Documentation/%s</Path>\n" "<Name>%s</Name>\n", id, node->filename, node->text); needclose = 1; } } if (subnodes) cupsFilePuts(fp, "</Subnodes>\n"); if (needclose) cupsFilePuts(fp, "</Node>\n"); cupsFilePuts(fp, "</TOC>\n" "</DocSetNodes>\n"); cupsFileClose(fp); }
int /* O - Exit status */ main(int argc, /* I - Number of command-line arguments */ char *argv[]) /* I - Command-line arguments */ { int i; /* Looping var */ ipp_t *event; /* Event from scheduler */ ipp_state_t state; /* IPP event state */ char scheme[32], /* URI scheme ("rss") */ username[256], /* Username for remote RSS */ host[1024], /* Hostname for remote RSS */ resource[1024], /* RSS file */ *options; /* Options */ int port, /* Port number for remote RSS */ max_events; /* Maximum number of events */ http_t *http; /* Connection to remote server */ http_status_t status; /* HTTP GET/PUT status code */ char filename[1024], /* Local filename */ newname[1024]; /* filename.N */ cups_lang_t *language; /* Language information */ ipp_attribute_t *printer_up_time, /* Timestamp on event */ *notify_sequence_number,/* Sequence number */ *notify_printer_uri; /* Printer URI */ char *subject, /* Subject for notification message */ *text, /* Text for notification message */ link_url[1024], /* Link to printer */ link_scheme[32], /* Scheme for link */ link_username[256], /* Username for link */ link_host[1024], /* Host for link */ link_resource[1024]; /* Resource for link */ int link_port; /* Link port */ cups_array_t *rss; /* RSS message array */ _cups_rss_t *msg; /* RSS message */ char baseurl[1024]; /* Base URL */ fd_set input; /* Input set for select() */ struct timeval timeout; /* Timeout for select() */ int changed; /* Has the RSS data changed? */ int exit_status; /* Exit status */ fprintf(stderr, "DEBUG: argc=%d\n", argc); for (i = 0; i < argc; i ++) fprintf(stderr, "DEBUG: argv[%d]=\"%s\"\n", i, argv[i]); /* * See whether we are publishing this RSS feed locally or remotely... */ if (httpSeparateURI(HTTP_URI_CODING_ALL, argv[1], scheme, sizeof(scheme), username, sizeof(username), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_OK) { fprintf(stderr, "ERROR: Bad RSS URI \"%s\"!\n", argv[1]); return (1); } max_events = 20; if ((options = strchr(resource, '?')) != NULL) { *options++ = '\0'; if (!strncmp(options, "max_events=", 11)) { max_events = atoi(options + 11); if (max_events <= 0) max_events = 20; } } rss = cupsArrayNew((cups_array_func_t)compare_rss, NULL); if (host[0]) { /* * Remote feed, see if we can get the current file... */ int fd; /* Temporary file */ if ((rss_password = strchr(username, ':')) != NULL) *rss_password++ = '\0'; cupsSetPasswordCB(password_cb); cupsSetUser(username); if ((fd = cupsTempFd(filename, sizeof(filename))) < 0) { fprintf(stderr, "ERROR: Unable to create temporary file: %s\n", strerror(errno)); return (1); } if ((http = httpConnect(host, port)) == NULL) { fprintf(stderr, "ERROR: Unable to connect to %s on port %d: %s\n", host, port, strerror(errno)); close(fd); unlink(filename); return (1); } status = cupsGetFd(http, resource, fd); close(fd); if (status != HTTP_OK && status != HTTP_NOT_FOUND) { fprintf(stderr, "ERROR: Unable to GET %s from %s on port %d: %d %s\n", resource, host, port, status, httpStatus(status)); httpClose(http); unlink(filename); return (1); } strlcpy(newname, filename, sizeof(newname)); httpAssembleURI(HTTP_URI_CODING_ALL, baseurl, sizeof(baseurl), "http", NULL, host, port, resource); } else { const char *cachedir, /* CUPS_CACHEDIR */ *server_name, /* SERVER_NAME */ *server_port; /* SERVER_PORT */ http = NULL; if ((cachedir = getenv("CUPS_CACHEDIR")) == NULL) cachedir = CUPS_CACHEDIR; if ((server_name = getenv("SERVER_NAME")) == NULL) server_name = "localhost"; if ((server_port = getenv("SERVER_PORT")) == NULL) server_port = "631"; snprintf(filename, sizeof(filename), "%s/rss%s", cachedir, resource); snprintf(newname, sizeof(newname), "%s.N", filename); httpAssembleURIf(HTTP_URI_CODING_ALL, baseurl, sizeof(baseurl), "http", NULL, server_name, atoi(server_port), "/rss%s", resource); } /* * Load the previous RSS file, if any... */ load_rss(rss, filename); changed = cupsArrayCount(rss) == 0; /* * Localize for the user's chosen language... */ language = cupsLangDefault(); /* * Read events and update the RSS file until we are out of events. */ for (exit_status = 0, event = NULL;;) { if (changed) { /* * Save the messages to the file again, uploading as needed... */ if (save_rss(rss, newname, baseurl)) { if (http) { /* * Upload the RSS file... */ if ((status = cupsPutFile(http, resource, filename)) != HTTP_CREATED) fprintf(stderr, "ERROR: Unable to PUT %s from %s on port %d: %d %s\n", resource, host, port, status, httpStatus(status)); } else { /* * Move the new RSS file over top the old one... */ if (rename(newname, filename)) fprintf(stderr, "ERROR: Unable to rename %s to %s: %s\n", newname, filename, strerror(errno)); } changed = 0; } } /* * Wait up to 30 seconds for an event... */ timeout.tv_sec = 30; timeout.tv_usec = 0; FD_ZERO(&input); FD_SET(0, &input); if (select(1, &input, NULL, NULL, &timeout) < 0) continue; else if (!FD_ISSET(0, &input)) { fprintf(stderr, "DEBUG: %s is bored, exiting...\n", argv[1]); break; } /* * Read the next event... */ event = ippNew(); while ((state = ippReadFile(0, event)) != IPP_DATA) { if (state <= IPP_IDLE) break; } if (state == IPP_ERROR) fputs("DEBUG: ippReadFile() returned IPP_ERROR!\n", stderr); if (state <= IPP_IDLE) break; /* * Collect the info from the event... */ printer_up_time = ippFindAttribute(event, "printer-up-time", IPP_TAG_INTEGER); notify_sequence_number = ippFindAttribute(event, "notify-sequence-number", IPP_TAG_INTEGER); notify_printer_uri = ippFindAttribute(event, "notify-printer-uri", IPP_TAG_URI); subject = cupsNotifySubject(language, event); text = cupsNotifyText(language, event); if (printer_up_time && notify_sequence_number && subject && text) { /* * Create a new RSS message... */ if (notify_printer_uri) { httpSeparateURI(HTTP_URI_CODING_ALL, notify_printer_uri->values[0].string.text, link_scheme, sizeof(link_scheme), link_username, sizeof(link_username), link_host, sizeof(link_host), &link_port, link_resource, sizeof(link_resource)); httpAssembleURI(HTTP_URI_CODING_ALL, link_url, sizeof(link_url), "http", link_username, link_host, link_port, link_resource); } msg = new_message(notify_sequence_number->values[0].integer, xml_escape(subject), xml_escape(text), notify_printer_uri ? xml_escape(link_url) : NULL, printer_up_time->values[0].integer); if (!msg) { fprintf(stderr, "ERROR: Unable to create message: %s\n", strerror(errno)); exit_status = 1; break; } /* * Add it to the array... */ cupsArrayAdd(rss, msg); changed = 1; /* * Trim the array as needed... */ while (cupsArrayCount(rss) > max_events) { msg = cupsArrayFirst(rss); cupsArrayRemove(rss, msg); delete_message(msg); } } if (subject) free(subject); if (text) free(text); ippDelete(event); event = NULL; } /* * We only get here when idle or error... */ ippDelete(event); if (http) { unlink(filename); httpClose(http); } return (exit_status); }
char * /* O - String containing option code or @code NULL@ if there is no option code */ ppdEmitString(ppd_file_t *ppd, /* I - PPD file record */ ppd_section_t section, /* I - Section to write */ float min_order) /* I - Lowest OrderDependency */ { int i, j, /* Looping vars */ count; /* Number of choices */ ppd_choice_t **choices; /* Choices */ ppd_size_t *size; /* Custom page size */ ppd_coption_t *coption; /* Custom option */ ppd_cparam_t *cparam; /* Custom parameter */ size_t bufsize; /* Size of string buffer needed */ char *buffer, /* String buffer */ *bufptr, /* Pointer into buffer */ *bufend; /* End of buffer */ struct lconv *loc; /* Locale data */ DEBUG_printf(("ppdEmitString(ppd=%p, section=%d, min_order=%f)", ppd, section, min_order)); /* * Range check input... */ if (!ppd) return (NULL); /* * Use PageSize or PageRegion as required... */ ppd_handle_media(ppd); /* * Collect the options we need to emit... */ if ((count = ppdCollect2(ppd, section, min_order, &choices)) == 0) return (NULL); /* * Count the number of bytes that are required to hold all of the * option code... */ for (i = 0, bufsize = 1; i < count; i ++) { if (section == PPD_ORDER_JCL) { if (!_cups_strcasecmp(choices[i]->choice, "Custom") && (coption = ppdFindCustomOption(ppd, choices[i]->option->keyword)) != NULL) { /* * Add space to account for custom parameter substitution... */ for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params); cparam; cparam = (ppd_cparam_t *)cupsArrayNext(coption->params)) { switch (cparam->type) { case PPD_CUSTOM_CURVE : case PPD_CUSTOM_INVCURVE : case PPD_CUSTOM_POINTS : case PPD_CUSTOM_REAL : case PPD_CUSTOM_INT : bufsize += 10; break; case PPD_CUSTOM_PASSCODE : case PPD_CUSTOM_PASSWORD : case PPD_CUSTOM_STRING : if (cparam->current.custom_string) bufsize += strlen(cparam->current.custom_string); break; } } } } else if (section != PPD_ORDER_EXIT) { bufsize += 3; /* [{\n */ if ((!_cups_strcasecmp(choices[i]->option->keyword, "PageSize") || !_cups_strcasecmp(choices[i]->option->keyword, "PageRegion")) && !_cups_strcasecmp(choices[i]->choice, "Custom")) { DEBUG_puts("2ppdEmitString: Custom size set!"); bufsize += 37; /* %%BeginFeature: *CustomPageSize True\n */ bufsize += 50; /* Five 9-digit numbers + newline */ } else if (!_cups_strcasecmp(choices[i]->choice, "Custom") && (coption = ppdFindCustomOption(ppd, choices[i]->option->keyword)) != NULL) { bufsize += 23 + strlen(choices[i]->option->keyword) + 6; /* %%BeginFeature: *Customkeyword True\n */ for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params); cparam; cparam = (ppd_cparam_t *)cupsArrayNext(coption->params)) { switch (cparam->type) { case PPD_CUSTOM_CURVE : case PPD_CUSTOM_INVCURVE : case PPD_CUSTOM_POINTS : case PPD_CUSTOM_REAL : case PPD_CUSTOM_INT : bufsize += 10; break; case PPD_CUSTOM_PASSCODE : case PPD_CUSTOM_PASSWORD : case PPD_CUSTOM_STRING : bufsize += 3; if (cparam->current.custom_string) bufsize += 4 * strlen(cparam->current.custom_string); break; } } } else bufsize += 17 + strlen(choices[i]->option->keyword) + 1 + strlen(choices[i]->choice) + 1; /* %%BeginFeature: *keyword choice\n */ bufsize += 13; /* %%EndFeature\n */ bufsize += 22; /* } stopped cleartomark\n */ } if (choices[i]->code) bufsize += strlen(choices[i]->code) + 1; else bufsize += strlen(ppd_custom_code); } /* * Allocate memory... */ DEBUG_printf(("2ppdEmitString: Allocating %d bytes for string...", (int)bufsize)); if ((buffer = calloc(1, bufsize)) == NULL) { free(choices); return (NULL); } bufend = buffer + bufsize - 1; //loc = localeconv(); /* * Copy the option code to the buffer... */ for (i = 0, bufptr = buffer; i < count; i ++, bufptr += strlen(bufptr)) if (section == PPD_ORDER_JCL) { if (!_cups_strcasecmp(choices[i]->choice, "Custom") && choices[i]->code && (coption = ppdFindCustomOption(ppd, choices[i]->option->keyword)) != NULL) { /* * Handle substitutions in custom JCL options... */ char *cptr; /* Pointer into code */ int pnum; /* Parameter number */ for (cptr = choices[i]->code; *cptr && bufptr < bufend;) { if (*cptr == '\\') { cptr ++; if (isdigit(*cptr & 255)) { /* * Substitute parameter... */ pnum = *cptr++ - '0'; while (isdigit(*cptr & 255)) pnum = pnum * 10 + *cptr++ - '0'; for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params); cparam; cparam = (ppd_cparam_t *)cupsArrayNext(coption->params)) if (cparam->order == pnum) break; if (cparam) { switch (cparam->type) { case PPD_CUSTOM_CURVE : case PPD_CUSTOM_INVCURVE : case PPD_CUSTOM_POINTS : case PPD_CUSTOM_REAL : bufptr = _cupsStrFormatd(bufptr, bufend, cparam->current.custom_real, loc); break; case PPD_CUSTOM_INT : snprintf(bufptr, bufend - bufptr, "%d", cparam->current.custom_int); bufptr += strlen(bufptr); break; case PPD_CUSTOM_PASSCODE : case PPD_CUSTOM_PASSWORD : case PPD_CUSTOM_STRING : if (cparam->current.custom_string) { strlcpy(bufptr, cparam->current.custom_string, bufend - bufptr); bufptr += strlen(bufptr); } break; } } } else if (*cptr) *bufptr++ = *cptr++; } else *bufptr++ = *cptr++; } } else { /* * Otherwise just copy the option code directly... */ strlcpy(bufptr, choices[i]->code, bufend - bufptr + 1); bufptr += strlen(bufptr); } } else if (section != PPD_ORDER_EXIT) { /* * Add wrapper commands to prevent printer errors for unsupported * options... */ strlcpy(bufptr, "[{\n", bufend - bufptr + 1); bufptr += 3; /* * Send DSC comments with option... */ DEBUG_printf(("2ppdEmitString: Adding code for %s=%s...", choices[i]->option->keyword, choices[i]->choice)); if ((!_cups_strcasecmp(choices[i]->option->keyword, "PageSize") || !_cups_strcasecmp(choices[i]->option->keyword, "PageRegion")) && !_cups_strcasecmp(choices[i]->choice, "Custom")) { /* * Variable size; write out standard size options, using the * parameter positions defined in the PPD file... */ ppd_attr_t *attr; /* PPD attribute */ int pos, /* Position of custom value */ orientation; /* Orientation to use */ float values[5]; /* Values for custom command */ strlcpy(bufptr, "%%BeginFeature: *CustomPageSize True\n", bufend - bufptr + 1); bufptr += 37; size = ppdPageSize(ppd, "Custom"); memset(values, 0, sizeof(values)); if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Width")) != NULL) { pos = atoi(attr->value) - 1; if (pos < 0 || pos > 4) pos = 0; } else pos = 0; values[pos] = size->width; if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Height")) != NULL) { pos = atoi(attr->value) - 1; if (pos < 0 || pos > 4) pos = 1; } else pos = 1; values[pos] = size->length; /* * According to the Adobe PPD specification, an orientation of 1 * will produce a print that comes out upside-down with the X * axis perpendicular to the direction of feed, which is exactly * what we want to be consistent with non-PS printers. * * We could also use an orientation of 3 to produce output that * comes out rightside-up (this is the default for many large format * printer PPDs), however for consistency we will stick with the * value 1. * * If we wanted to get fancy, we could use orientations of 0 or * 2 and swap the width and length, however we don't want to get * fancy, we just want it to work consistently. * * The orientation value is range limited by the Orientation * parameter definition, so certain non-PS printer drivers that * only support an Orientation of 0 will get the value 0 as * expected. */ orientation = 1; if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Orientation")) != NULL) { int min_orient, max_orient; /* Minimum and maximum orientations */ if (sscanf(attr->value, "%d%*s%d%d", &pos, &min_orient, &max_orient) != 3) pos = 4; else { pos --; if (pos < 0 || pos > 4) pos = 4; if (orientation > max_orient) orientation = max_orient; else if (orientation < min_orient) orientation = min_orient; } } else pos = 4; values[pos] = (float)orientation; for (pos = 0; pos < 5; pos ++) { bufptr = _cupsStrFormatd(bufptr, bufend, values[pos], loc); *bufptr++ = '\n'; } if (!choices[i]->code) { /* * This can happen with certain buggy PPD files that don't include * a CustomPageSize command sequence... We just use a generic * Level 2 command sequence... */ strlcpy(bufptr, ppd_custom_code, bufend - bufptr + 1); bufptr += strlen(bufptr); } } else if (!_cups_strcasecmp(choices[i]->choice, "Custom") && (coption = ppdFindCustomOption(ppd, choices[i]->option->keyword)) != NULL) { /* * Custom option... */ const char *s; /* Pointer into string value */ cups_array_t *params; /* Parameters in the correct output order */ params = cupsArrayNew((cups_array_func_t)ppd_compare_cparams, NULL); for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params); cparam; cparam = (ppd_cparam_t *)cupsArrayNext(coption->params)) cupsArrayAdd(params, cparam); snprintf(bufptr, bufend - bufptr + 1, "%%%%BeginFeature: *Custom%s True\n", coption->keyword); bufptr += strlen(bufptr); for (cparam = (ppd_cparam_t *)cupsArrayFirst(params); cparam; cparam = (ppd_cparam_t *)cupsArrayNext(params)) { switch (cparam->type) { case PPD_CUSTOM_CURVE : case PPD_CUSTOM_INVCURVE : case PPD_CUSTOM_POINTS : case PPD_CUSTOM_REAL : bufptr = _cupsStrFormatd(bufptr, bufend, cparam->current.custom_real, loc); *bufptr++ = '\n'; break; case PPD_CUSTOM_INT : snprintf(bufptr, bufend - bufptr + 1, "%d\n", cparam->current.custom_int); bufptr += strlen(bufptr); break; case PPD_CUSTOM_PASSCODE : case PPD_CUSTOM_PASSWORD : case PPD_CUSTOM_STRING : *bufptr++ = '('; if (cparam->current.custom_string) { for (s = cparam->current.custom_string; *s; s ++) { if (*s < ' ' || *s == '(' || *s == ')' || *s >= 127) { snprintf(bufptr, bufend - bufptr + 1, "\\%03o", *s & 255); bufptr += strlen(bufptr); } else *bufptr++ = *s; } } *bufptr++ = ')'; *bufptr++ = '\n'; break; } } cupsArrayDelete(params); } else { snprintf(bufptr, bufend - bufptr + 1, "%%%%BeginFeature: *%s %s\n", choices[i]->option->keyword, choices[i]->choice); bufptr += strlen(bufptr); } if (choices[i]->code && choices[i]->code[0]) { j = (int)strlen(choices[i]->code); memcpy(bufptr, choices[i]->code, j); bufptr += j; if (choices[i]->code[j - 1] != '\n') *bufptr++ = '\n'; } strlcpy(bufptr, "%%EndFeature\n" "} stopped cleartomark\n", bufend - bufptr + 1); bufptr += strlen(bufptr); DEBUG_printf(("2ppdEmitString: Offset in string is %d...", (int)(bufptr - buffer))); } else { strlcpy(bufptr, choices[i]->code, bufend - bufptr + 1); bufptr += strlen(bufptr); } /* * Nul-terminate, free, and return... */ *bufptr = '\0'; free(choices); return (buffer); }
static void probe_device(snmp_cache_t *device) /* I - Device */ { char uri[1024], /* Full device URI */ *uriptr, /* Pointer into URI */ *format; /* Format string for device */ device_uri_t *device_uri; /* Current DeviceURI match */ debug_printf("DEBUG: %.3f Probing %s...\n", run_time(), device->addrname); #ifdef __APPLE__ /* * If the printer supports Bonjour/mDNS, don't report it from the SNMP backend. */ if (!try_connect(&(device->address), device->addrname, 5353)) { debug_printf("DEBUG: %s supports mDNS, not reporting!\n", device->addrname); return; } #endif /* __APPLE__ */ /* * Lookup the device in the match table... */ for (device_uri = (device_uri_t *)cupsArrayFirst(DeviceURIs); device_uri; device_uri = (device_uri_t *)cupsArrayNext(DeviceURIs)) if (device->make_and_model && !regexec(&(device_uri->re), device->make_and_model, 0, NULL, 0)) { /* * Found a match, add the URIs... */ for (format = (char *)cupsArrayFirst(device_uri->uris); format; format = (char *)cupsArrayNext(device_uri->uris)) { for (uriptr = uri; *format && uriptr < (uri + sizeof(uri) - 1);) if (*format == '%' && format[1] == 's') { /* * Insert hostname/address... */ strlcpy(uriptr, device->addrname, sizeof(uri) - (size_t)(uriptr - uri)); uriptr += strlen(uriptr); format += 2; } else *uriptr++ = *format++; *uriptr = '\0'; update_cache(device, uri, NULL, NULL); } return; } /* * Then try the standard ports... */ if (!try_connect(&(device->address), device->addrname, 9100)) { debug_printf("DEBUG: %s supports AppSocket!\n", device->addrname); snprintf(uri, sizeof(uri), "socket://%s", device->addrname); update_cache(device, uri, NULL, NULL); } else if (!try_connect(&(device->address), device->addrname, 515)) { debug_printf("DEBUG: %s supports LPD!\n", device->addrname); snprintf(uri, sizeof(uri), "lpd://%s/", device->addrname); update_cache(device, uri, NULL, NULL); } }
static void dnssdUpdateDNSSDName(int from_callback) /* I - Called from callback? */ { char webif[1024]; /* Web interface share name */ # ifdef __APPLE__ SCDynamicStoreRef sc; /* Context for dynamic store */ CFDictionaryRef btmm; /* Back-to-My-Mac domains */ CFStringEncoding nameEncoding; /* Encoding of computer name */ CFStringRef nameRef; /* Host name CFString */ char nameBuffer[1024]; /* C-string buffer */ # endif /* __APPLE__ */ /* * Only share the web interface and printers when non-local listening is * enabled... */ if (!DNSSDPort) { /* * Get the port we use for registrations. If we are not listening on any * non-local ports, there is no sense sharing local printers via Bonjour... */ cupsd_listener_t *lis; /* Current listening socket */ for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); lis; lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) { if (httpAddrLocalhost(&(lis->address))) continue; DNSSDPort = httpAddrPort(&(lis->address)); break; } } if (!DNSSDPort) return; /* * Get the computer name as a c-string... */ # ifdef __APPLE__ sc = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("cupsd"), NULL, NULL); if (sc) { /* * Get the computer name from the dynamic store... */ cupsdClearString(&DNSSDComputerName); if ((nameRef = SCDynamicStoreCopyComputerName(sc, &nameEncoding)) != NULL) { if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer), kCFStringEncodingUTF8)) { cupsdLogMessage(CUPSD_LOG_DEBUG, "Dynamic store computer name is \"%s\".", nameBuffer); cupsdSetString(&DNSSDComputerName, nameBuffer); } CFRelease(nameRef); } if (!DNSSDComputerName) { /* * Use the ServerName instead... */ cupsdLogMessage(CUPSD_LOG_DEBUG, "Using ServerName \"%s\" as computer name.", ServerName); cupsdSetString(&DNSSDComputerName, ServerName); } if (!DNSSDHostName) { /* * Get the local hostname from the dynamic store... */ if ((nameRef = SCDynamicStoreCopyLocalHostName(sc)) != NULL) { if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer), kCFStringEncodingUTF8)) { cupsdLogMessage(CUPSD_LOG_DEBUG, "Dynamic store host name is \"%s\".", nameBuffer); if (strchr(nameBuffer, '.')) cupsdSetString(&DNSSDHostName, nameBuffer); else cupsdSetStringf(&DNSSDHostName, "%s.local", nameBuffer); cupsdLogMessage(CUPSD_LOG_INFO, "Defaulting to \"DNSSDHostName %s\".", DNSSDHostName); } CFRelease(nameRef); } } if (!DNSSDHostName) { /* * Use the ServerName instead... */ cupsdLogMessage(CUPSD_LOG_DEBUG, "Using ServerName \"%s\" as host name.", ServerName); cupsdSetString(&DNSSDHostName, ServerName); cupsdLogMessage(CUPSD_LOG_INFO, "Defaulting to \"DNSSDHostName %s\".", DNSSDHostName); } /* * Get any Back-to-My-Mac domains and add them as aliases... */ cupsdFreeAliases(DNSSDAlias); DNSSDAlias = NULL; btmm = SCDynamicStoreCopyValue(sc, CFSTR("Setup:/Network/BackToMyMac")); if (btmm && CFGetTypeID(btmm) == CFDictionaryGetTypeID()) { cupsdLogMessage(CUPSD_LOG_DEBUG, "%d Back to My Mac aliases to add.", (int)CFDictionaryGetCount(btmm)); CFDictionaryApplyFunction(btmm, dnssdAddAlias, NULL); } else if (btmm) cupsdLogMessage(CUPSD_LOG_ERROR, "Bad Back to My Mac data in dynamic store!"); else cupsdLogMessage(CUPSD_LOG_DEBUG, "No Back to My Mac aliases to add."); if (btmm) CFRelease(btmm); CFRelease(sc); } else # endif /* __APPLE__ */ # ifdef HAVE_AVAHI if (DNSSDClient) { const char *host_name = avahi_client_get_host_name(DNSSDClient); cupsdSetString(&DNSSDComputerName, host_name ? host_name : ServerName); if (!DNSSDHostName) { const char *host_fqdn = avahi_client_get_host_name_fqdn(DNSSDClient); if (host_fqdn) cupsdSetString(&DNSSDHostName, host_fqdn); else if (strchr(ServerName, '.')) cupsdSetString(&DNSSDHostName, ServerName); else cupsdSetStringf(&DNSSDHostName, "%s.local", ServerName); cupsdLogMessage(CUPSD_LOG_INFO, "Defaulting to \"DNSSDHostName %s\".", DNSSDHostName); } } else # endif /* HAVE_AVAHI */ { cupsdSetString(&DNSSDComputerName, ServerName); if (!DNSSDHostName) { if (strchr(ServerName, '.')) cupsdSetString(&DNSSDHostName, ServerName); else cupsdSetStringf(&DNSSDHostName, "%s.local", ServerName); cupsdLogMessage(CUPSD_LOG_INFO, "Defaulting to \"DNSSDHostName %s\".", DNSSDHostName); } } /* * Then (re)register the web interface if enabled... */ if (BrowseWebIF) { if (DNSSDComputerName) snprintf(webif, sizeof(webif), "CUPS @ %s", DNSSDComputerName); else strlcpy(webif, "CUPS", sizeof(webif)); dnssdDeregisterInstance(&WebIFSrv, from_callback); dnssdRegisterInstance(&WebIFSrv, NULL, webif, "_http._tcp", "_printer", DNSSDPort, NULL, 1, from_callback); } }
int /* O - Exit status */ main(int argc, /* I - Number of command-line arguments */ char *argv[]) /* I - Command-line arguments */ { int i; /* Looping var */ ppd_file_t *ppd; /* PPD file loaded from disk */ int status; /* Status of tests (0 = success, 1 = fail) */ int conflicts; /* Number of conflicts */ char *s; /* String */ char buffer[8192]; /* String buffer */ const char *text, /* Localized text */ *val; /* Option value */ int num_options; /* Number of options */ cups_option_t *options; /* Options */ ppd_size_t minsize, /* Minimum size */ maxsize, /* Maximum size */ *size; /* Current size */ ppd_attr_t *attr; /* Current attribute */ _ppd_cache_t *pc; /* PPD cache */ status = 0; if (argc == 1) { /* * Setup directories for locale stuff... */ if (access("locale", 0)) { mkdir("locale", 0777); mkdir("locale/fr", 0777); symlink("../../../locale/cups_fr.po", "locale/fr/cups_fr.po"); mkdir("locale/zh_TW", 0777); symlink("../../../locale/cups_zh_TW.po", "locale/zh_TW/cups_zh_TW.po"); } putenv("LOCALEDIR=locale"); putenv("SOFTWARE=CUPS"); /* * Do tests with test.ppd... */ fputs("ppdOpenFile(test.ppd): ", stdout); if ((ppd = _ppdOpenFile("test.ppd", _PPD_LOCALIZATION_ALL)) != NULL) puts("PASS"); else { ppd_status_t err; /* Last error in file */ int line; /* Line number in file */ status ++; err = ppdLastError(&line); printf("FAIL (%s on line %d)\n", ppdErrorString(err), line); } fputs("ppdFindAttr(wildcard): ", stdout); if ((attr = ppdFindAttr(ppd, "cupsTest", NULL)) == NULL) { status ++; puts("FAIL (not found)"); } else if (strcmp(attr->name, "cupsTest") || strcmp(attr->spec, "Foo")) { status ++; printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec); } else puts("PASS"); fputs("ppdFindNextAttr(wildcard): ", stdout); if ((attr = ppdFindNextAttr(ppd, "cupsTest", NULL)) == NULL) { status ++; puts("FAIL (not found)"); } else if (strcmp(attr->name, "cupsTest") || strcmp(attr->spec, "Bar")) { status ++; printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec); } else puts("PASS"); fputs("ppdFindAttr(Foo): ", stdout); if ((attr = ppdFindAttr(ppd, "cupsTest", "Foo")) == NULL) { status ++; puts("FAIL (not found)"); } else if (strcmp(attr->name, "cupsTest") || strcmp(attr->spec, "Foo")) { status ++; printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec); } else puts("PASS"); fputs("ppdFindNextAttr(Foo): ", stdout); if ((attr = ppdFindNextAttr(ppd, "cupsTest", "Foo")) != NULL) { status ++; printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec); } else puts("PASS"); fputs("ppdMarkDefaults: ", stdout); ppdMarkDefaults(ppd); if ((conflicts = ppdConflicts(ppd)) == 0) puts("PASS"); else { status ++; printf("FAIL (%d conflicts)\n", conflicts); } fputs("ppdEmitString (defaults): ", stdout); if ((s = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL && !strcmp(s, default_code)) puts("PASS"); else { status ++; printf("FAIL (%d bytes instead of %d)\n", s ? (int)strlen(s) : 0, (int)strlen(default_code)); if (s) puts(s); } if (s) free(s); fputs("ppdEmitString (custom size and string): ", stdout); ppdMarkOption(ppd, "PageSize", "Custom.400x500"); ppdMarkOption(ppd, "StringOption", "{String1=\"value 1\" String2=value(2)}"); if ((s = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL && !strcmp(s, custom_code)) puts("PASS"); else { status ++; printf("FAIL (%d bytes instead of %d)\n", s ? (int)strlen(s) : 0, (int)strlen(custom_code)); if (s) puts(s); } if (s) free(s); /* * Test constraints... */ fputs("cupsGetConflicts(InputSlot=Envelope): ", stdout); ppdMarkOption(ppd, "PageSize", "Letter"); num_options = cupsGetConflicts(ppd, "InputSlot", "Envelope", &options); if (num_options != 2 || (val = cupsGetOption("PageRegion", num_options, options)) == NULL || _cups_strcasecmp(val, "Letter") || (val = cupsGetOption("PageSize", num_options, options)) == NULL || _cups_strcasecmp(val, "Letter")) { printf("FAIL (%d options:", num_options); for (i = 0; i < num_options; i ++) printf(" %s=%s", options[i].name, options[i].value); puts(")"); status ++; } else puts("PASS"); fputs("ppdConflicts(): ", stdout); ppdMarkOption(ppd, "InputSlot", "Envelope"); if ((conflicts = ppdConflicts(ppd)) == 2) puts("PASS (2)"); else { printf("FAIL (%d)\n", conflicts); status ++; } fputs("cupsResolveConflicts(InputSlot=Envelope): ", stdout); num_options = 0; options = NULL; if (!cupsResolveConflicts(ppd, "InputSlot", "Envelope", &num_options, &options)) { puts("FAIL (Unable to resolve)"); status ++; } else if (num_options != 2 || !cupsGetOption("PageSize", num_options, options)) { printf("FAIL (%d options:", num_options); for (i = 0; i < num_options; i ++) printf(" %s=%s", options[i].name, options[i].value); puts(")"); status ++; } else puts("PASS (Resolved by changing PageSize)"); cupsFreeOptions(num_options, options); fputs("cupsResolveConflicts(No option/choice): ", stdout); num_options = 0; options = NULL; if (cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options) && num_options == 1 && !_cups_strcasecmp(options[0].name, "InputSlot") && !_cups_strcasecmp(options[0].value, "Tray")) puts("PASS (Resolved by changing InputSlot)"); else if (num_options > 0) { printf("FAIL (%d options:", num_options); for (i = 0; i < num_options; i ++) printf(" %s=%s", options[i].name, options[i].value); puts(")"); status ++; } else { puts("FAIL (Unable to resolve)"); status ++; } cupsFreeOptions(num_options, options); fputs("ppdInstallableConflict(): ", stdout); if (ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble") && !ppdInstallableConflict(ppd, "Duplex", "None")) puts("PASS"); else if (!ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble")) { puts("FAIL (Duplex=DuplexNoTumble did not conflict)"); status ++; } else { puts("FAIL (Duplex=None conflicted)"); status ++; } /* * ppdPageSizeLimits */ fputs("ppdPageSizeLimits: ", stdout); if (ppdPageSizeLimits(ppd, &minsize, &maxsize)) { if (minsize.width != 36 || minsize.length != 36 || maxsize.width != 1080 || maxsize.length != 86400) { printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, " "expected min=36x36, max=1080x86400)\n", minsize.width, minsize.length, maxsize.width, maxsize.length); status ++; } else puts("PASS"); } else { puts("FAIL (returned 0)"); status ++; } /* * cupsMarkOptions with PWG and IPP size names. */ fputs("cupsMarkOptions(media=iso-a4): ", stdout); num_options = cupsAddOption("media", "iso-a4", 0, &options); cupsMarkOptions(ppd, num_options, options); cupsFreeOptions(num_options, options); size = ppdPageSize(ppd, NULL); if (!size || strcmp(size->name, "A4")) { printf("FAIL (%s)\n", size ? size->name : "unknown"); status ++; } else puts("PASS"); fputs("cupsMarkOptions(media=na_letter_8.5x11in): ", stdout); num_options = cupsAddOption("media", "na_letter_8.5x11in", 0, &options); cupsMarkOptions(ppd, num_options, options); cupsFreeOptions(num_options, options); size = ppdPageSize(ppd, NULL); if (!size || strcmp(size->name, "Letter")) { printf("FAIL (%s)\n", size ? size->name : "unknown"); status ++; } else puts("PASS"); fputs("cupsMarkOptions(media=oe_letter-fullbleed_8.5x11in): ", stdout); num_options = cupsAddOption("media", "oe_letter-fullbleed_8.5x11in", 0, &options); cupsMarkOptions(ppd, num_options, options); cupsFreeOptions(num_options, options); size = ppdPageSize(ppd, NULL); if (!size || strcmp(size->name, "Letter.Fullbleed")) { printf("FAIL (%s)\n", size ? size->name : "unknown"); status ++; } else puts("PASS"); fputs("cupsMarkOptions(media=A4): ", stdout); num_options = cupsAddOption("media", "A4", 0, &options); cupsMarkOptions(ppd, num_options, options); cupsFreeOptions(num_options, options); size = ppdPageSize(ppd, NULL); if (!size || strcmp(size->name, "A4")) { printf("FAIL (%s)\n", size ? size->name : "unknown"); status ++; } else puts("PASS"); /* * Custom sizes... */ fputs("cupsMarkOptions(media=Custom.8x10in): ", stdout); num_options = cupsAddOption("media", "Custom.8x10in", 0, &options); cupsMarkOptions(ppd, num_options, options); cupsFreeOptions(num_options, options); size = ppdPageSize(ppd, NULL); if (!size || strcmp(size->name, "Custom") || size->width != 576 || size->length != 720) { printf("FAIL (%s - %gx%g)\n", size ? size->name : "unknown", size ? size->width : 0.0, size ? size->length : 0.0); status ++; } else puts("PASS"); /* * Test localization... */ fputs("ppdLocalizeIPPReason(text): ", stdout); if (ppdLocalizeIPPReason(ppd, "foo", NULL, buffer, sizeof(buffer)) && !strcmp(buffer, "Foo Reason")) puts("PASS"); else { status ++; printf("FAIL (\"%s\" instead of \"Foo Reason\")\n", buffer); } fputs("ppdLocalizeIPPReason(http): ", stdout); if (ppdLocalizeIPPReason(ppd, "foo", "http", buffer, sizeof(buffer)) && !strcmp(buffer, "http://foo/bar.html")) puts("PASS"); else { status ++; printf("FAIL (\"%s\" instead of \"http://foo/bar.html\")\n", buffer); } fputs("ppdLocalizeIPPReason(help): ", stdout); if (ppdLocalizeIPPReason(ppd, "foo", "help", buffer, sizeof(buffer)) && !strcmp(buffer, "help:anchor='foo'%20bookID=Vendor%20Help")) puts("PASS"); else { status ++; printf("FAIL (\"%s\" instead of \"help:anchor='foo'%%20bookID=Vendor%%20Help\")\n", buffer); } fputs("ppdLocalizeIPPReason(file): ", stdout); if (ppdLocalizeIPPReason(ppd, "foo", "file", buffer, sizeof(buffer)) && !strcmp(buffer, "/help/foo/bar.html")) puts("PASS"); else { status ++; printf("FAIL (\"%s\" instead of \"/help/foo/bar.html\")\n", buffer); } putenv("LANG=fr"); putenv("LC_ALL=fr"); putenv("LC_CTYPE=fr"); putenv("LC_MESSAGES=fr"); fputs("ppdLocalizeIPPReason(fr text): ", stdout); if (ppdLocalizeIPPReason(ppd, "foo", NULL, buffer, sizeof(buffer)) && !strcmp(buffer, "La Long Foo Reason")) puts("PASS"); else { status ++; printf("FAIL (\"%s\" instead of \"La Long Foo Reason\")\n", buffer); } putenv("LANG=zh_TW"); putenv("LC_ALL=zh_TW"); putenv("LC_CTYPE=zh_TW"); putenv("LC_MESSAGES=zh_TW"); fputs("ppdLocalizeIPPReason(zh_TW text): ", stdout); if (ppdLocalizeIPPReason(ppd, "foo", NULL, buffer, sizeof(buffer)) && !strcmp(buffer, "Number 1 Foo Reason")) puts("PASS"); else { status ++; printf("FAIL (\"%s\" instead of \"Number 1 Foo Reason\")\n", buffer); } /* * cupsMarkerName localization... */ putenv("LANG=en"); putenv("LC_ALL=en"); putenv("LC_CTYPE=en"); putenv("LC_MESSAGES=en"); fputs("ppdLocalizeMarkerName(bogus): ", stdout); if ((text = ppdLocalizeMarkerName(ppd, "bogus")) != NULL) { status ++; printf("FAIL (\"%s\" instead of NULL)\n", text); } else puts("PASS"); fputs("ppdLocalizeMarkerName(cyan): ", stdout); if ((text = ppdLocalizeMarkerName(ppd, "cyan")) != NULL && !strcmp(text, "Cyan Toner")) puts("PASS"); else { status ++; printf("FAIL (\"%s\" instead of \"Cyan Toner\")\n", text ? text : "(null)"); } putenv("LANG=fr"); putenv("LC_ALL=fr"); putenv("LC_CTYPE=fr"); putenv("LC_MESSAGES=fr"); fputs("ppdLocalizeMarkerName(fr cyan): ", stdout); if ((text = ppdLocalizeMarkerName(ppd, "cyan")) != NULL && !strcmp(text, "La Toner Cyan")) puts("PASS"); else { status ++; printf("FAIL (\"%s\" instead of \"La Toner Cyan\")\n", text ? text : "(null)"); } putenv("LANG=zh_TW"); putenv("LC_ALL=zh_TW"); putenv("LC_CTYPE=zh_TW"); putenv("LC_MESSAGES=zh_TW"); fputs("ppdLocalizeMarkerName(zh_TW cyan): ", stdout); if ((text = ppdLocalizeMarkerName(ppd, "cyan")) != NULL && !strcmp(text, "Number 1 Cyan Toner")) puts("PASS"); else { status ++; printf("FAIL (\"%s\" instead of \"Number 1 Cyan Toner\")\n", text ? text : "(null)"); } ppdClose(ppd); /* * Test new constraints... */ fputs("ppdOpenFile(test2.ppd): ", stdout); if ((ppd = ppdOpenFile("test2.ppd")) != NULL) puts("PASS"); else { ppd_status_t err; /* Last error in file */ int line; /* Line number in file */ status ++; err = ppdLastError(&line); printf("FAIL (%s on line %d)\n", ppdErrorString(err), line); } fputs("ppdMarkDefaults: ", stdout); ppdMarkDefaults(ppd); if ((conflicts = ppdConflicts(ppd)) == 0) puts("PASS"); else { status ++; printf("FAIL (%d conflicts)\n", conflicts); } fputs("ppdEmitString (defaults): ", stdout); if ((s = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL && !strcmp(s, default2_code)) puts("PASS"); else { status ++; printf("FAIL (%d bytes instead of %d)\n", s ? (int)strlen(s) : 0, (int)strlen(default2_code)); if (s) puts(s); } if (s) free(s); fputs("ppdConflicts(): ", stdout); ppdMarkOption(ppd, "PageSize", "Env10"); ppdMarkOption(ppd, "InputSlot", "Envelope"); ppdMarkOption(ppd, "Quality", "Photo"); if ((conflicts = ppdConflicts(ppd)) == 1) puts("PASS (1)"); else { printf("FAIL (%d)\n", conflicts); status ++; } fputs("cupsResolveConflicts(Quality=Photo): ", stdout); num_options = 0; options = NULL; if (cupsResolveConflicts(ppd, "Quality", "Photo", &num_options, &options)) { printf("FAIL (%d options:", num_options); for (i = 0; i < num_options; i ++) printf(" %s=%s", options[i].name, options[i].value); puts(")"); status ++; } else puts("PASS (Unable to resolve)"); cupsFreeOptions(num_options, options); fputs("cupsResolveConflicts(No option/choice): ", stdout); num_options = 0; options = NULL; if (cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options) && num_options == 1 && !_cups_strcasecmp(options->name, "Quality") && !_cups_strcasecmp(options->value, "Normal")) puts("PASS"); else if (num_options > 0) { printf("FAIL (%d options:", num_options); for (i = 0; i < num_options; i ++) printf(" %s=%s", options[i].name, options[i].value); puts(")"); status ++; } else { puts("FAIL (Unable to resolve!)"); status ++; } cupsFreeOptions(num_options, options); fputs("cupsResolveConflicts(loop test): ", stdout); ppdMarkOption(ppd, "PageSize", "A4"); ppdMarkOption(ppd, "InputSlot", "Tray"); ppdMarkOption(ppd, "Quality", "Photo"); num_options = 0; options = NULL; if (!cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options)) puts("PASS"); else if (num_options > 0) { printf("FAIL (%d options:", num_options); for (i = 0; i < num_options; i ++) printf(" %s=%s", options[i].name, options[i].value); puts(")"); } else puts("FAIL (No conflicts!)"); fputs("ppdInstallableConflict(): ", stdout); if (ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble") && !ppdInstallableConflict(ppd, "Duplex", "None")) puts("PASS"); else if (!ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble")) { puts("FAIL (Duplex=DuplexNoTumble did not conflict)"); status ++; } else { puts("FAIL (Duplex=None conflicted)"); status ++; } /* * ppdPageSizeLimits */ ppdMarkDefaults(ppd); fputs("ppdPageSizeLimits(default): ", stdout); if (ppdPageSizeLimits(ppd, &minsize, &maxsize)) { if (minsize.width != 36 || minsize.length != 36 || maxsize.width != 1080 || maxsize.length != 86400) { printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, " "expected min=36x36, max=1080x86400)\n", minsize.width, minsize.length, maxsize.width, maxsize.length); status ++; } else puts("PASS"); } else { puts("FAIL (returned 0)"); status ++; } ppdMarkOption(ppd, "InputSlot", "Manual"); fputs("ppdPageSizeLimits(InputSlot=Manual): ", stdout); if (ppdPageSizeLimits(ppd, &minsize, &maxsize)) { if (minsize.width != 100 || minsize.length != 100 || maxsize.width != 1000 || maxsize.length != 1000) { printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, " "expected min=100x100, max=1000x1000)\n", minsize.width, minsize.length, maxsize.width, maxsize.length); status ++; } else puts("PASS"); } else { puts("FAIL (returned 0)"); status ++; } ppdMarkOption(ppd, "Quality", "Photo"); fputs("ppdPageSizeLimits(Quality=Photo): ", stdout); if (ppdPageSizeLimits(ppd, &minsize, &maxsize)) { if (minsize.width != 200 || minsize.length != 200 || maxsize.width != 1000 || maxsize.length != 1000) { printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, " "expected min=200x200, max=1000x1000)\n", minsize.width, minsize.length, maxsize.width, maxsize.length); status ++; } else puts("PASS"); } else { puts("FAIL (returned 0)"); status ++; } ppdMarkOption(ppd, "InputSlot", "Tray"); fputs("ppdPageSizeLimits(Quality=Photo): ", stdout); if (ppdPageSizeLimits(ppd, &minsize, &maxsize)) { if (minsize.width != 300 || minsize.length != 300 || maxsize.width != 1080 || maxsize.length != 86400) { printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, " "expected min=300x300, max=1080x86400)\n", minsize.width, minsize.length, maxsize.width, maxsize.length); status ++; } else puts("PASS"); } else { puts("FAIL (returned 0)"); status ++; } } else { const char *filename; /* PPD filename */ struct stat fileinfo; /* File information */ if (!strncmp(argv[1], "-d", 2)) { const char *printer; /* Printer name */ if (argv[1][2]) printer = argv[1] + 2; else if (argv[2]) printer = argv[2]; else { puts("Usage: ./testppd -d printer"); return (1); } filename = cupsGetPPD(printer); if (!filename) { printf("%s: %s\n", printer, cupsLastErrorString()); return (1); } } else filename = argv[1]; if (lstat(filename, &fileinfo)) { printf("%s: %s\n", filename, strerror(errno)); return (1); } if (S_ISLNK(fileinfo.st_mode)) { char realfile[1024]; /* Real file path */ ssize_t realsize; /* Size of real file path */ if ((realsize = readlink(filename, realfile, sizeof(realfile) - 1)) < 0) strlcpy(realfile, "Unknown", sizeof(realfile)); else realfile[realsize] = '\0'; if (stat(realfile, &fileinfo)) printf("%s: symlink to \"%s\", %s\n", filename, realfile, strerror(errno)); else printf("%s: symlink to \"%s\", %ld bytes\n", filename, realfile, (long)fileinfo.st_size); } else printf("%s: regular file, %ld bytes\n", filename, (long)fileinfo.st_size); if ((ppd = ppdOpenFile(filename)) == NULL) { ppd_status_t err; /* Last error in file */ int line; /* Line number in file */ status ++; err = ppdLastError(&line); printf("%s: %s on line %d\n", argv[1], ppdErrorString(err), line); } else { int j, k; /* Looping vars */ ppd_group_t *group; /* Option group */ ppd_option_t *option; /* Option */ ppd_coption_t *coption; /* Custom option */ ppd_cparam_t *cparam; /* Custom parameter */ ppd_const_t *c; /* UIConstraints */ char lang[255], /* LANG environment variable */ lc_all[255], /* LC_ALL environment variable */ lc_ctype[255], /* LC_CTYPE environment variable */ lc_messages[255];/* LC_MESSAGES environment variable */ if (argc > 2) { snprintf(lang, sizeof(lang), "LANG=%s", argv[2]); putenv(lang); snprintf(lc_all, sizeof(lc_all), "LC_ALL=%s", argv[2]); putenv(lc_all); snprintf(lc_ctype, sizeof(lc_ctype), "LC_CTYPE=%s", argv[2]); putenv(lc_ctype); snprintf(lc_messages, sizeof(lc_messages), "LC_MESSAGES=%s", argv[2]); putenv(lc_messages); } ppdLocalize(ppd); ppdMarkDefaults(ppd); if (argc > 3) { text = ppdLocalizeIPPReason(ppd, argv[3], NULL, buffer, sizeof(buffer)); printf("ppdLocalizeIPPReason(%s)=%s\n", argv[3], text ? text : "(null)"); return (text == NULL); } for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++) { printf("%s (%s):\n", group->name, group->text); for (j = group->num_options, option = group->options; j > 0; j --, option ++) { printf(" %s (%s):\n", option->keyword, option->text); for (k = 0; k < option->num_choices; k ++) printf(" - %s%s (%s)\n", option->choices[k].marked ? "*" : "", option->choices[k].choice, option->choices[k].text); if ((coption = ppdFindCustomOption(ppd, option->keyword)) != NULL) { for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params); cparam; cparam = (ppd_cparam_t *)cupsArrayNext(coption->params)) { switch (cparam->type) { case PPD_CUSTOM_CURVE : printf(" %s(%s): PPD_CUSTOM_CURVE (%g to %g)\n", cparam->name, cparam->text, cparam->minimum.custom_curve, cparam->maximum.custom_curve); break; case PPD_CUSTOM_INT : printf(" %s(%s): PPD_CUSTOM_INT (%d to %d)\n", cparam->name, cparam->text, cparam->minimum.custom_int, cparam->maximum.custom_int); break; case PPD_CUSTOM_INVCURVE : printf(" %s(%s): PPD_CUSTOM_INVCURVE (%g to %g)\n", cparam->name, cparam->text, cparam->minimum.custom_invcurve, cparam->maximum.custom_invcurve); break; case PPD_CUSTOM_PASSCODE : printf(" %s(%s): PPD_CUSTOM_PASSCODE (%d to %d)\n", cparam->name, cparam->text, cparam->minimum.custom_passcode, cparam->maximum.custom_passcode); break; case PPD_CUSTOM_PASSWORD : printf(" %s(%s): PPD_CUSTOM_PASSWORD (%d to %d)\n", cparam->name, cparam->text, cparam->minimum.custom_password, cparam->maximum.custom_password); break; case PPD_CUSTOM_POINTS : printf(" %s(%s): PPD_CUSTOM_POINTS (%g to %g)\n", cparam->name, cparam->text, cparam->minimum.custom_points, cparam->maximum.custom_points); break; case PPD_CUSTOM_REAL : printf(" %s(%s): PPD_CUSTOM_REAL (%g to %g)\n", cparam->name, cparam->text, cparam->minimum.custom_real, cparam->maximum.custom_real); break; case PPD_CUSTOM_STRING : printf(" %s(%s): PPD_CUSTOM_STRING (%d to %d)\n", cparam->name, cparam->text, cparam->minimum.custom_string, cparam->maximum.custom_string); break; } } } } } puts("\nSizes:"); for (i = ppd->num_sizes, size = ppd->sizes; i > 0; i --, size ++) printf(" %s = %gx%g, [%g %g %g %g]\n", size->name, size->width, size->length, size->left, size->bottom, size->right, size->top); puts("\nConstraints:"); for (i = ppd->num_consts, c = ppd->consts; i > 0; i --, c ++) printf(" *UIConstraints: *%s %s *%s %s\n", c->option1, c->choice1, c->option2, c->choice2); if (ppd->num_consts == 0) puts(" NO CONSTRAINTS"); puts("\nFilters:"); for (i = 0; i < ppd->num_filters; i ++) printf(" %s\n", ppd->filters[i]); if (ppd->num_filters == 0) puts(" NO FILTERS"); puts("\nAttributes:"); for (attr = (ppd_attr_t *)cupsArrayFirst(ppd->sorted_attrs); attr; attr = (ppd_attr_t *)cupsArrayNext(ppd->sorted_attrs)) printf(" *%s %s/%s: \"%s\"\n", attr->name, attr->spec, attr->text, attr->value ? attr->value : ""); puts("\nPPD Cache:"); if ((pc = _ppdCacheCreateWithPPD(ppd)) == NULL) printf(" Unable to create: %s\n", cupsLastErrorString()); else { _ppdCacheWriteFile(pc, "t.cache", NULL); puts(" Wrote t.cache."); } } if (!strncmp(argv[1], "-d", 2)) unlink(filename); } #ifdef __APPLE__ if (getenv("MallocStackLogging") && getenv("MallocStackLoggingNoCompact")) { char command[1024]; /* malloc_history command */ snprintf(command, sizeof(command), "malloc_history %d -all_by_size", getpid()); fflush(stdout); system(command); } #endif /* __APPLE__ */ ppdClose(ppd); return (status); }
static void scan_devices(int ipv4, /* I - SNMP IPv4 socket */ int ipv6) /* I - SNMP IPv6 socket */ { int fd, /* File descriptor for this address */ busy; /* Are we busy processing something? */ char *address, /* Current address */ *community; /* Current community */ fd_set input; /* Input set for select() */ struct timeval timeout; /* Timeout for select() */ time_t endtime; /* End time for scan */ http_addrlist_t *addrs, /* List of addresses */ *addr; /* Current address */ snmp_cache_t *device; /* Current device */ char temp[1024]; /* Temporary address string */ gettimeofday(&StartTime, NULL); /* * First send all of the broadcast queries... */ for (address = (char *)cupsArrayFirst(Addresses); address; address = (char *)cupsArrayNext(Addresses)) { if (!strcmp(address, "@LOCAL")) addrs = get_interface_addresses(NULL); else if (!strncmp(address, "@IF(", 4)) { char ifname[255]; /* Interface name */ strlcpy(ifname, address + 4, sizeof(ifname)); if (ifname[0]) ifname[strlen(ifname) - 1] = '\0'; addrs = get_interface_addresses(ifname); } else addrs = httpAddrGetList(address, AF_UNSPEC, NULL); if (!addrs) { fprintf(stderr, "ERROR: Unable to scan \"%s\"!\n", address); continue; } for (community = (char *)cupsArrayFirst(Communities); community; community = (char *)cupsArrayNext(Communities)) { debug_printf("DEBUG: Scanning for devices in \"%s\" via \"%s\"...\n", community, address); for (addr = addrs; addr; addr = addr->next) { #ifdef AF_INET6 if (httpAddrFamily(&(addr->addr)) == AF_INET6) fd = ipv6; else #endif /* AF_INET6 */ fd = ipv4; debug_printf("DEBUG: Sending get request to %s...\n", httpAddrString(&(addr->addr), temp, sizeof(temp))); _cupsSNMPWrite(fd, &(addr->addr), CUPS_SNMP_VERSION_1, community, CUPS_ASN1_GET_REQUEST, DEVICE_TYPE, DeviceTypeOID); } } httpAddrFreeList(addrs); } /* * Then read any responses that come in over the next 3 seconds... */ endtime = time(NULL) + MaxRunTime; FD_ZERO(&input); while (time(NULL) < endtime) { timeout.tv_sec = 2; timeout.tv_usec = 0; FD_SET(ipv4, &input); if (ipv6 >= 0) FD_SET(ipv6, &input); fd = ipv4 > ipv6 ? ipv4 : ipv6; if (select(fd + 1, &input, NULL, NULL, &timeout) < 0) { fprintf(stderr, "ERROR: %.3f select() for %d/%d failed: %s\n", run_time(), ipv4, ipv6, strerror(errno)); break; } busy = 0; if (FD_ISSET(ipv4, &input)) { read_snmp_response(ipv4); busy = 1; } if (ipv6 >= 0 && FD_ISSET(ipv6, &input)) { read_snmp_response(ipv6); busy = 1; } if (!busy) { /* * List devices with complete information... */ int sent_something = 0; for (device = (snmp_cache_t *)cupsArrayFirst(Devices); device; device = (snmp_cache_t *)cupsArrayNext(Devices)) if (!device->sent && device->info && device->make_and_model) { if (device->uri) list_device(device); else probe_device(device); device->sent = sent_something = 1; } if (!sent_something) break; } } debug_printf("DEBUG: %.3f Scan complete!\n", run_time()); }
static int /* O - 0 on success, 1 on error */ exec_filters(mime_type_t *srctype, /* I - Source type */ cups_array_t *filters, /* I - Array of filters to run */ const char *infile, /* I - File to filter */ const char *outfile, /* I - File to create */ const char *ppdfile, /* I - PPD file, if any */ const char *printer, /* I - Printer name */ const char *user, /* I - Username */ const char *title, /* I - Job title */ int num_options, /* I - Number of filter options */ cups_option_t *options) /* I - Filter options */ { int i; /* Looping var */ const char *argv[8], /* Command-line arguments */ *envp[15], /* Environment variables */ *temp; /* Temporary string */ char *optstr, /* Filter options */ content_type[1024], /* CONTENT_TYPE */ cups_datadir[1024], /* CUPS_DATADIR */ cups_fontpath[1024], /* CUPS_FONTPATH */ cups_serverbin[1024], /* CUPS_SERVERBIN */ cups_serverroot[1024], /* CUPS_SERVERROOT */ lang[1024], /* LANG */ path[1024], /* PATH */ ppd[1024], /* PPD */ printer_info[255], /* PRINTER_INFO env variable */ printer_location[255], /* PRINTER_LOCATION env variable */ printer_name[255], /* PRINTER env variable */ rip_max_cache[1024], /* RIP_MAX_CACHE */ userenv[1024], /* USER */ program[1024]; /* Program to run */ mime_filter_t *filter, /* Current filter */ *next; /* Next filter */ int current, /* Current filter */ filterfds[2][2], /* Pipes for filters */ pid, /* Process ID of filter */ status, /* Exit status */ retval; /* Return value */ cups_array_t *pids; /* Executed filters array */ mime_filter_t key; /* Search key for filters */ cups_lang_t *language; /* Current language */ cups_dest_t *dest; /* Destination information */ /* * Setup the filter environment and command-line... */ optstr = escape_options(num_options, options); snprintf(content_type, sizeof(content_type), "CONTENT_TYPE=%s/%s", srctype->super, srctype->type); snprintf(cups_datadir, sizeof(cups_datadir), "CUPS_DATADIR=%s", DataDir); snprintf(cups_fontpath, sizeof(cups_fontpath), "CUPS_FONTPATH=%s", FontPath); snprintf(cups_serverbin, sizeof(cups_serverbin), "CUPS_SERVERBIN=%s", ServerBin); snprintf(cups_serverroot, sizeof(cups_serverroot), "CUPS_SERVERROOT=%s", ServerRoot); language = cupsLangDefault(); snprintf(lang, sizeof(lang), "LANG=%s.UTF8", language->language); snprintf(path, sizeof(path), "PATH=%s", Path); if (ppdfile) snprintf(ppd, sizeof(ppd), "PPD=%s", ppdfile); else if ((temp = getenv("PPD")) != NULL) snprintf(ppd, sizeof(ppd), "PPD=%s", temp); else #ifdef __APPLE__ if (!access("/System/Library/Frameworks/ApplicationServices.framework/" "Versions/A/Frameworks/PrintCore.framework/Versions/A/" "Resources/English.lproj/Generic.ppd", 0)) strlcpy(ppd, "PPD=/System/Library/Frameworks/ApplicationServices.framework/" "Versions/A/Frameworks/PrintCore.framework/Versions/A/" "Resources/English.lproj/Generic.ppd", sizeof(ppd)); else strlcpy(ppd, "PPD=/System/Library/Frameworks/ApplicationServices.framework/" "Versions/A/Frameworks/PrintCore.framework/Versions/A/" "Resources/Generic.ppd", sizeof(ppd)); #else snprintf(ppd, sizeof(ppd), "PPD=%s/model/laserjet.ppd", DataDir); #endif /* __APPLE__ */ snprintf(rip_max_cache, sizeof(rip_max_cache), "RIP_MAX_CACHE=%s", RIPCache); snprintf(userenv, sizeof(userenv), "USER=%s", user); if (printer && (dest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, printer, NULL)) != NULL) { if ((temp = cupsGetOption("printer-info", dest->num_options, dest->options)) != NULL) snprintf(printer_info, sizeof(printer_info), "PRINTER_INFO=%s", temp); else snprintf(printer_info, sizeof(printer_info), "PRINTER_INFO=%s", printer); if ((temp = cupsGetOption("printer-location", dest->num_options, dest->options)) != NULL) snprintf(printer_location, sizeof(printer_location), "PRINTER_LOCATION=%s", temp); else strlcpy(printer_location, "PRINTER_LOCATION=Unknown", sizeof(printer_location)); } else { snprintf(printer_info, sizeof(printer_info), "PRINTER_INFO=%s", printer ? printer : "Unknown"); strlcpy(printer_location, "PRINTER_LOCATION=Unknown", sizeof(printer_location)); } snprintf(printer_name, sizeof(printer_name), "PRINTER=%s", printer ? printer : "Unknown"); argv[0] = (char *)printer; argv[1] = "1"; argv[2] = user; argv[3] = title; argv[4] = cupsGetOption("copies", num_options, options); argv[5] = optstr; argv[6] = infile; argv[7] = NULL; if (!argv[4]) argv[4] = "1"; envp[0] = "<CFProcessPath>"; envp[1] = content_type; envp[2] = cups_datadir; envp[3] = cups_fontpath; envp[4] = cups_serverbin; envp[5] = cups_serverroot; envp[6] = lang; envp[7] = path; envp[8] = ppd; envp[9] = printer_info; envp[10] = printer_location; envp[11] = printer_name; envp[12] = rip_max_cache; envp[13] = userenv; envp[14] = NULL; for (i = 0; argv[i]; i ++) fprintf(stderr, "DEBUG: argv[%d]=\"%s\"\n", i, argv[i]); for (i = 0; envp[i]; i ++) fprintf(stderr, "DEBUG: envp[%d]=\"%s\"\n", i, envp[i]); /* * Execute all of the filters... */ pids = cupsArrayNew((cups_array_func_t)compare_pids, NULL); current = 0; filterfds[0][0] = -1; filterfds[0][1] = -1; filterfds[1][0] = -1; filterfds[1][1] = -1; if (!infile) filterfds[0][0] = 0; for (filter = (mime_filter_t *)cupsArrayFirst(filters); filter; filter = next, current = 1 - current) { next = (mime_filter_t *)cupsArrayNext(filters); if (filter->filter[0] == '/') strlcpy(program, filter->filter, sizeof(program)); else snprintf(program, sizeof(program), "%s/filter/%s", ServerBin, filter->filter); if (filterfds[!current][1] > 1) { close(filterfds[1 - current][0]); close(filterfds[1 - current][1]); filterfds[1 - current][0] = -1; filterfds[1 - current][0] = -1; } if (next) open_pipe(filterfds[1 - current]); else if (outfile) { filterfds[1 - current][1] = open(outfile, O_CREAT | O_TRUNC | O_WRONLY, 0666); if (filterfds[1 - current][1] < 0) fprintf(stderr, "ERROR: Unable to create \"%s\" - %s\n", outfile, strerror(errno)); } else filterfds[1 - current][1] = 1; pid = exec_filter(program, (char **)argv, (char **)envp, filterfds[current][0], filterfds[1 - current][1]); if (pid > 0) { fprintf(stderr, "INFO: %s (PID %d) started.\n", filter->filter, pid); filter->cost = pid; cupsArrayAdd(pids, filter); } else break; argv[6] = NULL; } /* * Close remaining pipes... */ if (filterfds[0][1] > 1) { close(filterfds[0][0]); close(filterfds[0][1]); } if (filterfds[1][1] > 1) { close(filterfds[1][0]); close(filterfds[1][1]); } /* * Wait for the children to exit... */ retval = 0; while (cupsArrayCount(pids) > 0) { if ((pid = wait(&status)) < 0) continue; key.cost = pid; if ((filter = (mime_filter_t *)cupsArrayFind(pids, &key)) != NULL) { cupsArrayRemove(pids, filter); if (status) { if (WIFEXITED(status)) fprintf(stderr, "ERROR: %s (PID %d) stopped with status %d\n", filter->filter, pid, WEXITSTATUS(status)); else fprintf(stderr, "ERROR: %s (PID %d) crashed on signal %d\n", filter->filter, pid, WTERMSIG(status)); retval = 1; } else fprintf(stderr, "INFO: %s (PID %d) exited with no errors.\n", filter->filter, pid); } } cupsArrayDelete(pids); return (retval); }
int /* O - Exit status */ main(int argc, /* I - Number of command-line args */ char *argv[]) /* I - Command-line arguments */ { int i; /* Looping vars */ const char *command, /* Command name */ *opt, /* Current option */ *printer; /* Printer name */ mime_type_t *printer_type, /* Printer MIME type */ *prefilter_type; /* Printer prefilter MIME type */ char *srctype, /* Source type */ *dsttype, /* Destination type */ super[MIME_MAX_SUPER], /* Super-type name */ type[MIME_MAX_TYPE]; /* Type name */ int compression; /* Compression of file */ int cost; /* Cost of filters */ mime_t *mime; /* MIME database */ char mimedir[1024]; /* MIME directory */ char *infile, /* File to filter */ *outfile; /* File to create */ char cupsdconf[1024]; /* cupsd.conf file */ const char *server_root; /* CUPS_SERVERROOT environment variable */ mime_type_t *src, /* Source type */ *dst; /* Destination type */ cups_array_t *filters; /* Filters for the file */ int num_options; /* Number of options */ cups_option_t *options; /* Options */ const char *ppdfile; /* PPD file */ const char *title, /* Title string */ *user; /* Username */ int all_filters, /* Use all filters */ removeppd, /* Remove PPD file */ removeinfile; /* Remove input file */ int status; /* Execution status */ /* * Setup defaults... */ if ((command = strrchr(argv[0], '/')) != NULL) command ++; else command = argv[0]; printer = !strcmp(command, "convert") ? "tofile" : "cupsfilter"; mime = NULL; srctype = NULL; compression = 0; dsttype = "application/pdf"; infile = NULL; outfile = NULL; num_options = 0; options = NULL; ppdfile = NULL; title = NULL; user = cupsUser(); all_filters = 0; removeppd = 0; removeinfile = 0; if ((server_root = getenv("CUPS_SERVERROOT")) == NULL) server_root = CUPS_SERVERROOT; snprintf(cupsdconf, sizeof(cupsdconf), "%s/cupsd.conf", server_root); /* * Process command-line arguments... */ _cupsSetLocale(argv); for (i = 1; i < argc; i ++) if (argv[i][0] == '-') { for (opt = argv[i] + 1; *opt; opt ++) switch (*opt) { case '-' : /* Next argument is a filename... */ i ++; if (i < argc && !infile) infile = argv[i]; else usage(opt); break; case 'a' : /* Specify option... */ i ++; if (i < argc) num_options = cupsParseOptions(argv[i], num_options, &options); else usage(opt); break; case 'c' : /* Specify cupsd.conf file location... */ i ++; if (i < argc) { if (!strcmp(command, "convert")) num_options = cupsAddOption("copies", argv[i], num_options, &options); else strlcpy(cupsdconf, argv[i], sizeof(cupsdconf)); } else usage(opt); break; case 'd' : /* Specify the real printer name */ i ++; if (i < argc) printer = argv[i]; else usage(opt); break; case 'D' : /* Delete input file after conversion */ removeinfile = 1; break; case 'e' : /* Use every filter from the PPD file */ all_filters = 1; break; case 'f' : /* Specify input file... */ i ++; if (i < argc && !infile) infile = argv[i]; else usage(opt); break; case 'i' : /* Specify source MIME type... */ i ++; if (i < argc) { if (sscanf(argv[i], "%15[^/]/%255s", super, type) != 2) usage(opt); srctype = argv[i]; } else usage(opt); break; case 'j' : /* Get job file or specify destination MIME type... */ if (strcmp(command, "convert")) { i ++; if (i < argc) { get_job_file(argv[i]); infile = TempFile; } else usage(opt); break; } case 'm' : /* Specify destination MIME type... */ i ++; if (i < argc) { if (sscanf(argv[i], "%15[^/]/%255s", super, type) != 2) usage(opt); dsttype = argv[i]; } else usage(opt); break; case 'n' : /* Specify number of copies... */ i ++; if (i < argc) num_options = cupsAddOption("copies", argv[i], num_options, &options); else usage(opt); break; case 'o' : /* Specify option(s) or output filename */ i ++; if (i < argc) { if (!strcmp(command, "convert")) { if (outfile) usage(NULL); else outfile = argv[i]; } else num_options = cupsParseOptions(argv[i], num_options, &options); } else usage(opt); break; case 'p' : /* Specify PPD file... */ case 'P' : /* Specify PPD file... */ i ++; if (i < argc) ppdfile = argv[i]; else usage(opt); break; case 't' : /* Specify title... */ case 'J' : /* Specify title... */ i ++; if (i < argc) title = argv[i]; else usage(opt); break; case 'u' : /* Delete PPD file after conversion */ removeppd = 1; break; case 'U' : /* Specify username... */ i ++; if (i < argc) user = argv[i]; else usage(opt); break; default : /* Something we don't understand... */ usage(opt); break; } } else if (!infile) { if (strcmp(command, "convert")) infile = argv[i]; else usage(NULL); } else { _cupsLangPuts(stderr, _("cupsfilter: Only one filename can be specified.")); usage(NULL); } if (!infile && !srctype) usage(NULL); if (!title) { if (!infile) title = "(stdin)"; else if ((title = strrchr(infile, '/')) != NULL) title ++; else title = infile; } /* * Load the cupsd.conf file and create the MIME database... */ if (read_cupsd_conf(cupsdconf)) return (1); snprintf(mimedir, sizeof(mimedir), "%s/mime", DataDir); mime = mimeLoadTypes(NULL, mimedir); mime = mimeLoadTypes(mime, ServerRoot); mime = mimeLoadFilters(mime, mimedir, Path); mime = mimeLoadFilters(mime, ServerRoot, Path); if (!mime) { _cupsLangPrintf(stderr, _("%s: Unable to read MIME database from \"%s\" or " "\"%s\"."), command, mimedir, ServerRoot); return (1); } prefilter_type = NULL; if (all_filters) printer_type = add_printer_filters(command, mime, printer, ppdfile, &prefilter_type); else printer_type = mimeType(mime, "application", "vnd.cups-postscript"); /* * Get the source and destination types... */ if (srctype) { sscanf(srctype, "%15[^/]/%255s", super, type); if ((src = mimeType(mime, super, type)) == NULL) { _cupsLangPrintf(stderr, _("%s: Unknown source MIME type %s/%s."), command, super, type); return (1); } } else if ((src = mimeFileType(mime, infile, infile, &compression)) == NULL) { _cupsLangPrintf(stderr, _("%s: Unable to determine MIME type of \"%s\"."), command, infile); return (1); } sscanf(dsttype, "%15[^/]/%255s", super, type); if (!_cups_strcasecmp(super, "printer")) dst = printer_type; else if ((dst = mimeType(mime, super, type)) == NULL) { _cupsLangPrintf(stderr, _("%s: Unknown destination MIME type %s/%s."), command, super, type); return (1); } /* * Figure out how to filter the file... */ if (src == dst) { /* * Special case - no filtering needed... */ filters = cupsArrayNew(NULL, NULL); cupsArrayAdd(filters, &GZIPFilter); GZIPFilter.src = src; GZIPFilter.dst = dst; } else if ((filters = mimeFilter(mime, src, dst, &cost)) == NULL) { _cupsLangPrintf(stderr, _("%s: No filter to convert from %s/%s to %s/%s."), command, src->super, src->type, dst->super, dst->type); return (1); } else if (compression) cupsArrayInsert(filters, &GZIPFilter); if (prefilter_type) { /* * Add pre-filters... */ mime_filter_t *filter, /* Current filter */ *prefilter; /* Current pre-filter */ cups_array_t *prefilters = cupsArrayNew(NULL, NULL); /* New filters array */ for (filter = (mime_filter_t *)cupsArrayFirst(filters); filter; filter = (mime_filter_t *)cupsArrayNext(filters)) { if ((prefilter = mimeFilterLookup(mime, filter->src, prefilter_type)) != NULL) cupsArrayAdd(prefilters, prefilter); cupsArrayAdd(prefilters, filter); } cupsArrayDelete(filters); filters = prefilters; } /* * Do it! */ status = exec_filters(src, filters, infile, outfile, ppdfile, printer, user, title, num_options, options); /* * Remove files as needed, then exit... */ if (TempFile[0]) unlink(TempFile); if (removeppd && ppdfile) unlink(ppdfile); if (removeinfile && infile) unlink(infile); return (status); }
static void ppd_mark_option(ppd_file_t *ppd, /* I - PPD file */ const char *option, /* I - Option name */ const char *choice) /* I - Choice name */ { int i, j; /* Looping vars */ ppd_option_t *o; /* Option pointer */ ppd_choice_t *c, /* Choice pointer */ *oldc, /* Old choice pointer */ key; /* Search key for choice */ struct lconv *loc; /* Locale data */ DEBUG_printf(("7ppd_mark_option(ppd=%p, option=\"%s\", choice=\"%s\")", ppd, option, choice)); /* * AP_D_InputSlot is the "default input slot" on MacOS X, and setting * it clears the regular InputSlot choices... */ if (!_cups_strcasecmp(option, "AP_D_InputSlot")) { cupsArraySave(ppd->options); if ((o = ppdFindOption(ppd, "InputSlot")) != NULL) { key.option = o; if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL) { oldc->marked = 0; cupsArrayRemove(ppd->marked, oldc); } } cupsArrayRestore(ppd->options); } /* * Check for custom options... */ cupsArraySave(ppd->options); o = ppdFindOption(ppd, option); cupsArrayRestore(ppd->options); if (!o) return; //loc = localeconv(); if (!_cups_strncasecmp(choice, "Custom.", 7)) { /* * Handle a custom option... */ if ((c = ppdFindChoice(o, "Custom")) == NULL) return; if (!_cups_strcasecmp(option, "PageSize")) { /* * Handle custom page sizes... */ ppdPageSize(ppd, choice); } else { /* * Handle other custom options... */ ppd_coption_t *coption; /* Custom option */ ppd_cparam_t *cparam; /* Custom parameter */ char *units; /* Custom points units */ if ((coption = ppdFindCustomOption(ppd, option)) != NULL) { if ((cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params)) == NULL) return; switch (cparam->type) { case PPD_CUSTOM_CURVE : case PPD_CUSTOM_INVCURVE : case PPD_CUSTOM_REAL : cparam->current.custom_real = (float)_cupsStrScand(choice + 7, NULL, loc); break; case PPD_CUSTOM_POINTS : cparam->current.custom_points = (float)_cupsStrScand(choice + 7, &units, loc); if (units) { if (!_cups_strcasecmp(units, "cm")) cparam->current.custom_points *= 72.0f / 2.54f; else if (!_cups_strcasecmp(units, "mm")) cparam->current.custom_points *= 72.0f / 25.4f; else if (!_cups_strcasecmp(units, "m")) cparam->current.custom_points *= 72.0f / 0.0254f; else if (!_cups_strcasecmp(units, "in")) cparam->current.custom_points *= 72.0f; else if (!_cups_strcasecmp(units, "ft")) cparam->current.custom_points *= 12.0f * 72.0f; } break; case PPD_CUSTOM_INT : cparam->current.custom_int = atoi(choice + 7); break; case PPD_CUSTOM_PASSCODE : case PPD_CUSTOM_PASSWORD : case PPD_CUSTOM_STRING : if (cparam->current.custom_string) _cupsStrFree(cparam->current.custom_string); cparam->current.custom_string = _cupsStrAlloc(choice + 7); break; } } } /* * Make sure that we keep the option marked below... */ choice = "Custom"; } else if (choice[0] == '{') { /* * Handle multi-value custom options... */ ppd_coption_t *coption; /* Custom option */ ppd_cparam_t *cparam; /* Custom parameter */ char *units; /* Custom points units */ int num_vals; /* Number of values */ cups_option_t *vals, /* Values */ *val; /* Value */ if ((c = ppdFindChoice(o, "Custom")) == NULL) return; if ((coption = ppdFindCustomOption(ppd, option)) != NULL) { num_vals = cupsParseOptions(choice, 0, &vals); for (i = 0, val = vals; i < num_vals; i ++, val ++) { if ((cparam = ppdFindCustomParam(coption, val->name)) == NULL) continue; switch (cparam->type) { case PPD_CUSTOM_CURVE : case PPD_CUSTOM_INVCURVE : case PPD_CUSTOM_REAL : cparam->current.custom_real = (float)_cupsStrScand(val->value, NULL, loc); break; case PPD_CUSTOM_POINTS : cparam->current.custom_points = (float)_cupsStrScand(val->value, &units, loc); if (units) { if (!_cups_strcasecmp(units, "cm")) cparam->current.custom_points *= 72.0f / 2.54f; else if (!_cups_strcasecmp(units, "mm")) cparam->current.custom_points *= 72.0f / 25.4f; else if (!_cups_strcasecmp(units, "m")) cparam->current.custom_points *= 72.0f / 0.0254f; else if (!_cups_strcasecmp(units, "in")) cparam->current.custom_points *= 72.0f; else if (!_cups_strcasecmp(units, "ft")) cparam->current.custom_points *= 12.0f * 72.0f; } break; case PPD_CUSTOM_INT : cparam->current.custom_int = atoi(val->value); break; case PPD_CUSTOM_PASSCODE : case PPD_CUSTOM_PASSWORD : case PPD_CUSTOM_STRING : if (cparam->current.custom_string) _cupsStrFree(cparam->current.custom_string); cparam->current.custom_string = _cupsStrRetain(val->value); break; } } cupsFreeOptions(num_vals, vals); } } else { for (i = o->num_choices, c = o->choices; i > 0; i --, c ++) if (!_cups_strcasecmp(c->choice, choice)) break; if (!i) return; } /* * Option found; mark it and then handle unmarking any other options. */ if (o->ui != PPD_UI_PICKMANY) { /* * Unmark all other choices... */ if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, c)) != NULL) { oldc->marked = 0; cupsArrayRemove(ppd->marked, oldc); } if (!_cups_strcasecmp(option, "PageSize") || !_cups_strcasecmp(option, "PageRegion")) { /* * Mark current page size... */ for (j = 0; j < ppd->num_sizes; j ++) ppd->sizes[j].marked = !_cups_strcasecmp(ppd->sizes[j].name, choice); /* * Unmark the current PageSize or PageRegion setting, as * appropriate... */ cupsArraySave(ppd->options); if (!_cups_strcasecmp(option, "PageSize")) { if ((o = ppdFindOption(ppd, "PageRegion")) != NULL) { key.option = o; if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL) { oldc->marked = 0; cupsArrayRemove(ppd->marked, oldc); } } } else { if ((o = ppdFindOption(ppd, "PageSize")) != NULL) { key.option = o; if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL) { oldc->marked = 0; cupsArrayRemove(ppd->marked, oldc); } } } cupsArrayRestore(ppd->options); } else if (!_cups_strcasecmp(option, "InputSlot")) { /* * Unmark ManualFeed option... */ cupsArraySave(ppd->options); if ((o = ppdFindOption(ppd, "ManualFeed")) != NULL) { key.option = o; if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL) { oldc->marked = 0; cupsArrayRemove(ppd->marked, oldc); } } cupsArrayRestore(ppd->options); } else if (!_cups_strcasecmp(option, "ManualFeed") && !_cups_strcasecmp(choice, "True")) { /* * Unmark InputSlot option... */ cupsArraySave(ppd->options); if ((o = ppdFindOption(ppd, "InputSlot")) != NULL) { key.option = o; if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL) { oldc->marked = 0; cupsArrayRemove(ppd->marked, oldc); } } cupsArrayRestore(ppd->options); } } c->marked = 1; cupsArrayAdd(ppd->marked, c); }
cupsd_subscription_t * /* O - New subscription object */ cupsdAddSubscription( unsigned mask, /* I - Event mask */ cupsd_printer_t *dest, /* I - Printer, if any */ cupsd_job_t *job, /* I - Job, if any */ const char *uri, /* I - notify-recipient-uri, if any */ int sub_id) /* I - notify-subscription-id or 0 */ { cupsd_subscription_t *temp; /* New subscription object */ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAddSubscription(mask=%x, dest=%p(%s), job=%p(%d), " "uri=\"%s\")", mask, dest, dest ? dest->name : "", job, job ? job->id : 0, uri ? uri : "(null)"); if (!Subscriptions) Subscriptions = cupsArrayNew((cups_array_func_t)cupsd_compare_subscriptions, NULL); if (!Subscriptions) { cupsdLogMessage(CUPSD_LOG_CRIT, "Unable to allocate memory for subscriptions - %s", strerror(errno)); return (NULL); } /* * Limit the number of subscriptions... */ if (MaxSubscriptions > 0 && cupsArrayCount(Subscriptions) >= MaxSubscriptions) { cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAddSubscription: Reached MaxSubscriptions %d " "(count=%d)", MaxSubscriptions, cupsArrayCount(Subscriptions)); return (NULL); } if (MaxSubscriptionsPerJob > 0 && job) { int count; /* Number of job subscriptions */ for (temp = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions), count = 0; temp; temp = (cupsd_subscription_t *)cupsArrayNext(Subscriptions)) if (temp->job == job) count ++; if (count >= MaxSubscriptionsPerJob) { cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAddSubscription: Reached MaxSubscriptionsPerJob %d " "for job #%d (count=%d)", MaxSubscriptionsPerJob, job->id, count); return (NULL); } } if (MaxSubscriptionsPerPrinter > 0 && dest) { int count; /* Number of printer subscriptions */ for (temp = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions), count = 0; temp; temp = (cupsd_subscription_t *)cupsArrayNext(Subscriptions)) if (temp->dest == dest) count ++; if (count >= MaxSubscriptionsPerPrinter) { cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAddSubscription: Reached " "MaxSubscriptionsPerPrinter %d for %s (count=%d)", MaxSubscriptionsPerPrinter, dest->name, count); return (NULL); } } /* * Allocate memory for this subscription... */ if ((temp = calloc(1, sizeof(cupsd_subscription_t))) == NULL) { cupsdLogMessage(CUPSD_LOG_CRIT, "Unable to allocate memory for subscription object - %s", strerror(errno)); return (NULL); } /* * Fill in common data... */ if (sub_id) { temp->id = sub_id; if (sub_id >= NextSubscriptionId) NextSubscriptionId = sub_id + 1; } else { temp->id = NextSubscriptionId; NextSubscriptionId ++; } temp->mask = mask; temp->dest = dest; temp->job = job; temp->pipe = -1; temp->first_event_id = 1; temp->next_event_id = 1; cupsdSetString(&(temp->recipient), uri); /* * Add the subscription to the array... */ cupsArrayAdd(Subscriptions, temp); /* * For RSS subscriptions, run the notifier immediately... */ if (uri && !strncmp(uri, "rss:", 4)) cupsd_start_notifier(temp); return (temp); }
cupsd_quota_t * /* O - Quota data */ cupsdUpdateQuota( cupsd_printer_t *p, /* I - Printer */ const char *username, /* I - User */ int pages, /* I - Number of pages */ int k) /* I - Number of kilobytes */ { cupsd_quota_t *q; /* Quota data */ cupsd_job_t *job; /* Current job */ time_t curtime; /* Current time */ ipp_attribute_t *attr; /* Job attribute */ if (!p || !username) return (NULL); if (!p->k_limit && !p->page_limit) return (NULL); if ((q = cupsdFindQuota(p, username)) == NULL) return (NULL); cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdUpdateQuota: p=%s username=%s pages=%d k=%d", p->name, username, pages, k); curtime = time(NULL); if (curtime < q->next_update) { q->page_count += pages; q->k_count += k; return (q); } if (p->quota_period) curtime -= p->quota_period; else curtime = 0; q->next_update = 0; q->page_count = 0; q->k_count = 0; for (job = (cupsd_job_t *)cupsArrayFirst(Jobs); job; job = (cupsd_job_t *)cupsArrayNext(Jobs)) { /* * We only care about the current printer/class and user... */ if (_cups_strcasecmp(job->dest, p->name) != 0 || _cups_strcasecmp(job->username, q->username) != 0) continue; /* * Make sure attributes are loaded; we always call cupsdLoadJob() to ensure * the access_time member is updated so the job isn't unloaded right away... */ if (!cupsdLoadJob(job)) continue; if ((attr = ippFindAttribute(job->attrs, "time-at-completion", IPP_TAG_INTEGER)) == NULL) if ((attr = ippFindAttribute(job->attrs, "time-at-processing", IPP_TAG_INTEGER)) == NULL) attr = ippFindAttribute(job->attrs, "time-at-creation", IPP_TAG_INTEGER); if (attr->values[0].integer < curtime) { /* * This job is too old to count towards the quota, ignore it... */ if (JobAutoPurge && !job->printer && job->state_value > IPP_JOB_STOPPED) cupsdDeleteJob(job, CUPSD_JOB_PURGE); continue; } if (q->next_update == 0) q->next_update = attr->values[0].integer + p->quota_period; if ((attr = ippFindAttribute(job->attrs, "job-media-sheets-completed", IPP_TAG_INTEGER)) != NULL) q->page_count += attr->values[0].integer; if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL) q->k_count += attr->values[0].integer; } return (q); }
void cupsdAddEvent( cupsd_eventmask_t event, /* I - Event */ cupsd_printer_t *dest, /* I - Printer associated with event */ cupsd_job_t *job, /* I - Job associated with event */ const char *text, /* I - Notification text */ ...) /* I - Additional arguments as needed */ { va_list ap; /* Pointer to additional arguments */ char ftext[1024]; /* Formatted text buffer */ ipp_attribute_t *attr; /* Printer/job attribute */ cupsd_event_t *temp; /* New event pointer */ cupsd_subscription_t *sub; /* Current subscription */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddEvent(event=%s, dest=%p(%s), job=%p(%d), text=\"%s\", ...)", cupsdEventName(event), dest, dest ? dest->name : "", job, job ? job->id : 0, text); /* * Keep track of events with any OS-supplied notification mechanisms... */ LastEvent |= event; #ifdef HAVE_DBUS cupsd_send_dbus(event, dest, job); #endif /* HAVE_DBUS */ /* * Return if we aren't keeping events... */ if (MaxEvents <= 0) { cupsdLogMessage(CUPSD_LOG_WARN, "cupsdAddEvent: Discarding %s event since MaxEvents is %d!", cupsdEventName(event), MaxEvents); return; } /* * Then loop through the subscriptions and add the event to the corresponding * caches... */ for (temp = NULL, sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions); sub; sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions)) { /* * Check if this subscription requires this event... */ if ((sub->mask & event) != 0 && (sub->dest == dest || !sub->dest) && (sub->job == job || !sub->job)) { /* * Need this event, so create a new event record... */ if ((temp = (cupsd_event_t *)calloc(1, sizeof(cupsd_event_t))) == NULL) { cupsdLogMessage(CUPSD_LOG_CRIT, "Unable to allocate memory for event - %s", strerror(errno)); return; } temp->event = event; temp->time = time(NULL); temp->attrs = ippNew(); temp->job = job; if (dest) temp->dest = dest; else if (job) temp->dest = dest = cupsdFindPrinter(job->dest); /* * Add common event notification attributes... */ ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_CHARSET, "notify-charset", NULL, "utf-8"); ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_LANGUAGE, "notify-natural-language", NULL, "en-US"); ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER, "notify-subscription-id", sub->id); ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER, "notify-sequence-number", sub->next_event_id); ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD, "notify-subscribed-event", NULL, cupsdEventName(event)); if (sub->user_data_len > 0) ippAddOctetString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, "notify-user-data", sub->user_data, sub->user_data_len); ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER, "printer-up-time", time(NULL)); va_start(ap, text); vsnprintf(ftext, sizeof(ftext), text, ap); va_end(ap); ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_TEXT, "notify-text", NULL, ftext); if (dest) { /* * Add printer attributes... */ ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_URI, "notify-printer-uri", NULL, dest->uri); ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_NAME, "printer-name", NULL, dest->name); ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_ENUM, "printer-state", dest->state); if (dest->num_reasons == 0) ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD, "printer-state-reasons", NULL, dest->state == IPP_PRINTER_STOPPED ? "paused" : "none"); else ippAddStrings(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD, "printer-state-reasons", dest->num_reasons, NULL, (const char * const *)dest->reasons); ippAddBoolean(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, "printer-is-accepting-jobs", dest->accepting); } if (job) { /* * Add job attributes... */ ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER, "notify-job-id", job->id); ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_ENUM, "job-state", job->state_value); if ((attr = ippFindAttribute(job->attrs, "job-name", IPP_TAG_NAME)) != NULL) ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_NAME, "job-name", NULL, attr->values[0].string.text); switch (job->state_value) { case IPP_JOB_PENDING : if (dest && dest->state == IPP_PRINTER_STOPPED) ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "printer-stopped"); else ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "none"); break; case IPP_JOB_HELD : if (ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_KEYWORD) != NULL || ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME) != NULL) ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "job-hold-until-specified"); else ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "job-incoming"); break; case IPP_JOB_PROCESSING : ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "job-printing"); break; case IPP_JOB_STOPPED : ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "job-stopped"); break; case IPP_JOB_CANCELED : ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "job-canceled-by-user"); break; case IPP_JOB_ABORTED : ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "aborted-by-system"); break; case IPP_JOB_COMPLETED : ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "job-completed-successfully"); break; } ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER, "job-impressions-completed", job->sheets ? job->sheets->values[0].integer : 0); } /* * Send the notification for this subscription... */ cupsd_send_notification(sub, temp); } } if (temp) cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS); else cupsdLogMessage(CUPSD_LOG_DEBUG, "Discarding unused %s event...", cupsdEventName(event)); }
static void mime_load_convs( mime_t *mime, /* I - MIME database */ const char *filename, /* I - Convs file to load */ const char *filterpath, /* I - Path for filters */ cups_array_t *filtercache) /* I - Filter program cache */ { cups_file_t *fp; /* Convs file */ char line[1024], /* Input line from file */ *lineptr, /* Current position in line */ super[MIME_MAX_SUPER], /* Super-type name */ type[MIME_MAX_TYPE], /* Type name */ *temp, /* Temporary pointer */ *filter; /* Filter program */ mime_type_t *temptype, /* MIME type looping var */ *dsttype; /* Destination MIME type */ int cost; /* Cost of filter */ DEBUG_printf(("2mime_load_convs(mime=%p, filename=\"%s\", filterpath=\"%s\", " "filtercache=%p)", mime, filename, filterpath, filtercache)); /* * First try to open the file... */ if ((fp = cupsFileOpen(filename, "r")) == NULL) { DEBUG_printf(("3mime_load_convs: Unable to open \"%s\": %s", filename, strerror(errno))); _mimeError(mime, "Unable to open \"%s\": %s", filename, strerror(errno)); return; } /* * Then read each line from the file, skipping any comments in the file... */ while (cupsFileGets(fp, line, sizeof(line)) != NULL) { /* * Skip blank lines and lines starting with a #... */ if (!line[0] || line[0] == '#') continue; /* * Strip trailing whitespace... */ for (lineptr = line + strlen(line) - 1; lineptr >= line && isspace(*lineptr & 255); lineptr --) *lineptr = '\0'; /* * Extract the destination super-type and type names from the middle of * the line. */ lineptr = line; while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\0') lineptr ++; while (*lineptr == ' ' || *lineptr == '\t') lineptr ++; temp = super; while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' && (temp - super + 1) < MIME_MAX_SUPER) *temp++ = (char)tolower(*lineptr++ & 255); *temp = '\0'; if (*lineptr != '/') continue; lineptr ++; temp = type; while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' && *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE) *temp++ = (char)tolower(*lineptr++ & 255); *temp = '\0'; if (*lineptr == '\0' || *lineptr == '\n') continue; if ((dsttype = mimeType(mime, super, type)) == NULL) { DEBUG_printf(("3mime_load_convs: Destination type %s/%s not found.", super, type)); continue; } /* * Then get the cost and filter program... */ while (*lineptr == ' ' || *lineptr == '\t') lineptr ++; if (*lineptr < '0' || *lineptr > '9') continue; cost = atoi(lineptr); while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\0') lineptr ++; while (*lineptr == ' ' || *lineptr == '\t') lineptr ++; if (*lineptr == '\0' || *lineptr == '\n') continue; filter = lineptr; if (strcmp(filter, "-")) { /* * Verify that the filter exists and is executable... */ if (!mime_add_fcache(filtercache, filter, filterpath)) { DEBUG_printf(("mime_load_convs: Filter %s not found in %s.", filter, filterpath)); _mimeError(mime, "Filter \"%s\" not found.", filter); continue; } } /* * Finally, get the source super-type and type names from the beginning of * the line. We do it here so we can support wildcards... */ lineptr = line; temp = super; while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' && (temp - super + 1) < MIME_MAX_SUPER) *temp++ = (char)tolower(*lineptr++ & 255); *temp = '\0'; if (*lineptr != '/') continue; lineptr ++; temp = type; while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' && *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE) *temp++ = (char)tolower(*lineptr++ & 255); *temp = '\0'; if (!strcmp(super, "*") && !strcmp(type, "*")) { /* * Force * / * to be "application/octet-stream"... */ strlcpy(super, "application", sizeof(super)); strlcpy(type, "octet-stream", sizeof(type)); } /* * Add the filter to the MIME database, supporting wildcards as needed... */ for (temptype = (mime_type_t *)cupsArrayFirst(mime->types); temptype; temptype = (mime_type_t *)cupsArrayNext(mime->types)) if ((super[0] == '*' || !strcmp(temptype->super, super)) && (type[0] == '*' || !strcmp(temptype->type, type))) mimeAddFilter(mime, temptype, dsttype, cost, filter); } cupsFileClose(fp); }
static cupsd_txt_t /* O - TXT record */ dnssdBuildTxtRecord( cupsd_printer_t *p, /* I - Printer information */ int for_lpd) /* I - 1 = LPD, 0 = IPP */ { int i, /* Looping var */ count; /* Count of key/value pairs */ char admin_hostname[256], /* Hostname for admin page */ adminurl_str[256], /* URL for the admin page */ type_str[32], /* Type to string buffer */ state_str[32], /* State to string buffer */ rp_str[1024], /* Queue name string buffer */ air_str[1024], /* auth-info-required string buffer */ *keyvalue[32][2], /* Table of key/value pairs */ *ptr; /* Pointer in string */ cupsd_txt_t txt; /* TXT record */ cupsd_listener_t *lis; /* Current listener */ const char *admin_scheme = "http"; /* Admin page URL scheme */ /* * Load up the key value pairs... */ count = 0; if (!for_lpd || (BrowseLocalProtocols & BROWSE_LPD)) { keyvalue[count ][0] = "txtvers"; keyvalue[count++][1] = "1"; keyvalue[count ][0] = "qtotal"; keyvalue[count++][1] = "1"; keyvalue[count ][0] = "rp"; keyvalue[count++][1] = rp_str; if (for_lpd) strlcpy(rp_str, p->name, sizeof(rp_str)); else snprintf(rp_str, sizeof(rp_str), "%s/%s", (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", p->name); keyvalue[count ][0] = "ty"; keyvalue[count++][1] = p->make_model ? p->make_model : "Unknown"; /* * Get the hostname for the admin page... */ if (strchr(DNSSDHostName, '.')) { /* * Use the provided hostname, but make sure it ends with a period... */ if ((ptr = DNSSDHostName + strlen(DNSSDHostName) - 1) >= DNSSDHostName && *ptr == '.') strlcpy(admin_hostname, DNSSDHostName, sizeof(admin_hostname)); else snprintf(admin_hostname, sizeof(admin_hostname), "%s.", DNSSDHostName); } else { /* * Unqualified hostname gets ".local." added to it... */ snprintf(admin_hostname, sizeof(admin_hostname), "%s.local.", DNSSDHostName); } /* * Get the URL scheme for the admin page... */ # ifdef HAVE_SSL for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); lis; lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) { if (lis->encryption != HTTP_ENCRYPTION_NEVER) { admin_scheme = "https"; break; } } # endif /* HAVE_SSL */ httpAssembleURIf(HTTP_URI_CODING_ALL, adminurl_str, sizeof(adminurl_str), admin_scheme, NULL, admin_hostname, DNSSDPort, "/%s/%s", (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", p->name); keyvalue[count ][0] = "adminurl"; keyvalue[count++][1] = adminurl_str; if (p->location) { keyvalue[count ][0] = "note"; keyvalue[count++][1] = p->location; } keyvalue[count ][0] = "priority"; keyvalue[count++][1] = for_lpd ? "100" : "0"; keyvalue[count ][0] = "product"; keyvalue[count++][1] = p->pc && p->pc->product ? p->pc->product : "Unknown"; keyvalue[count ][0] = "pdl"; keyvalue[count++][1] = p->pdl ? p->pdl : "application/postscript"; if (get_auth_info_required(p, air_str, sizeof(air_str))) { keyvalue[count ][0] = "air"; keyvalue[count++][1] = air_str; } keyvalue[count ][0] = "UUID"; keyvalue[count++][1] = p->uuid + 9; #ifdef HAVE_SSL keyvalue[count ][0] = "TLS"; keyvalue[count++][1] = "1.2"; #endif /* HAVE_SSL */ if (p->type & CUPS_PRINTER_FAX) { keyvalue[count ][0] = "Fax"; keyvalue[count++][1] = "T"; keyvalue[count ][0] = "rfo"; keyvalue[count++][1] = rp_str; } if (p->type & CUPS_PRINTER_COLOR) { keyvalue[count ][0] = "Color"; keyvalue[count++][1] = (p->type & CUPS_PRINTER_COLOR) ? "T" : "F"; } if (p->type & CUPS_PRINTER_DUPLEX) { keyvalue[count ][0] = "Duplex"; keyvalue[count++][1] = (p->type & CUPS_PRINTER_DUPLEX) ? "T" : "F"; } if (p->type & CUPS_PRINTER_STAPLE) { keyvalue[count ][0] = "Staple"; keyvalue[count++][1] = (p->type & CUPS_PRINTER_STAPLE) ? "T" : "F"; } if (p->type & CUPS_PRINTER_COPIES) { keyvalue[count ][0] = "Copies"; keyvalue[count++][1] = (p->type & CUPS_PRINTER_COPIES) ? "T" : "F"; } if (p->type & CUPS_PRINTER_COLLATE) { keyvalue[count ][0] = "Collate"; keyvalue[count++][1] = (p->type & CUPS_PRINTER_COLLATE) ? "T" : "F"; } if (p->type & CUPS_PRINTER_PUNCH) { keyvalue[count ][0] = "Punch"; keyvalue[count++][1] = (p->type & CUPS_PRINTER_PUNCH) ? "T" : "F"; } if (p->type & CUPS_PRINTER_BIND) { keyvalue[count ][0] = "Bind"; keyvalue[count++][1] = (p->type & CUPS_PRINTER_BIND) ? "T" : "F"; } if (p->type & CUPS_PRINTER_SORT) { keyvalue[count ][0] = "Sort"; keyvalue[count++][1] = (p->type & CUPS_PRINTER_SORT) ? "T" : "F"; } if (p->type & CUPS_PRINTER_MFP) { keyvalue[count ][0] = "Scan"; keyvalue[count++][1] = (p->type & CUPS_PRINTER_MFP) ? "T" : "F"; } snprintf(type_str, sizeof(type_str), "0x%X", p->type | CUPS_PRINTER_REMOTE); snprintf(state_str, sizeof(state_str), "%d", p->state); keyvalue[count ][0] = "printer-state"; keyvalue[count++][1] = state_str; keyvalue[count ][0] = "printer-type"; keyvalue[count++][1] = type_str; } /* * Then pack them into a proper txt record... */ # ifdef HAVE_DNSSD TXTRecordCreate(&txt, 0, NULL); for (i = 0; i < count; i ++) { size_t len = strlen(keyvalue[i][1]); if (len < 256) TXTRecordSetValue(&txt, keyvalue[i][0], (uint8_t)len, keyvalue[i][1]); } # else for (i = 0, txt = NULL; i < count; i ++) txt = avahi_string_list_add_printf(txt, "%s=%s", keyvalue[i][0], keyvalue[i][1]); # endif /* HAVE_DNSSD */ return (txt); }
void cupsdSaveAllClasses(void) { cups_file_t *fp; /* classes.conf file */ char temp[1024], /* Temporary string */ backup[1024], /* printers.conf.O file */ value[2048]; /* Value string */ cupsd_printer_t *pclass; /* Current printer class */ int i; /* Looping var */ time_t curtime; /* Current time */ struct tm *curdate; /* Current date */ cups_option_t *option; /* Current option */ /* * Create the classes.conf file... */ snprintf(temp, sizeof(temp), "%s/classes.conf", ServerRoot); snprintf(backup, sizeof(backup), "%s/classes.conf.O", ServerRoot); if (rename(temp, backup)) { if (errno != ENOENT) cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to backup classes.conf - %s", strerror(errno)); } if ((fp = cupsFileOpen(temp, "w")) == NULL) { cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to save classes.conf - %s", strerror(errno)); if (rename(backup, temp)) cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to restore classes.conf - %s", strerror(errno)); return; } else cupsdLogMessage(CUPSD_LOG_INFO, "Saving classes.conf..."); /* * Restrict access to the file... */ fchown(cupsFileNumber(fp), RunUser, Group); fchmod(cupsFileNumber(fp), 0600); /* * Write a small header to the file... */ curtime = time(NULL); curdate = localtime(&curtime); strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate); cupsFilePuts(fp, "# Class configuration file for " CUPS_SVERSION "\n"); cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp); cupsFilePuts(fp, "# DO NOT EDIT THIS FILE WHEN CUPSD IS RUNNING\n"); /* * Write each local class known to the system... */ for (pclass = (cupsd_printer_t *)cupsArrayFirst(Printers); pclass; pclass = (cupsd_printer_t *)cupsArrayNext(Printers)) { /* * Skip remote destinations and regular printers... */ if ((pclass->type & CUPS_PRINTER_REMOTE) || (pclass->type & CUPS_PRINTER_IMPLICIT) || !(pclass->type & CUPS_PRINTER_CLASS)) continue; /* * Write printers as needed... */ if (pclass == DefaultPrinter) cupsFilePrintf(fp, "<DefaultClass %s>\n", pclass->name); else cupsFilePrintf(fp, "<Class %s>\n", pclass->name); if (pclass->num_auth_info_required > 0) { switch (pclass->num_auth_info_required) { case 1 : strlcpy(value, pclass->auth_info_required[0], sizeof(value)); break; case 2 : snprintf(value, sizeof(value), "%s,%s", pclass->auth_info_required[0], pclass->auth_info_required[1]); break; case 3 : default : snprintf(value, sizeof(value), "%s,%s,%s", pclass->auth_info_required[0], pclass->auth_info_required[1], pclass->auth_info_required[2]); break; } cupsFilePutConf(fp, "AuthInfoRequired", value); } if (pclass->info) cupsFilePutConf(fp, "Info", pclass->info); if (pclass->location) cupsFilePutConf(fp, "Location", pclass->location); if (pclass->state == IPP_PRINTER_STOPPED) cupsFilePuts(fp, "State Stopped\n"); else cupsFilePuts(fp, "State Idle\n"); cupsFilePrintf(fp, "StateTime %d\n", (int)pclass->state_time); if (pclass->accepting) cupsFilePuts(fp, "Accepting Yes\n"); else cupsFilePuts(fp, "Accepting No\n"); if (pclass->shared) cupsFilePuts(fp, "Shared Yes\n"); else cupsFilePuts(fp, "Shared No\n"); snprintf(value, sizeof(value), "%s %s", pclass->job_sheets[0], pclass->job_sheets[1]); cupsFilePutConf(fp, "JobSheets", value); for (i = 0; i < pclass->num_printers; i ++) cupsFilePrintf(fp, "Printer %s\n", pclass->printers[i]->name); cupsFilePrintf(fp, "QuotaPeriod %d\n", pclass->quota_period); cupsFilePrintf(fp, "PageLimit %d\n", pclass->page_limit); cupsFilePrintf(fp, "KLimit %d\n", pclass->k_limit); for (i = 0; i < pclass->num_users; i ++) cupsFilePutConf(fp, pclass->deny_users ? "DenyUser" : "AllowUser", pclass->users[i]); if (pclass->op_policy) cupsFilePutConf(fp, "OpPolicy", pclass->op_policy); if (pclass->error_policy) cupsFilePutConf(fp, "ErrorPolicy", pclass->error_policy); for (i = pclass->num_options, option = pclass->options; i > 0; i --, option ++) { snprintf(value, sizeof(value), "%s %s", option->name, option->value); cupsFilePutConf(fp, "Option", value); } cupsFilePuts(fp, "</Class>\n"); } cupsFileClose(fp); }
static void list_group(ppd_file_t *ppd, /* I - PPD file */ ppd_group_t *group) /* I - Group to show */ { int i, j; /* Looping vars */ ppd_option_t *option; /* Current option */ ppd_choice_t *choice; /* Current choice */ ppd_group_t *subgroup; /* Current subgroup */ char buffer[10240], /* Option string buffer */ *ptr; /* Pointer into option string */ for (i = group->num_options, option = group->options; i > 0; i --, option ++) { if (!_cups_strcasecmp(option->keyword, "PageRegion")) continue; snprintf(buffer, sizeof(buffer), "%s/%s:", option->keyword, option->text); for (j = option->num_choices, choice = option->choices, ptr = buffer + strlen(buffer); j > 0 && ptr < (buffer + sizeof(buffer) - 1); j --, choice ++) { if (!_cups_strcasecmp(choice->choice, "Custom")) { ppd_coption_t *coption; /* Custom option */ ppd_cparam_t *cparam; /* Custom parameter */ static const char * const types[] = { /* Parameter types */ "CURVE", "INTEGER", "INVCURVE", "PASSCODE", "PASSWORD", "POINTS", "REAL", "STRING" }; if ((coption = ppdFindCustomOption(ppd, option->keyword)) == NULL || cupsArrayCount(coption->params) == 0) snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %sCustom", choice->marked ? "*" : ""); else if (!_cups_strcasecmp(option->keyword, "PageSize") || !_cups_strcasecmp(option->keyword, "PageRegion")) snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %sCustom.WIDTHxHEIGHT", choice->marked ? "*" : ""); else { cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params); if (cupsArrayCount(coption->params) == 1) snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %sCustom.%s", choice->marked ? "*" : "", types[cparam->type]); else { const char *prefix; /* Prefix string */ if (choice->marked) prefix = " *{"; else prefix = " {"; while (cparam) { snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), "%s%s=%s", prefix, cparam->name, types[cparam->type]); cparam = (ppd_cparam_t *)cupsArrayNext(coption->params); prefix = " "; ptr += strlen(ptr); } if (ptr < (buffer + sizeof(buffer) - 1)) strlcpy(ptr, "}", sizeof(buffer) - (size_t)(ptr - buffer)); } } } else if (choice->marked) snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " *%s", choice->choice); else snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %s", choice->choice); ptr += strlen(ptr); } _cupsLangPuts(stdout, buffer); } for (i = group->num_subgroups, subgroup = group->subgroups; i > 0; i --, subgroup ++) list_group(ppd, subgroup); }
static void write_index(const char *path, /* I - File to write */ help_index_t *hi) /* I - Index of files */ { cups_file_t *fp; /* Output file */ help_node_t *node; /* Current help node */ _cups_section_t *section, /* Current section */ key; /* Section search key */ _cups_html_t *html; /* Current HTML file */ cups_array_t *sections, /* Sections in index */ *sections_files,/* Sections sorted by size */ *columns[3]; /* Columns in final HTML file */ int column, /* Current column */ lines[3], /* Number of lines in each column */ min_column, /* Smallest column */ min_lines; /* Smallest number of lines */ /* * Build an array of sections and their files. */ sections = cupsArrayNew((cups_array_func_t)compare_sections, NULL); for (node = (help_node_t *)cupsArrayFirst(hi->nodes); node; node = (help_node_t *)cupsArrayNext(hi->nodes)) { if (node->anchor) continue; key.name = node->section ? node->section : "Miscellaneous"; if ((section = (_cups_section_t *)cupsArrayFind(sections, &key)) == NULL) { section = (_cups_section_t *)calloc(1, sizeof(_cups_section_t)); section->name = key.name; section->files = cupsArrayNew((cups_array_func_t)compare_html, NULL); cupsArrayAdd(sections, section); } html = (_cups_html_t *)calloc(1, sizeof(_cups_html_t)); html->path = node->filename; html->title = node->text; cupsArrayAdd(section->files, html); } /* * Build a sorted list of sections based on the number of files in each section * and the section name... */ sections_files = cupsArrayNew((cups_array_func_t)compare_sections_files, NULL); for (section = (_cups_section_t *)cupsArrayFirst(sections); section; section = (_cups_section_t *)cupsArrayNext(sections)) cupsArrayAdd(sections_files, section); /* * Then build three columns to hold everything, trying to balance the number of * lines in each column... */ for (column = 0; column < 3; column ++) { columns[column] = cupsArrayNew((cups_array_func_t)compare_sections, NULL); lines[column] = 0; } for (section = (_cups_section_t *)cupsArrayFirst(sections_files); section; section = (_cups_section_t *)cupsArrayNext(sections_files)) { for (min_column = 0, min_lines = lines[0], column = 1; column < 3; column ++) { if (lines[column] < min_lines) { min_column = column; min_lines = lines[column]; } } cupsArrayAdd(columns[min_column], section); lines[min_column] += cupsArrayCount(section->files) + 2; } /* * Write the HTML file... */ if ((fp = cupsFileOpen(path, "w")) == NULL) { fprintf(stderr, "makedocset: Unable to create %s: %s\n", path, strerror(errno)); exit(1); } cupsFilePuts(fp, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 " "Transitional//EN\" " "\"http://www.w3.org/TR/html4/loose.dtd\">\n" "<html>\n" "<head>\n" "<title>CUPS Documentation</title>\n" "<link rel='stylesheet' type='text/css' " "href='cups-printable.css'>\n" "</head>\n" "<body>\n" "<h1 class='title'>CUPS Documentation</h1>\n" "<table width='100%' summary=''>\n" "<tr>\n"); for (column = 0; column < 3; column ++) { if (column) cupsFilePuts(fp, "<td> </td>\n"); cupsFilePuts(fp, "<td valign='top' width='33%'>"); for (section = (_cups_section_t *)cupsArrayFirst(columns[column]); section; section = (_cups_section_t *)cupsArrayNext(columns[column])) { cupsFilePrintf(fp, "<h2 class='title'>%s</h2>\n", section->name); for (html = (_cups_html_t *)cupsArrayFirst(section->files); html; html = (_cups_html_t *)cupsArrayNext(section->files)) cupsFilePrintf(fp, "<p class='compact'><a href='%s'>%s</a></p>\n", html->path, html->title); } cupsFilePuts(fp, "</td>\n"); } cupsFilePuts(fp, "</tr>\n" "</table>\n" "</body>\n" "</html>\n"); cupsFileClose(fp); }
int /* O - Number of options marked */ ppdCollect2(ppd_file_t *ppd, /* I - PPD file data */ ppd_section_t section, /* I - Section to collect */ float min_order, /* I - Minimum OrderDependency value */ ppd_choice_t ***choices) /* O - Pointers to choices */ { ppd_choice_t *c; /* Current choice */ ppd_section_t csection; /* Current section */ float corder; /* Current OrderDependency value */ int count; /* Number of choices collected */ ppd_choice_t **collect; /* Collected choices */ float *orders; /* Collected order values */ DEBUG_printf(("ppdCollect2(ppd=%p, section=%d, min_order=%f, choices=%p)", ppd, section, min_order, choices)); if (!ppd || !choices) { if (choices) *choices = NULL; return (0); } /* * Allocate memory for up to N selected choices... */ count = 0; if ((collect = calloc(sizeof(ppd_choice_t *), cupsArrayCount(ppd->marked))) == NULL) { *choices = NULL; return (0); } if ((orders = calloc(sizeof(float), cupsArrayCount(ppd->marked))) == NULL) { *choices = NULL; free(collect); return (0); } /* * Loop through all options and add choices as needed... */ for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked); c; c = (ppd_choice_t *)cupsArrayNext(ppd->marked)) { csection = c->option->section; corder = c->option->order; if (!strcmp(c->choice, "Custom")) { ppd_attr_t *attr; /* NonUIOrderDependency value */ float aorder; /* Order value */ char asection[17], /* Section name */ amain[PPD_MAX_NAME + 1], aoption[PPD_MAX_NAME]; /* *CustomFoo and True */ for (attr = ppdFindAttr(ppd, "NonUIOrderDependency", NULL); attr; attr = ppdFindNextAttr(ppd, "NonUIOrderDependency", NULL)) if (attr->value && sscanf(attr->value, "%f%16s%41s%40s", &aorder, asection, amain, aoption) == 4 && !strncmp(amain, "*Custom", 7) && !strcmp(amain + 7, c->option->keyword) && !strcmp(aoption, "True")) { /* * Use this NonUIOrderDependency... */ corder = aorder; if (!strcmp(asection, "DocumentSetup")) csection = PPD_ORDER_DOCUMENT; else if (!strcmp(asection, "ExitServer")) csection = PPD_ORDER_EXIT; else if (!strcmp(asection, "JCLSetup")) csection = PPD_ORDER_JCL; else if (!strcmp(asection, "PageSetup")) csection = PPD_ORDER_PAGE; else if (!strcmp(asection, "Prolog")) csection = PPD_ORDER_PROLOG; else csection = PPD_ORDER_ANY; break; } } if (csection == section && corder >= min_order) { collect[count] = c; orders[count] = corder; count ++; } } /* * If we have more than 1 marked choice, sort them... */ if (count > 1) { int i, j; /* Looping vars */ for (i = 0; i < (count - 1); i ++) for (j = i + 1; j < count; j ++) if (orders[i] > orders[j]) { c = collect[i]; corder = orders[i]; collect[i] = collect[j]; orders[i] = orders[j]; collect[j] = c; orders[j] = corder; } } free(orders); DEBUG_printf(("2ppdCollect2: %d marked choices...", count)); /* * Return the array and number of choices; if 0, free the array since * it isn't needed. */ if (count > 0) { *choices = collect; return (count); } else { *choices = NULL; free(collect); return (0); } }
int /* O - Exit code */ main(int argc, /* I - Number of command-line args */ char *argv[]) /* I - Command-line arguments */ { const char *server_bin; /* CUPS_SERVERBIN environment variable */ char backends[1024]; /* Location of backends */ int request_id; /* Request ID */ int count; /* Number of devices from backend */ int compat; /* Compatibility device? */ char *backend_argv[2]; /* Arguments for backend */ cups_file_t *fp; /* Pipe to device backend */ int pid; /* Process ID of backend */ cups_dir_t *dir; /* Directory pointer */ cups_dentry_t *dent; /* Directory entry */ char filename[1024], /* Name of backend */ line[2048], /* Line from backend */ dclass[64], /* Device class */ uri[1024], /* Device URI */ info[128], /* Device info */ make_model[256], /* Make and model */ device_id[1024]; /* 1284 device ID */ int num_options; /* Number of options */ cups_option_t *options; /* Options */ const char *requested; /* requested-attributes option */ int send_class, /* Send device-class attribute? */ send_info, /* Send device-info attribute? */ send_make_and_model, /* Send device-make-and-model attribute? */ send_uri, /* Send device-uri attribute? */ send_id; /* Send device-id attribute? */ dev_info_t *dev; /* Current device */ #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) struct sigaction action; /* Actions for POSIX signals */ #endif /* HAVE_SIGACTION && !HAVE_SIGSET */ setbuf(stderr, NULL); /* * Check the command-line... */ if (argc > 1) request_id = atoi(argv[1]); else request_id = 1; if (argc != 5) { fputs("Usage: cups-deviced request-id limit user-id options\n", stderr); return (1); } if (request_id < 1) { fprintf(stderr, "cups-deviced: Bad request ID %d!\n", request_id); return (1); } normal_user = atoi(argv[3]); if (normal_user <= 0) { fprintf(stderr, "cups-deviced: Bad user %d!\n", normal_user); return (1); } num_options = cupsParseOptions(argv[4], 0, &options); requested = cupsGetOption("requested-attributes", num_options, options); if (!requested || strstr(requested, "all")) { send_class = 1; send_info = 1; send_make_and_model = 1; send_uri = 1; send_id = 1; } else { send_class = strstr(requested, "device-class") != NULL; send_info = strstr(requested, "device-info") != NULL; send_make_and_model = strstr(requested, "device-make-and-model") != NULL; send_uri = strstr(requested, "device-uri") != NULL; send_id = strstr(requested, "device-id") != NULL; } /* * Try opening the backend directory... */ if ((server_bin = getenv("CUPS_SERVERBIN")) == NULL) server_bin = CUPS_SERVERBIN; snprintf(backends, sizeof(backends), "%s/backend", server_bin); if ((dir = cupsDirOpen(backends)) == NULL) { fprintf(stderr, "ERROR: [cups-deviced] Unable to open backend directory " "\"%s\": %s", backends, strerror(errno)); return (1); } /* * Setup the devices array... */ devs = cupsArrayNew((cups_array_func_t)compare_devs, NULL); /* * Loop through all of the device backends... */ while ((dent = cupsDirRead(dir)) != NULL) { /* * Skip entries that are not executable files... */ if (!S_ISREG(dent->fileinfo.st_mode) || (dent->fileinfo.st_mode & (S_IRUSR | S_IXUSR)) != (S_IRUSR | S_IXUSR)) continue; /* * Change effective users depending on the backend permissions... */ snprintf(filename, sizeof(filename), "%s/%s", backends, dent->filename); /* * Backends without permissions for normal users run as root, * all others run as the unprivileged user... */ backend_argv[0] = dent->filename; backend_argv[1] = NULL; fp = cupsdPipeCommand(&pid, filename, backend_argv, (dent->fileinfo.st_mode & (S_IRWXG | S_IRWXO)) ? normal_user : 0); /* * Collect the output from the backend... */ if (fp) { /* * Set an alarm for the first read from the backend; this avoids * problems when a backend is hung getting device information. */ #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ sigset(SIGALRM, sigalrm_handler); #elif defined(HAVE_SIGACTION) memset(&action, 0, sizeof(action)); sigemptyset(&action.sa_mask); sigaddset(&action.sa_mask, SIGALRM); action.sa_handler = sigalrm_handler; sigaction(SIGALRM, &action, NULL); #else signal(SIGALRM, sigalrm_handler); #endif /* HAVE_SIGSET */ alarm_tripped = 0; count = 0; compat = !strcmp(dent->filename, "smb"); alarm(30); while (cupsFileGets(fp, line, sizeof(line))) { /* * Reset the alarm clock... */ alarm(30); /* * Each line is of the form: * * class URI "make model" "name" ["1284 device ID"] */ device_id[0] = '\0'; if (!strncasecmp(line, "Usage", 5)) compat = 1; else if (sscanf(line, "%63s%1023s%*[ \t]\"%255[^\"]\"%*[ \t]\"%127[^\"]\"" "%*[ \t]\"%1023[^\"]", dclass, uri, make_model, info, device_id) < 4) { /* * Bad format; strip trailing newline and write an error message. */ if (line[strlen(line) - 1] == '\n') line[strlen(line) - 1] = '\0'; fprintf(stderr, "ERROR: [cups-deviced] Bad line from \"%s\": %s\n", dent->filename, line); compat = 1; break; } else { /* * Add the device to the array of available devices... */ dev = add_dev(dclass, make_model, info, uri, device_id); if (!dev) { cupsDirClose(dir); cupsFileClose(fp); kill(pid, SIGTERM); return (1); } fprintf(stderr, "DEBUG: [cups-deviced] Added device \"%s\"...\n", uri); count ++; } } /* * Turn the alarm clock off and close the pipe to the command... */ alarm(0); if (alarm_tripped) fprintf(stderr, "WARNING: [cups-deviced] Backend \"%s\" did not " "respond within 30 seconds!\n", dent->filename); cupsFileClose(fp); kill(pid, SIGTERM); /* * Hack for backends that don't support the CUPS 1.1 calling convention: * add a network device with the method == backend name. */ if (count == 0 && compat) { snprintf(line, sizeof(line), "Unknown Network Device (%s)", dent->filename); dev = add_dev("network", line, "Unknown", dent->filename, ""); if (!dev) { cupsDirClose(dir); return (1); } fprintf(stderr, "DEBUG: [cups-deviced] Compatibility device " "\"%s\"...\n", dent->filename); } } else fprintf(stderr, "WARNING: [cups-deviced] Unable to execute \"%s\" " "backend: %s\n", dent->filename, strerror(errno)); } cupsDirClose(dir); /* * Output the list of devices... */ puts("Content-Type: application/ipp\n"); cupsdSendIPPHeader(IPP_OK, request_id); cupsdSendIPPGroup(IPP_TAG_OPERATION); cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8"); cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language", "en-US"); if ((count = atoi(argv[2])) <= 0) count = cupsArrayCount(devs); if (count > cupsArrayCount(devs)) count = cupsArrayCount(devs); for (dev = (dev_info_t *)cupsArrayFirst(devs); count > 0; count --, dev = (dev_info_t *)cupsArrayNext(devs)) { /* * Add strings to attributes... */ cupsdSendIPPGroup(IPP_TAG_PRINTER); if (send_class) cupsdSendIPPString(IPP_TAG_KEYWORD, "device-class", dev->device_class); if (send_info) cupsdSendIPPString(IPP_TAG_TEXT, "device-info", dev->device_info); if (send_make_and_model) cupsdSendIPPString(IPP_TAG_TEXT, "device-make-and-model", dev->device_make_and_model); if (send_uri) cupsdSendIPPString(IPP_TAG_URI, "device-uri", dev->device_uri); if (send_id) cupsdSendIPPString(IPP_TAG_TEXT, "device-id", dev->device_id); } cupsdSendIPPTrailer(); /* * Free the devices array and return... */ for (dev = (dev_info_t *)cupsArrayFirst(devs); dev; dev = (dev_info_t *)cupsArrayNext(devs)) free(dev); cupsArrayDelete(devs); return (0); }