From e60ec91f3e2a38a90f17ee193db32f5c6bef27ed Mon Sep 17 00:00:00 2001 From: msweet Date: Fri, 11 Feb 2011 21:20:35 +0000 Subject: [PATCH] Merge changes from CUPS 1.5svn-r9525 git-svn-id: svn+ssh://src.apple.com/svn/cups/easysw/current@2975 a1ca3aef-8c08-0410-bb20-df032aa958be --- CHANGES-1.4.txt | 7 ++ CHANGES.txt | 6 +- Makedefs.in | 2 +- backend/ipp.c | 4 +- cgi-bin/admin.c | 3 +- cups/conflicts.c | 99 ++++++++++++---- cups/http-private.h | 1 + cups/http.c | 262 ++++++++++++++++++++++++------------------ cups/language.c | 34 +++++- cups/request.c | 41 ++++--- filter/image-zoom.c | 8 +- notifier/mailto.c | 197 +++++-------------------------- notifier/testnotify.c | 174 ++-------------------------- scheduler/client.c | 28 ++--- scheduler/dirsvc.c | 7 +- scheduler/ipp.c | 80 +++++++------ scheduler/main.c | 4 +- scheduler/printers.c | 22 +++- scheduler/process.c | 31 ++++- scheduler/server.c | 2 +- scheduler/sysman.c | 35 +++++- test/Makefile | 9 ++ test/ippserver.c | 156 ++++++++++++++++--------- test/ipptool.c | 102 ++++++++++++---- 24 files changed, 681 insertions(+), 633 deletions(-) diff --git a/CHANGES-1.4.txt b/CHANGES-1.4.txt index cb42517ca..ece5fcb70 100644 --- a/CHANGES-1.4.txt +++ b/CHANGES-1.4.txt @@ -9,6 +9,13 @@ CHANGES IN CUPS V1.4.7 STR #3755, STR #3769) - Configure script fixes (STR #3659, STR #3691) - Compilation fixes (STR #3718, STR #3771, STR #3774) + - The scheduler did not always register the correct default ICC profile + on Mac OS X. + - The scheduler did not use the job owner when authorizing access for + the CUPS-Get-Document operation, preventing non-admins from accessing + their own jobs. + - CUPS did not work with some printers that incorrectly implemented the + HTTP/1.1 standard (STR #3778, STR #3791) - The scheduler did not retry fax jobs properly. - The scheduler now recognizes an empty cupsCommands PPD keyword as meaning that CUPS commands are not supported for a printer (STR #3773) diff --git a/CHANGES.txt b/CHANGES.txt index b3ba2f351..6e2297203 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,8 +1,12 @@ -CHANGES.txt - 2011-01-10 +CHANGES.txt - 2011-01-21 ------------------------ CHANGES IN CUPS V1.5b1 + - The scheduler now provides default values for the pages-per-minute and + pages-per-minute-color attributes for PPD files that lack a + Throughput keyword. + - Email notifications did not work on Mac OS X. - The cupstestppd program now shows an error for files missing a CloseGroup keyword (STR #3668) - Name resolution errors no longer cause queues to stop (STR #3719, diff --git a/Makedefs.in b/Makedefs.in index c7d066d42..61f12bb59 100644 --- a/Makedefs.in +++ b/Makedefs.in @@ -143,7 +143,7 @@ LDFLAGS = -L../cgi-bin -L../cups -L../filter -L../ppdc \ -L../scheduler @LDARCHFLAGS@ \ @LDFLAGS@ @RELROFLAGS@ @PIEFLAGS@ $(OPTIM) LEGACY_BACKENDS = @LEGACY_BACKENDS@ -LINKCUPS = @LINKCUPS@ $(SSLLIBS) $(DNSSDLIBS) +LINKCUPS = @LINKCUPS@ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(LIBZ) LINKCUPSIMAGE = @LINKCUPSIMAGE@ LIBS = $(LINKCUPS) $(COMMONLIBS) OPTIM = @OPTIM@ diff --git a/backend/ipp.c b/backend/ipp.c index b09cc729a..13a688574 100644 --- a/backend/ipp.c +++ b/backend/ipp.c @@ -2122,7 +2122,7 @@ report_printer_state(ipp_t *ipp, /* I - IPP response */ } *valptr++ = '\n'; - *valptr++ = '\0'; + *valptr = '\0'; fputs(value, stderr); } @@ -2158,7 +2158,7 @@ report_printer_state(ipp_t *ipp, /* I - IPP response */ if (value[0]) { *valptr++ = '\n'; - *valptr++ = '\0'; + *valptr = '\0'; fputs(value, stderr); } diff --git a/cgi-bin/admin.c b/cgi-bin/admin.c index f8cbba1ea..c38352a6b 100644 --- a/cgi-bin/admin.c +++ b/cgi-bin/admin.c @@ -2607,7 +2607,8 @@ do_list_printers(http_t *http) /* I - HTTP connection */ if (isalnum(*ptr & 255) || *ptr == '_' || *ptr == '-' || *ptr == '.') *option_ptr++ = *ptr; - else if ((*ptr == ' ' || *ptr == '/') && option_ptr[-1] != '_') + else if ((*ptr == ' ' || *ptr == '/') && option_ptr > option && + option_ptr[-1] != '_') *option_ptr++ = '_'; else if (*ptr == '?' || *ptr == '(') break; diff --git a/cups/conflicts.c b/cups/conflicts.c index 0ccc3b624..56f800c1d 100644 --- a/cups/conflicts.c +++ b/cups/conflicts.c @@ -196,7 +196,8 @@ cupsResolveConflicts( /* Current resolver option */ reschoice[PPD_MAX_NAME], /* Current resolver choice */ - *resptr; /* Pointer into option/choice */ + *resptr, /* Pointer into option/choice */ + firstpage[255]; /* AP_FIRSTPAGE_Keyword string */ const char *value; /* Selected option value */ int changed; /* Did we change anything? */ ppd_choice_t *marked; /* Marked choice */ @@ -321,12 +322,23 @@ cupsResolveConflicts( * Is this the option we are changing? */ + snprintf(firstpage, sizeof(firstpage), "AP_FIRSTPAGE_%s", resoption); + if (option && (!strcasecmp(resoption, option) || + !strcasecmp(firstpage, option) || (!strcasecmp(option, "PageSize") && !strcasecmp(resoption, "PageRegion")) || + (!strcasecmp(option, "AP_FIRSTPAGE_PageSize") && + !strcasecmp(resoption, "PageSize")) || + (!strcasecmp(option, "AP_FIRSTPAGE_PageSize") && + !strcasecmp(resoption, "PageRegion")) || (!strcasecmp(option, "PageRegion") && - !strcasecmp(resoption, "PageSize")))) + !strcasecmp(resoption, "PageSize")) || + (!strcasecmp(option, "AP_FIRSTPAGE_PageRegion") && + !strcasecmp(resoption, "PageSize")) || + (!strcasecmp(option, "AP_FIRSTPAGE_PageRegion") && + !strcasecmp(resoption, "PageRegion")))) continue; /* @@ -955,7 +967,9 @@ ppd_test_constraints( ppd_choice_t key, /* Search key */ *marked; /* Marked choice */ cups_array_t *active = NULL; /* Active constraints */ - const char *value; /* Current value */ + const char *value, /* Current value */ + *firstvalue; /* AP_FIRSTPAGE_Keyword value */ + char firstpage[255]; /* AP_FIRSTPAGE_Keyword string */ DEBUG_printf(("7ppd_test_constraints(ppd=%p, option=\"%s\", choice=\"%s\", " @@ -1000,9 +1014,15 @@ ppd_test_constraints( for (i = consts->num_constraints, constptr = consts->constraints; i > 0; i --, constptr ++) + { if (!strcasecmp(constptr->option->keyword, option)) break; + if (!strncasecmp(option, "AP_FIRSTPAGE_", 13) && + !strcasecmp(constptr->option->keyword, option + 13)) + break; + } + if (!i) continue; } @@ -1047,7 +1067,22 @@ ppd_test_constraints( if (value && !strncasecmp(value, "Custom.", 7)) value = "Custom"; - if (!value || strcasecmp(value, constptr->choice->choice)) + if (option && choice && + (!strcasecmp(option, "AP_FIRSTPAGE_PageSize") || + !strcasecmp(option, "AP_FIRSTPAGE_PageRegion"))) + { + firstvalue = choice; + } + else if ((firstvalue = cupsGetOption("AP_FIRSTPAGE_PageSize", + num_options, options)) == NULL) + firstvalue = cupsGetOption("AP_FIRSTPAGE_PageRegion", num_options, + options); + + if (firstvalue && !strncasecmp(firstvalue, "Custom.", 7)) + firstvalue = "Custom"; + + if ((!value || strcasecmp(value, constptr->choice->choice)) && + (!firstvalue || strcasecmp(firstvalue, constptr->choice->choice))) { DEBUG_puts("9ppd_test_constraints: NO"); break; @@ -1055,32 +1090,56 @@ ppd_test_constraints( } else if (constptr->choice) { + /* + * Compare against the constrained choice... + */ + if (option && choice && !strcasecmp(option, constptr->option->keyword)) { if (!strncasecmp(choice, "Custom.", 7)) value = "Custom"; else value = choice; - - if (strcasecmp(value, constptr->choice->choice)) - { - DEBUG_puts("9ppd_test_constraints: NO"); - break; - } } else if ((value = cupsGetOption(constptr->option->keyword, num_options, options)) != NULL) { if (!strncasecmp(value, "Custom.", 7)) value = "Custom"; + } + else if (constptr->choice->marked) + value = constptr->choice->choice; + else + value = NULL; - if (strcasecmp(value, constptr->choice->choice)) - { - DEBUG_puts("9ppd_test_constraints: NO"); - break; - } + /* + * Now check AP_FIRSTPAGE_option... + */ + + snprintf(firstpage, sizeof(firstpage), "AP_FIRSTPAGE_%s", + constptr->option->keyword); + + if (option && choice && !strcasecmp(option, firstpage)) + { + if (!strncasecmp(choice, "Custom.", 7)) + firstvalue = "Custom"; + else + firstvalue = choice; + } + else if ((firstvalue = cupsGetOption(firstpage, num_options, + options)) != NULL) + { + if (!strncasecmp(firstvalue, "Custom.", 7)) + firstvalue = "Custom"; } - else if (!constptr->choice->marked) + else + firstvalue = NULL; + + DEBUG_printf(("9ppd_test_constraints: value=%s, firstvalue=%s", value, + firstvalue)); + + if ((!value || strcasecmp(value, constptr->choice->choice)) && + (!firstvalue || strcasecmp(firstvalue, constptr->choice->choice))) { DEBUG_puts("9ppd_test_constraints: NO"); break; @@ -1093,11 +1152,11 @@ ppd_test_constraints( !strcasecmp(choice, "False")) { DEBUG_puts("9ppd_test_constraints: NO"); - break; + break; } } else if ((value = cupsGetOption(constptr->option->keyword, num_options, - options)) != NULL) + options)) != NULL) { if (!strcasecmp(value, "None") || !strcasecmp(value, "Off") || !strcasecmp(value, "False")) @@ -1108,10 +1167,10 @@ ppd_test_constraints( } else { - key.option = constptr->option; + key.option = constptr->option; if ((marked = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) - == NULL || + == NULL || (!strcasecmp(marked->choice, "None") || !strcasecmp(marked->choice, "Off") || !strcasecmp(marked->choice, "False"))) diff --git a/cups/http-private.h b/cups/http-private.h index 932259ddc..31c76387a 100644 --- a/cups/http-private.h +++ b/cups/http-private.h @@ -326,6 +326,7 @@ extern const char *_httpResolveURI(const char *uri, char *resolved_uri, size_t resolved_size, int log); extern void _httpSetTimeout(http_t *http, double timeout, _http_timeout_cb_t cb, void *user_data); +extern int _httpUpdate(http_t *http, http_status_t *status); extern int _httpWait(http_t *http, int msec, int usessl); diff --git a/cups/http.c b/cups/http.c index 834f61c4c..92997959d 100644 --- a/cups/http.c +++ b/cups/http.c @@ -83,6 +83,8 @@ * _httpSetTimeout() - Set read/write timeouts and an optional * callback. * httpTrace() - Send an TRACE request to the server. + * _httpUpdate() - Update the current HTTP status for incoming + * data. * httpUpdate() - Update the current HTTP state for incoming * data. * _httpWait() - Wait for data available on a connection (no @@ -2582,162 +2584,201 @@ httpTrace(http_t *http, /* I - Connection to server */ /* - * 'httpUpdate()' - Update the current HTTP state for incoming data. + * '_httpUpdate()' - Update the current HTTP status for incoming data. + * + * Note: Unlike httpUpdate(), this function does not flush pending write data + * and only retrieves a single status line from the HTTP connection. */ -http_status_t /* O - HTTP status */ -httpUpdate(http_t *http) /* I - Connection to server */ +int /* O - 1 to continue, 0 to stop */ +_httpUpdate(http_t *http, /* I - Connection to server */ + http_status_t *status) /* O - Current HTTP status */ { char line[32768], /* Line from connection... */ *value; /* Pointer to value on line */ http_field_t field; /* Field index */ - int major, minor, /* HTTP version numbers */ - status; /* Request status */ + int major, minor; /* HTTP version numbers */ - DEBUG_printf(("httpUpdate(http=%p), state=%s", http, + DEBUG_printf(("_httpUpdate(http=%p, status=%p), state=%s", http, status, http_states[http->state])); /* - * Flush pending data, if any... + * Grab a single line from the connection... */ - if (http->wused) + if (!httpGets(line, sizeof(line), http)) { - DEBUG_puts("2httpUpdate: flushing buffer..."); - - if (httpFlushWrite(http) < 0) - return (HTTP_ERROR); + *status = HTTP_ERROR; + return (0); } - /* - * If we haven't issued any commands, then there is nothing to "update"... - */ + DEBUG_printf(("2_httpUpdate: Got \"%s\"", line)); - if (http->state == HTTP_WAITING) - return (HTTP_CONTINUE); - - /* - * Grab all of the lines we can from the connection... - */ - - while (httpGets(line, sizeof(line), http) != NULL) + if (line[0] == '\0') { - DEBUG_printf(("2httpUpdate: Got \"%s\"", line)); + /* + * Blank line means the start of the data section (if any). Return + * the result code, too... + * + * If we get status 100 (HTTP_CONTINUE), then we *don't* change states. + * Instead, we just return HTTP_CONTINUE to the caller and keep on + * tryin'... + */ - if (line[0] == '\0') + if (http->status == HTTP_CONTINUE) { - /* - * Blank line means the start of the data section (if any). Return - * the result code, too... - * - * If we get status 100 (HTTP_CONTINUE), then we *don't* change states. - * Instead, we just return HTTP_CONTINUE to the caller and keep on - * tryin'... - */ - - if (http->status == HTTP_CONTINUE) - return (http->status); + *status = http->status; + return (0); + } - if (http->status < HTTP_BAD_REQUEST) - http->digest_tries = 0; + if (http->status < HTTP_BAD_REQUEST) + http->digest_tries = 0; #ifdef HAVE_SSL - if (http->status == HTTP_SWITCHING_PROTOCOLS && !http->tls) + if (http->status == HTTP_SWITCHING_PROTOCOLS && !http->tls) + { + if (http_setup_ssl(http) != 0) { - if (http_setup_ssl(http) != 0) - { # ifdef WIN32 - closesocket(http->fd); + closesocket(http->fd); # else - close(http->fd); + close(http->fd); # endif /* WIN32 */ - return (HTTP_ERROR); - } - - return (HTTP_CONTINUE); + *status = http->status = HTTP_ERROR; + return (0); } + + *status = HTTP_CONTINUE; + return (0); + } #endif /* HAVE_SSL */ - httpGetLength2(http); + httpGetLength2(http); - switch (http->state) - { - case HTTP_GET : - case HTTP_POST : - case HTTP_POST_RECV : - case HTTP_PUT : - http->state ++; - case HTTP_POST_SEND : - case HTTP_HEAD : - break; + switch (http->state) + { + case HTTP_GET : + case HTTP_POST : + case HTTP_POST_RECV : + case HTTP_PUT : + http->state ++; + case HTTP_POST_SEND : + case HTTP_HEAD : + break; - default : - http->state = HTTP_WAITING; - break; - } + default : + http->state = HTTP_WAITING; + break; + } + + *status = http->status; + return (0); + } + else if (!strncmp(line, "HTTP/", 5)) + { + /* + * Got the beginning of a response... + */ + + int intstatus; /* Status value as an integer */ - return (http->status); + if (sscanf(line, "HTTP/%d.%d%d", &major, &minor, &intstatus) != 3) + { + *status = http->status = HTTP_ERROR; + return (0); } - else if (!strncmp(line, "HTTP/", 5)) + + http->version = (http_version_t)(major * 100 + minor); + *status = http->status = (http_status_t)intstatus; + } + else if ((value = strchr(line, ':')) != NULL) + { + /* + * Got a value... + */ + + *value++ = '\0'; + while (_cups_isspace(*value)) + value ++; + + /* + * Be tolerants of servers that send unknown attribute fields... + */ + + if (!strcasecmp(line, "expect")) { /* - * Got the beginning of a response... + * "Expect: 100-continue" or similar... */ - if (sscanf(line, "HTTP/%d.%d%d", &major, &minor, &status) != 3) - return (HTTP_ERROR); - - http->version = (http_version_t)(major * 100 + minor); - http->status = (http_status_t)status; + http->expect = (http_status_t)atoi(value); } - else if ((value = strchr(line, ':')) != NULL) + else if (!strcasecmp(line, "cookie")) { /* - * Got a value... + * "Cookie: name=value[; name=value ...]" - replaces previous cookies... */ - *value++ = '\0'; - while (_cups_isspace(*value)) - value ++; + httpSetCookie(http, value); + } + else if ((field = http_field(line)) != HTTP_FIELD_UNKNOWN) + httpSetField(http, field, value); +#ifdef DEBUG + else + DEBUG_printf(("1_httpUpdate: unknown field %s seen!", line)); +#endif /* DEBUG */ + } + else + { + DEBUG_printf(("1_httpUpdate: Bad response line \"%s\"!", line)); + *status = http->status = HTTP_ERROR; + return (0); + } - /* - * Be tolerants of servers that send unknown attribute fields... - */ + return (1); +} - if (!strcasecmp(line, "expect")) - { - /* - * "Expect: 100-continue" or similar... - */ - http->expect = (http_status_t)atoi(value); - } - else if (!strcasecmp(line, "cookie")) - { - /* - * "Cookie: name=value[; name=value ...]" - replaces previous cookies... - */ +/* + * 'httpUpdate()' - Update the current HTTP state for incoming data. + */ - httpSetCookie(http, value); - } - else if ((field = http_field(line)) == HTTP_FIELD_UNKNOWN) - { - DEBUG_printf(("1httpUpdate: unknown field %s seen!", line)); - continue; - } - else - httpSetField(http, field, value); - } - else - { - DEBUG_printf(("1httpUpdate: Bad response line \"%s\"!", line)); - http->status = HTTP_ERROR; +http_status_t /* O - HTTP status */ +httpUpdate(http_t *http) /* I - Connection to server */ +{ + http_status_t status; /* Request status */ + + + DEBUG_printf(("httpUpdate(http=%p), state=%s", http, + http_states[http->state])); + + /* + * Flush pending data, if any... + */ + + if (http->wused) + { + DEBUG_puts("2httpUpdate: flushing buffer..."); + + if (httpFlushWrite(http) < 0) return (HTTP_ERROR); - } } + /* + * If we haven't issued any commands, then there is nothing to "update"... + */ + + if (http->state == HTTP_WAITING) + return (HTTP_CONTINUE); + + /* + * Grab all of the lines we can from the connection... + */ + + while (_httpUpdate(http, &status)); + /* * See if there was an error... */ @@ -2757,10 +2798,10 @@ httpUpdate(http_t *http) /* I - Connection to server */ } /* - * If we haven't already returned, then there is nothing new... + * Return the current status... */ - return (HTTP_CONTINUE); + return (status); } @@ -3040,13 +3081,6 @@ httpWrite2(http_t *http, /* I - Connection to server */ http->data_encoding = HTTP_ENCODE_LENGTH; http->data_remaining = 0; } - - if (http->state == HTTP_POST_RECV) - http->state ++; - else if (http->state == HTTP_PUT_RECV) - http->state = HTTP_STATUS; - else - http->state = HTTP_WAITING; } return (bytes); diff --git a/cups/language.c b/cups/language.c index 820b5421e..2d07c3184 100644 --- a/cups/language.c +++ b/cups/language.c @@ -3,7 +3,7 @@ * * I18N/language support for CUPS. * - * Copyright 2007-2010 by Apple Inc. + * Copyright 2007-2011 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -16,6 +16,26 @@ * * Contents: * + * _cupsAppleLanguage() - Get the Apple language identifier associated with + * a locale ID. + * _cupsEncodingName() - Return the character encoding name string for the + * given encoding enumeration. + * cupsLangDefault() - Return the default language. + * cupsLangEncoding() - Return the character encoding (us-ascii, etc.) for + * the given language. + * cupsLangFlush() - Flush all language data out of the cache. + * cupsLangFree() - Free language data. + * cupsLangGet() - Get a language. + * _cupsLangString() - Get a message string. + * _cupsMessageFree() - Free a messages array. + * _cupsMessageLoad() - Load a .po file into a messages array. + * _cupsMessageLookup() - Lookup a message string. + * appleLangDefault() - Get the default locale string. + * appleMessageLoad() - Load a message catalog from a localizable bundle. + * cups_cache_lookup() - Lookup a language in the cache... + * cups_message_compare() - Compare two messages. + * cups_message_free() - Free a message. + * cups_unquote() - Unquote characters in strings... */ /* @@ -1092,6 +1112,9 @@ _cupsMessageLookup(cups_array_t *a, /* I - Message array */ match->str = strdup(m); cupsArrayAdd(a, match); + + if (cfm) + CFRelease(cfm); } #endif /* __APPLE__ && CUPS_BUNDLEDIR */ @@ -1222,12 +1245,21 @@ appleLangDefault(void) # ifdef CUPS_BUNDLEDIR +# ifndef CF_RETURNS_RETAINED +# if __has_feature(attribute_cf_returns_retained) +# define CF_RETURNS_RETAINED __attribute__((cf_returns_retained)) +# else +# define CF_RETURNS_RETAINED +# endif /* __has_feature(attribute_cf_returns_retained) */ +# endif /* !CF_RETURNED_RETAINED */ + /* * 'appleMessageLoad()' - Load a message catalog from a localizable bundle. */ static cups_array_t * /* O - Message catalog */ appleMessageLoad(const char *locale) /* I - Locale ID */ +CF_RETURNS_RETAINED { char filename[1024], /* Path to cups.strings file */ applelang[256]; /* Apple language ID */ diff --git a/cups/request.c b/cups/request.c index 31b316cb3..cf8426fb6 100644 --- a/cups/request.c +++ b/cups/request.c @@ -3,7 +3,7 @@ * * IPP utilities for CUPS. * - * Copyright 2007-2010 by Apple Inc. + * Copyright 2007-2011 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -153,7 +153,11 @@ cupsDoIORequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP if (!http) if ((http = _cupsConnect()) == NULL) + { + ippDelete(request); + return (NULL); + } /* * See if we have a file to send... @@ -245,7 +249,9 @@ cupsDoIORequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP { if (httpCheck(http)) { - if ((status = httpUpdate(http)) != HTTP_CONTINUE) + _httpUpdate(http, &status); + + if (status >= HTTP_MULTIPLE_CHOICES) break; } @@ -385,9 +391,11 @@ cupsGetResponse(http_t *http, /* I - Connection to server or @code CUPS_HTTP DEBUG_printf(("2cupsGetResponse: Update loop, http->status=%d...", http->status)); - status = http->status; - while (status == HTTP_CONTINUE) + do + { status = httpUpdate(http); + } + while (http->state == HTTP_POST_RECV); DEBUG_printf(("2cupsGetResponse: status=%d", status)); @@ -692,7 +700,8 @@ cupsSendRequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP { got_status = 1; - if ((status = httpUpdate(http)) != HTTP_CONTINUE) + _httpUpdate(http, &status); + if (status >= HTTP_MULTIPLE_CHOICES) break; } @@ -700,15 +709,18 @@ cupsSendRequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP * Wait up to 1 second to get the 100-continue response as needed... */ - if (!got_status && expect == HTTP_CONTINUE) + if (!got_status) { - DEBUG_puts("2cupsSendRequest: Waiting for 100-continue..."); + if (expect == HTTP_CONTINUE) + { + DEBUG_puts("2cupsSendRequest: Waiting for 100-continue..."); - if (httpWait(http, 1000)) - status = httpUpdate(http); + if (httpWait(http, 1000)) + _httpUpdate(http, &status); + } + else if (httpCheck(http)) + _httpUpdate(http, &status); } - else if (httpCheck(http)) - status = httpUpdate(http); DEBUG_printf(("2cupsSendRequest: status=%d", status)); @@ -716,7 +728,7 @@ cupsSendRequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP * Process the current HTTP status... */ - if (status >= HTTP_BAD_REQUEST) + if (status >= HTTP_MULTIPLE_CHOICES) httpFlush(http); switch (status) @@ -848,9 +860,10 @@ cupsWriteRequestData( if (_httpWait(http, 0, 1)) { - http_status_t status; /* Status from httpUpdate */ + http_status_t status; /* Status from _httpUpdate */ - if ((status = httpUpdate(http)) >= HTTP_BAD_REQUEST) + _httpUpdate(http, &status); + if (status >= HTTP_MULTIPLE_CHOICES) { _cupsSetHTTPError(status); httpFlush(http); diff --git a/filter/image-zoom.c b/filter/image-zoom.c index f921fca89..c631a5021 100644 --- a/filter/image-zoom.c +++ b/filter/image-zoom.c @@ -1,9 +1,9 @@ /* * "$Id: image-zoom.c 6649 2007-07-11 21:46:42Z mike $" * - * cupsImage zoom routines for the Common UNIX Printing System (CUPS). + * cupsImage zoom routines for CUPS. * - * Copyright 2007 by Apple Inc. + * Copyright 2007-2011 by Apple Inc. * Copyright 1993-2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -136,7 +136,7 @@ _cupsImageZoomNew( z->ystep = z->height / z->ysize; z->yincr = 1; z->instep = z->xstep * z->depth; - z->inincr = z->xincr * z->depth; + z->inincr = /* z->xincr * */ z->depth; /* z->xincr is always 1 */ if (z->width < img->ysize) z->xmax = z->width; @@ -163,7 +163,7 @@ _cupsImageZoomNew( z->ystep = z->height / z->ysize; z->yincr = 1; z->instep = z->xstep * z->depth; - z->inincr = z->xincr * z->depth; + z->inincr = /* z->xincr * */ z->depth; /* z->xincr is always 1 */ if (z->width < img->xsize) z->xmax = z->width; diff --git a/notifier/mailto.c b/notifier/mailto.c index 8a2d2d386..606800af0 100644 --- a/notifier/mailto.c +++ b/notifier/mailto.c @@ -3,7 +3,7 @@ * * "mailto" notifier for CUPS. * - * Copyright 2007-2010 by Apple Inc. + * Copyright 2007-2011 by Apple Inc. * Copyright 1997-2005 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -25,9 +25,7 @@ * Include necessary headers... */ -#include -#include -#include +#include #include #include @@ -331,8 +329,16 @@ email_message(const char *to, /* I - Recipient of message */ cupsFileClose(fp); - if (wait(&status)) - status = errno << 8; + while (wait(&status)) + { + if (errno != EINTR) + { + fprintf(stderr, "DEBUG: Unable to get child status: %s\n", + strerror(errno)); + status = 0; + break; + } + } /* * Report any non-zero status... @@ -425,9 +431,14 @@ load_configuration(void) if ((fp = cupsFileOpen(line, "r")) == NULL) { - fprintf(stderr, "ERROR: Unable to open \"%s\" - %s\n", line, - strerror(errno)); - return (1); + if (errno != ENOENT) + { + fprintf(stderr, "ERROR: Unable to open \"%s\" - %s\n", line, + strerror(errno)); + return (1); + } + else + return (0); } linenum = 0; @@ -600,88 +611,9 @@ void print_attributes(ipp_t *ipp, /* I - IPP request */ int indent) /* I - Indentation */ { - int i; /* Looping var */ ipp_tag_t group; /* Current group */ ipp_attribute_t *attr; /* Current attribute */ - ipp_value_t *val; /* Current value */ - static const char * const tags[] = /* Value/group tag strings */ - { - "reserved-00", - "operation-attributes-tag", - "job-attributes-tag", - "end-of-attributes-tag", - "printer-attributes-tag", - "unsupported-attributes-tag", - "subscription-attributes-tag", - "event-attributes-tag", - "reserved-08", - "reserved-09", - "reserved-0A", - "reserved-0B", - "reserved-0C", - "reserved-0D", - "reserved-0E", - "reserved-0F", - "unsupported", - "default", - "unknown", - "no-value", - "reserved-14", - "not-settable", - "delete-attr", - "admin-define", - "reserved-18", - "reserved-19", - "reserved-1A", - "reserved-1B", - "reserved-1C", - "reserved-1D", - "reserved-1E", - "reserved-1F", - "reserved-20", - "integer", - "boolean", - "enum", - "reserved-24", - "reserved-25", - "reserved-26", - "reserved-27", - "reserved-28", - "reserved-29", - "reserved-2a", - "reserved-2b", - "reserved-2c", - "reserved-2d", - "reserved-2e", - "reserved-2f", - "octetString", - "dateTime", - "resolution", - "rangeOfInteger", - "begCollection", - "textWithLanguage", - "nameWithLanguage", - "endCollection", - "reserved-38", - "reserved-39", - "reserved-3a", - "reserved-3b", - "reserved-3c", - "reserved-3d", - "reserved-3e", - "reserved-3f", - "reserved-40", - "textWithoutLanguage", - "nameWithoutLanguage", - "reserved-43", - "keyword", - "uri", - "uriScheme", - "charset", - "naturalLanguage", - "mimeMediaType", - "memberName" - }; + char buffer[1024]; /* Value buffer */ for (group = IPP_TAG_ZERO, attr = ipp->attrs; attr; attr = attr->next) @@ -697,91 +629,14 @@ print_attributes(ipp_t *ipp, /* I - IPP request */ { group = attr->group_tag; - fprintf(stderr, "DEBUG: %*s%s:\n\n", indent - 4, "", tags[group]); + fprintf(stderr, "DEBUG: %*s%s:\n\n", indent - 4, "", ippTagString(group)); } - fprintf(stderr, "DEBUG: %*s%s (", indent, "", attr->name); - if (attr->num_values > 1) - fputs("1setOf ", stderr); - fprintf(stderr, "%s):", tags[attr->value_tag]); + _ippAttrString(attr, buffer, sizeof(buffer)); - switch (attr->value_tag) - { - case IPP_TAG_ENUM : - case IPP_TAG_INTEGER : - for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) - fprintf(stderr, " %d", val->integer); - fputc('\n', stderr); - break; - - case IPP_TAG_BOOLEAN : - for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) - fprintf(stderr, " %s", val->boolean ? "true" : "false"); - fputc('\n', stderr); - break; - - case IPP_TAG_RANGE : - for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) - fprintf(stderr, " %d-%d", val->range.lower, val->range.upper); - fputc('\n', stderr); - break; - - case IPP_TAG_DATE : - { - time_t vtime; /* Date/Time value */ - struct tm *vdate; /* Date info */ - char vstring[256]; /* Formatted time */ - - for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) - { - vtime = ippDateToTime(val->date); - vdate = localtime(&vtime); - strftime(vstring, sizeof(vstring), "%c", vdate); - fprintf(stderr, " (%s)", vstring); - } - } - fputc('\n', stderr); - break; - - case IPP_TAG_RESOLUTION : - for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) - fprintf(stderr, " %dx%d%s", val->resolution.xres, - val->resolution.yres, - val->resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpc"); - fputc('\n', stderr); - break; - - case IPP_TAG_STRING : - case IPP_TAG_TEXTLANG : - case IPP_TAG_NAMELANG : - case IPP_TAG_TEXT : - case IPP_TAG_NAME : - case IPP_TAG_KEYWORD : - case IPP_TAG_URI : - case IPP_TAG_URISCHEME : - case IPP_TAG_CHARSET : - case IPP_TAG_LANGUAGE : - case IPP_TAG_MIMETYPE : - for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) - fprintf(stderr, " \"%s\"", val->string.text); - fputc('\n', stderr); - break; - - case IPP_TAG_BEGIN_COLLECTION : - fputc('\n', stderr); - - for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) - { - if (i) - fputc('\n', stderr); - print_attributes(val->collection, indent + 4); - } - break; - - default : - fprintf(stderr, "UNKNOWN (%d values)\n", attr->num_values); - break; - } + fprintf(stderr, "DEBUG: %*s%s (%s%s) %s", indent, "", attr->name, + attr->num_values > 1 ? "1setOf " : "", + ippTagString(attr->value_tag), buffer); } } diff --git a/notifier/testnotify.c b/notifier/testnotify.c index 62475d6d7..7e91f18cb 100644 --- a/notifier/testnotify.c +++ b/notifier/testnotify.c @@ -3,7 +3,7 @@ * * Test notifier for CUPS. * - * Copyright 2007-2010 by Apple Inc. + * Copyright 2007-2011 by Apple Inc. * Copyright 1997-2005 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -22,9 +22,7 @@ * Include necessary headers... */ -#include -#include -#include +#include /* @@ -94,88 +92,9 @@ void print_attributes(ipp_t *ipp, /* I - IPP request */ int indent) /* I - Indentation */ { - int i; /* Looping var */ ipp_tag_t group; /* Current group */ ipp_attribute_t *attr; /* Current attribute */ - ipp_value_t *val; /* Current value */ - static const char * const tags[] = /* Value/group tag strings */ - { - "reserved-00", - "operation-attributes-tag", - "job-attributes-tag", - "end-of-attributes-tag", - "printer-attributes-tag", - "unsupported-attributes-tag", - "subscription-attributes-tag", - "event-attributes-tag", - "reserved-08", - "reserved-09", - "reserved-0A", - "reserved-0B", - "reserved-0C", - "reserved-0D", - "reserved-0E", - "reserved-0F", - "unsupported", - "default", - "unknown", - "no-value", - "reserved-14", - "not-settable", - "delete-attr", - "admin-define", - "reserved-18", - "reserved-19", - "reserved-1A", - "reserved-1B", - "reserved-1C", - "reserved-1D", - "reserved-1E", - "reserved-1F", - "reserved-20", - "integer", - "boolean", - "enum", - "reserved-24", - "reserved-25", - "reserved-26", - "reserved-27", - "reserved-28", - "reserved-29", - "reserved-2a", - "reserved-2b", - "reserved-2c", - "reserved-2d", - "reserved-2e", - "reserved-2f", - "octetString", - "dateTime", - "resolution", - "rangeOfInteger", - "begCollection", - "textWithLanguage", - "nameWithLanguage", - "endCollection", - "reserved-38", - "reserved-39", - "reserved-3a", - "reserved-3b", - "reserved-3c", - "reserved-3d", - "reserved-3e", - "reserved-3f", - "reserved-40", - "textWithoutLanguage", - "nameWithoutLanguage", - "reserved-43", - "keyword", - "uri", - "uriScheme", - "charset", - "naturalLanguage", - "mimeMediaType", - "memberName" - }; + char buffer[1024]; /* Value buffer */ for (group = IPP_TAG_ZERO, attr = ipp->attrs; attr; attr = attr->next) @@ -191,91 +110,14 @@ print_attributes(ipp_t *ipp, /* I - IPP request */ { group = attr->group_tag; - fprintf(stderr, "DEBUG: %*s%s:\n\n", indent - 4, "", tags[group]); + fprintf(stderr, "DEBUG: %*s%s:\n\n", indent - 4, "", ippTagString(group)); } - fprintf(stderr, "DEBUG: %*s%s (", indent, "", attr->name); - if (attr->num_values > 1) - fputs("1setOf ", stderr); - fprintf(stderr, "%s):", tags[attr->value_tag]); + _ippAttrString(attr, buffer, sizeof(buffer)); - switch (attr->value_tag) - { - case IPP_TAG_ENUM : - case IPP_TAG_INTEGER : - for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) - fprintf(stderr, " %d", val->integer); - fputc('\n', stderr); - break; - - case IPP_TAG_BOOLEAN : - for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) - fprintf(stderr, " %s", val->boolean ? "true" : "false"); - fputc('\n', stderr); - break; - - case IPP_TAG_RANGE : - for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) - fprintf(stderr, " %d-%d", val->range.lower, val->range.upper); - fputc('\n', stderr); - break; - - case IPP_TAG_DATE : - { - time_t vtime; /* Date/Time value */ - struct tm *vdate; /* Date info */ - char vstring[256]; /* Formatted time */ - - for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) - { - vtime = ippDateToTime(val->date); - vdate = localtime(&vtime); - strftime(vstring, sizeof(vstring), "%c", vdate); - fprintf(stderr, " (%s)", vstring); - } - } - fputc('\n', stderr); - break; - - case IPP_TAG_RESOLUTION : - for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) - fprintf(stderr, " %dx%d%s", val->resolution.xres, - val->resolution.yres, - val->resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpc"); - fputc('\n', stderr); - break; - - case IPP_TAG_STRING : - case IPP_TAG_TEXTLANG : - case IPP_TAG_NAMELANG : - case IPP_TAG_TEXT : - case IPP_TAG_NAME : - case IPP_TAG_KEYWORD : - case IPP_TAG_URI : - case IPP_TAG_URISCHEME : - case IPP_TAG_CHARSET : - case IPP_TAG_LANGUAGE : - case IPP_TAG_MIMETYPE : - for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) - fprintf(stderr, " \"%s\"", val->string.text); - fputc('\n', stderr); - break; - - case IPP_TAG_BEGIN_COLLECTION : - fputc('\n', stderr); - - for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) - { - if (i) - fputc('\n', stderr); - print_attributes(val->collection, indent + 4); - } - break; - - default : - fprintf(stderr, "UNKNOWN (%d values)\n", attr->num_values); - break; - } + fprintf(stderr, "DEBUG: %*s%s (%s%s) %s", indent, "", attr->name, + attr->num_values > 1 ? "1setOf " : "", + ippTagString(attr->value_tag), buffer); } } diff --git a/scheduler/client.c b/scheduler/client.c index 7239bdb83..65ce4f25b 100644 --- a/scheduler/client.c +++ b/scheduler/client.c @@ -3319,13 +3319,13 @@ encrypt_client(cupsd_client_t *con) /* I - Client to encrypt */ return (1); # elif defined(HAVE_CDSASSL) - OSStatus error; /* Error code */ + OSStatus error = 0; /* Error code */ + CFArrayRef peerCerts; /* Peer certificates */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "encrypt_client(con=%p(%d))", con, con->http.fd); - error = 0; con->http.tls_credentials = get_cdsa_certificate(con); if (!con->http.tls_credentials) @@ -3404,9 +3404,7 @@ encrypt_client(cupsd_client_t *con) /* I - Client to encrypt */ cupsdLogMessage(CUPSD_LOG_DEBUG, "Connection from %s now encrypted.", con->http.hostname); - CFArrayRef peerCerts; /* Peer certificates */ - - if (!(error = SSLCopyPeerCertificates(con->http.tls, &peerCerts)) && peerCerts) + if (!SSLCopyPeerCertificates(con->http.tls, &peerCerts) && peerCerts) { cupsdLogMessage(CUPSD_LOG_DEBUG, "Received %d peer certificates!", (int)CFArrayGetCount(peerCerts)); @@ -3468,15 +3466,17 @@ get_cdsa_certificate( servername = CFStringCreateWithCString(kCFAllocatorDefault, con->servername, kCFStringEncodingUTF8); - if ((policy = SecPolicyCreateSSL(1, servername)) == NULL) + policy = SecPolicyCreateSSL(1, servername); + + if (servername) + CFRelease(servername); + + if (!policy) { cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create ssl policy reference"); goto cleanup; } - if (servername) - CFRelease(servername); - if (!(query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks))) @@ -3510,15 +3510,17 @@ get_cdsa_certificate( CFRelease(policy); - if ((policy = SecPolicyCreateSSL(1, servername)) == NULL) + policy = SecPolicyCreateSSL(1, servername); + + if (servername) + CFRelease(servername); + + if (!policy) { cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create ssl policy reference"); goto cleanup; } - if (servername) - CFRelease(servername); - CFDictionarySetValue(query, kSecMatchPolicy, policy); err = SecItemCopyMatching(query, (CFTypeRef *)&identity); diff --git a/scheduler/dirsvc.c b/scheduler/dirsvc.c index 293b0622e..bf1041287 100644 --- a/scheduler/dirsvc.c +++ b/scheduler/dirsvc.c @@ -3,7 +3,7 @@ * * Directory services routines for the CUPS scheduler. * - * Copyright 2007-2010 by Apple Inc. + * Copyright 2007-2011 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -2550,6 +2550,9 @@ dnssdPackTxtRecord(int *txt_len, /* O - TXT record length */ * Calculate the buffer size */ + if (count <= 0) + return (NULL); + for (length = i = 0; i < count; i++) length += 1 + strlen(keyvalue[i][0]) + (keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0); @@ -3018,7 +3021,7 @@ get_auth_info_required( return (buffer); } - return (NULL); + return ("none"); } diff --git a/scheduler/ipp.c b/scheduler/ipp.c index 5200964c3..64b953fb1 100644 --- a/scheduler/ipp.c +++ b/scheduler/ipp.c @@ -3258,7 +3258,7 @@ apple_register_profiles( ppd_option_t *cm_option; /* Color model option */ ppd_choice_t *cm_choice; /* Color model choice */ int num_profiles; /* Number of profiles */ - CMError error = 0; /* Last error */ + OSStatus error = 0; /* Last error */ unsigned device_id, /* Printer device ID */ profile_id, /* Profile ID */ default_profile_id = 0; @@ -3510,41 +3510,54 @@ apple_register_profiles( * See if this is the default profile... */ - if (!default_profile_id) + if (!default_profile_id && q1_choice && q2_choice && q3_choice) { - if (q2_choice) - { - if (q3_choice) - { - snprintf(selector, sizeof(selector), "%s.%s.%s", - q1_choice, q2_choice, q3_choice); - if (!strcmp(selector, attr->spec)) - default_profile_id = profile_id; - } + snprintf(selector, sizeof(selector), "%s.%s.%s", q1_choice, q2_choice, + q3_choice); + if (!strcmp(selector, attr->spec)) + default_profile_id = profile_id; + } - if (!default_profile_id) - { - snprintf(selector, sizeof(selector), "%s.%s.", q1_choice, - q2_choice); - if (!strcmp(selector, attr->spec)) - default_profile_id = profile_id; - } - } + if (!default_profile_id && q1_choice && q2_choice) + { + snprintf(selector, sizeof(selector), "%s.%s.", q1_choice, q2_choice); + if (!strcmp(selector, attr->spec)) + default_profile_id = profile_id; + } - if (!default_profile_id && q3_choice) - { - snprintf(selector, sizeof(selector), "%s..%s", q1_choice, - q3_choice); - if (!strcmp(selector, attr->spec)) - default_profile_id = profile_id; - } + if (!default_profile_id && q1_choice && q3_choice) + { + snprintf(selector, sizeof(selector), "%s..%s", q1_choice, q3_choice); + if (!strcmp(selector, attr->spec)) + default_profile_id = profile_id; + } - if (!default_profile_id) - { - snprintf(selector, sizeof(selector), "%s..", q1_choice); - if (!strcmp(selector, attr->spec)) - default_profile_id = profile_id; - } + if (!default_profile_id && q1_choice) + { + snprintf(selector, sizeof(selector), "%s..", q1_choice); + if (!strcmp(selector, attr->spec)) + default_profile_id = profile_id; + } + + if (!default_profile_id && q2_choice && q3_choice) + { + snprintf(selector, sizeof(selector), ".%s.%s", q2_choice, q3_choice); + if (!strcmp(selector, attr->spec)) + default_profile_id = profile_id; + } + + if (!default_profile_id && q2_choice) + { + snprintf(selector, sizeof(selector), ".%s.", q2_choice); + if (!strcmp(selector, attr->spec)) + default_profile_id = profile_id; + } + + if (!default_profile_id && q3_choice) + { + snprintf(selector, sizeof(selector), "..%s", q3_choice); + if (!strcmp(selector, attr->spec)) + default_profile_id = profile_id; } } @@ -7292,7 +7305,8 @@ get_document(cupsd_client_t *con, /* I - Client connection */ * Check policy... */ - if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) + if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, + job->username)) != HTTP_OK) { send_http_error(con, status, NULL); return; diff --git a/scheduler/main.c b/scheduler/main.c index 77982326f..9d99264f5 100644 --- a/scheduler/main.c +++ b/scheduler/main.c @@ -3,7 +3,7 @@ * * Main loop for the CUPS scheduler. * - * Copyright 2007-2010 by Apple Inc. + * Copyright 2007-2011 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -867,7 +867,7 @@ main(int argc, /* I - Number of command-line args */ cupsArrayCount(PrintingJobs) > 0) { SleepJobs = 0; - cupsdStopAllJobs(CUPSD_JOB_DEFAULT, 10); + cupsdStopAllJobs(CUPSD_JOB_DEFAULT, 5); } #endif /* __APPLE__ */ diff --git a/scheduler/printers.c b/scheduler/printers.c index 6a6614a91..bc8dbd993 100644 --- a/scheduler/printers.c +++ b/scheduler/printers.c @@ -4120,6 +4120,18 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "pages-per-minute-color", ppd->throughput); } + else + { + /* + * When there is no speed information, just say "1 page per minute". + */ + + ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "pages-per-minute", 1); + if (ppd->color_device) + ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "pages-per-minute-color", 1); + } num_qualities = 0; @@ -5044,16 +5056,20 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ CGImageDestinationFinalize(destRef); CFRelease(destRef); } + } + if (imageRef) CGImageRelease(imageRef); - } CFRelease(sourceRef); - CFRelease(icnsFileUrl); } + } + if (outUrl) CFRelease(outUrl); - } + + if (icnsFileUrl) + CFRelease(icnsFileUrl); } #endif /* HAVE_APPLICATIONSERVICES_H */ diff --git a/scheduler/process.c b/scheduler/process.c index 850217406..506ef13bc 100644 --- a/scheduler/process.c +++ b/scheduler/process.c @@ -3,7 +3,7 @@ * * Process management routines for the CUPS scheduler. * - * Copyright 2007-2010 by Apple Inc. + * Copyright 2007-2011 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -173,10 +173,28 @@ cupsdCreateProfile(int job_id) /* I - Job ID or 0 for none */ " #\"^/Library/Printers/PPD Plugins/\"" "))\n"); if (job_id) + { + /* + * Allow job filters to read the spool file(s)... + */ + cupsFilePrintf(fp, "(allow file-read-data file-read-metadata\n" " (regex #\"^%s/([ac]%05d|d%05d-[0-9][0-9][0-9])$\"))\n", request, job_id, job_id); + } + else + { + /* + * Allow email notifications from notifiers... + */ + + cupsFilePuts(fp, + "(allow process-exec\n" + " (literal \"/usr/sbin/sendmail\")\n" + " (with no-sandbox)\n" + ")\n"); + } cupsFileClose(fp); @@ -295,6 +313,7 @@ cupsdStartProcess( int *pid) /* O - Process ID */ { int i; /* Looping var */ + const char *exec_path = command; /* Command to be exec'd */ char *real_argv[103], /* Real command-line arguments */ cups_exec[1024]; /* Path to "cups-exec" program */ int user; /* Command UID */ @@ -445,8 +464,8 @@ cupsdStartProcess( real_argv[i + 3] = NULL; - argv = real_argv; - command = cups_exec; + argv = real_argv; + exec_path = cups_exec; } /* @@ -590,9 +609,9 @@ cupsdStartProcess( */ if (envp) - execve(command, argv, envp); + execve(exec_path, argv, envp); else - execv(command, argv); + execv(exec_path, argv); perror(command); @@ -620,7 +639,7 @@ cupsdStartProcess( { proc->pid = *pid; proc->job_id = job ? job->id : 0; - strcpy(proc->name, command); + _cups_strcpy(proc->name, command); cupsArrayAdd(process_array, proc); } diff --git a/scheduler/server.c b/scheduler/server.c index 438b142dc..c913469f0 100644 --- a/scheduler/server.c +++ b/scheduler/server.c @@ -131,7 +131,7 @@ cupsdStopServer(void) * Send one last notification as the server shuts down. */ - cupsdLogMessage(CUPSD_LOG_DEBUG, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "notify_post(\"com.apple.printerListChange\") last"); notify_post("com.apple.printerListChange"); #endif /* HAVE_NOTIFY_POST */ diff --git a/scheduler/sysman.c b/scheduler/sysman.c index e5c138e28..9bfc17abb 100644 --- a/scheduler/sysman.c +++ b/scheduler/sysman.c @@ -3,7 +3,7 @@ * * System management functions for the CUPS scheduler. * - * Copyright 2007-2010 by Apple Inc. + * Copyright 2007-2011 by Apple Inc. * Copyright 2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -832,8 +832,37 @@ sysUpdate(void) sysevent.powerNotificationID); else { - LastSysEvent = sysevent; - SleepJobs = time(NULL) + 15; + /* + * If there are active printers that don't have the connecting-to-device + * printer-state-reason then delay the sleep request (i.e. this reason + * indicates a job that is not yet connected to the printer)... + */ + + for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); + p; + p = (cupsd_printer_t *)cupsArrayNext(Printers)) + { + if (p->job) + { + for (i = 0; i < p->num_reasons; i ++) + if (!strcmp(p->reasons[i], "connecting-to-device")) + break; + + if (!p->num_reasons || i >= p->num_reasons) + break; + } + } + + if (p) + { + LastSysEvent = sysevent; + SleepJobs = time(NULL) + 10; + } + else + { + IOAllowPowerChange(sysevent.powerKernelPort, + sysevent.powerNotificationID); + } } } diff --git a/test/Makefile b/test/Makefile index dfbe4245a..b0dec1fb9 100644 --- a/test/Makefile +++ b/test/Makefile @@ -141,6 +141,15 @@ ippserver: ippserver.o ../cups/$(LIBCUPSSTATIC) $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) +# +# ippserver-shared +# + +ippserver-shared: ippserver.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ ippserver.o $(LIBS) + + # # ipptool # diff --git a/test/ippserver.c b/test/ippserver.c index d4133f607..484ada29d 100644 --- a/test/ippserver.c +++ b/test/ippserver.c @@ -3,7 +3,7 @@ * * Sample IPP/2.0 server for CUPS. * - * Copyright 2010 by Apple Inc. + * Copyright 2010-2011 by Apple Inc. * * These coded instructions, statements, and computer programs are the * property of Apple Inc. and are protected by Federal copyright @@ -799,7 +799,7 @@ copy_job_attributes( _ipp_job_t *job, /* I - Job */ cups_array_t *ra) /* I - requested-attributes */ { - copy_attributes(client->response, job->attrs, ra, 0, IPP_TAG_ZERO); + copy_attributes(client->response, job->attrs, ra, IPP_TAG_ZERO, 0); if (!ra || cupsArrayFind(ra, "job-printer-up-time")) ippAddInteger(client->response, IPP_TAG_JOB, IPP_TAG_INTEGER, @@ -814,46 +814,55 @@ copy_job_attributes( switch (job->state) { case IPP_JOB_PENDING : - ippAddString(client->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "job-state-reasons", NULL, "none"); + ippAddString(client->response, IPP_TAG_JOB, + IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons", + NULL, "none"); break; case IPP_JOB_HELD : if (job->fd >= 0) - ippAddString(client->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "job-state-reasons", NULL, "job-incoming"); + ippAddString(client->response, IPP_TAG_JOB, + IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons", + NULL, "job-incoming"); else if (ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_ZERO)) - ippAddString(client->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "job-state-reasons", NULL, "job-hold-until-specified"); + ippAddString(client->response, IPP_TAG_JOB, + IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons", + NULL, "job-hold-until-specified"); break; case IPP_JOB_PROCESSING : if (job->cancel) - ippAddString(client->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "job-state-reasons", NULL, "processing-to-stop-point"); + ippAddString(client->response, IPP_TAG_JOB, + IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons", + NULL, "processing-to-stop-point"); else - ippAddString(client->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "job-state-reasons", NULL, "job-printing"); + ippAddString(client->response, IPP_TAG_JOB, + IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons", + NULL, "job-printing"); break; case IPP_JOB_STOPPED : - ippAddString(client->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "job-state-reasons", NULL, "job-stopped"); + ippAddString(client->response, IPP_TAG_JOB, + IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons", + NULL, "job-stopped"); break; case IPP_JOB_CANCELED : - ippAddString(client->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "job-state-reasons", NULL, "job-canceled-by-user"); + ippAddString(client->response, IPP_TAG_JOB, + IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons", + NULL, "job-canceled-by-user"); break; case IPP_JOB_ABORTED : - ippAddString(client->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "job-state-reasons", NULL, "aborted-by-system"); + ippAddString(client->response, IPP_TAG_JOB, + IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons", + NULL, "aborted-by-system"); break; case IPP_JOB_COMPLETED : - ippAddString(client->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "job-state-reasons", NULL, "job-completed-successfully"); + ippAddString(client->response, IPP_TAG_JOB, + IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons", + NULL, "job-completed-successfully"); break; } } @@ -992,7 +1001,7 @@ create_job(_ipp_client_t *client) /* I - Client */ attr->name = _cupsStrAlloc("job-originating-user-name"); } else - attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, + attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME | IPP_TAG_COPY, "job-originating-user-name", NULL, "anonymous"); if (attr) @@ -1189,13 +1198,13 @@ create_printer(const char *servername, /* I - Server hostname (NULL for default) ipp_value_t *media_col_value; /* Current media-col-database value */ int k_supported; /* Maximum file size supported */ -#ifdef HAVE_STATFS - struct statfs spoolinfo; /* FS info for spool directory */ - double spoolsize; /* FS size */ -#elif defined(HAVE_STATVFS) +#ifdef HAVE_STATVFS struct statvfs spoolinfo; /* FS info for spool directory */ double spoolsize; /* FS size */ -#endif /* HAVE_STATFS */ +#elif defined(HAVE_STATFS) + struct statfs spoolinfo; /* FS info for spool directory */ + double spoolsize; /* FS size */ +#endif /* HAVE_STATVFS */ static const int orients[4] = /* orientation-requested-supported values */ { IPP_PORTRAIT, @@ -1391,19 +1400,19 @@ create_printer(const char *servername, /* I - Server hostname (NULL for default) * or the filesystem is larger than 2TiB, always report INT_MAX. */ -#ifdef HAVE_STATFS - if (statfs(printer->directory, &spoolinfo)) +#ifdef HAVE_STATVFS + if (statvfs(printer->directory, &spoolinfo)) k_supported = INT_MAX; - else if ((spoolsize = (double)spoolinfo.f_bsize * + else if ((spoolsize = (double)spoolinfo.f_frsize * spoolinfo.f_blocks / 1024) > INT_MAX) k_supported = INT_MAX; else k_supported = (int)spoolsize; -#elif defined(HAVE_STATVFS) - if (statvfs(printer->directory, &spoolinfo)) +#elif defined(HAVE_STATFS) + if (statfs(printer->directory, &spoolinfo)) k_supported = INT_MAX; - else if ((spoolsize = (double)spoolinfo.f_frsize * + else if ((spoolsize = (double)spoolinfo.f_bsize * spoolinfo.f_blocks / 1024) > INT_MAX) k_supported = INT_MAX; else @@ -1411,7 +1420,7 @@ create_printer(const char *servername, /* I - Server hostname (NULL for default) #else k_supported = INT_MAX; -#endif /* HAVE_STATFS */ +#endif /* HAVE_STATVFS */ /* * Create the printer attributes. This list of attributes is sorted to improve @@ -1445,8 +1454,8 @@ create_printer(const char *servername, /* I - Server hostname (NULL for default) ippAddRange(printer->attrs, IPP_TAG_PRINTER, "copies-supported", 1, 999); /* document-format-default */ - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE | IPP_TAG_COPY, - "document-format-default", NULL, "application/octet-stream"); + ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE, + "document-format-default", NULL, defformat); /* document-format-supported */ ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE, @@ -1647,11 +1656,11 @@ create_printer(const char *servername, /* I - Server hostname (NULL for default) "orientation-requested-supported", 4, orients); /* output-bin-default */ - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, "output-bin-default", NULL, "face-down"); /* output-bin-supported */ - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, "output-bin-supported", NULL, "face-down"); /* pages-per-minute */ @@ -1727,15 +1736,15 @@ create_printer(const char *servername, /* I - Server hostname (NULL for default) "sides-default", NULL, "one-sided"); /* sides-supported */ - ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, "sides-supported", duplex ? 3 : 1, NULL, sides_supported); /* uri-authentication-supported */ - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, "uri-authentication-supported", NULL, "none"); /* uri-security-supported */ - ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, "uri-security-supported", NULL, "none"); /* which-jobs-supported */ @@ -2771,8 +2780,9 @@ ipp_get_printer_attributes( if (!ra || cupsArrayFind(ra, "printer-state-reasons")) { if (printer->state_reasons == _IPP_PRINTER_NONE) - ippAddString(client->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "printer-state-reasons", NULL, "none"); + ippAddString(client->response, IPP_TAG_PRINTER, + IPP_TAG_KEYWORD | IPP_TAG_COPY, "printer-state-reasons", + NULL, "none"); else { int num_reasons = 0;/* Number of reasons */ @@ -2984,6 +2994,7 @@ ipp_print_job(_ipp_client_t *client) /* I - Client */ cupsArrayAdd(ra, "job-uri"); copy_job_attributes(client, job, ra); + cupsArrayDelete(ra); } @@ -3224,6 +3235,38 @@ process_http(_ipp_client_t *client) /* I - Client connection */ return (0); } + /* + * Handle HTTP Expect... + */ + + if (client->http.expect && + (client->operation == HTTP_POST || client->operation == HTTP_PUT)) + { + if (client->http.expect == HTTP_CONTINUE) + { + /* + * Send 100-continue header... + */ + + if (!respond_http(client, HTTP_CONTINUE, NULL, 0)) + return (0); + } + else + { + /* + * Send 417-expectation-failed header... + */ + + if (!respond_http(client, HTTP_EXPECTATION_FAILED, NULL, 0)) + return (0); + + httpPrintf(&(client->http), "Content-Length: 0\r\n"); + httpPrintf(&(client->http), "\r\n"); + httpFlushWrite(&(client->http)); + client->http.data_encoding = HTTP_ENCODE_LENGTH; + } + } + /* * Handle new transfers... */ @@ -3888,10 +3931,12 @@ respond_ipp(_ipp_client_t *client, /* I - Client */ if (!client->response->attrs) { - ippAddString(client->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET, - "attributes-charset", NULL, "utf-8"); - ippAddString(client->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, - "attributes-natural-language", NULL, "en-US"); + ippAddString(client->response, IPP_TAG_OPERATION, + IPP_TAG_CHARSET | IPP_TAG_COPY, "attributes-charset", NULL, + "utf-8"); + ippAddString(client->response, IPP_TAG_OPERATION, + IPP_TAG_LANGUAGE | IPP_TAG_COPY, "attributes-natural-language", + NULL, "en-us"); } if (message) @@ -3952,8 +3997,7 @@ run_printer(_ipp_printer_t *printer) /* I - Printer */ else timeout = -1; - if (poll(polldata, (int)(sizeof(polldata) / sizeof(polldata[0])), - timeout) < 0 && errno != EINTR) + if (poll(polldata, num_fds, timeout) < 0 && errno != EINTR) { perror("poll() failed"); break; @@ -4063,7 +4107,7 @@ valid_job_attributes( ippTagString(attr->value_tag)); \ valid = 0; \ } \ - copy_attribute(client->response, attr, 0, IPP_TAG_UNSUPPORTED_GROUP) + copy_attribute(client->response, attr, IPP_TAG_UNSUPPORTED_GROUP, 0) if ((attr = ippFindAttribute(client->request, "compression", IPP_TAG_ZERO)) != NULL) @@ -4094,7 +4138,13 @@ valid_job_attributes( respond_unsupported(client, attr); } else + { format = attr->values[0].string.text; + + fprintf(stderr, "%s %s document-format=\"%s\"\n", + client->http.hostname, + ippOpString(client->request->request.op.operation_id), format); + } } else format = "application/octet-stream"; @@ -4140,14 +4190,12 @@ valid_job_attributes( "document-format-supported", IPP_TAG_MIMETYPE)) != NULL) { - for (i = 0; i < attr->num_values; i ++) - if (!strcasecmp(format, attr->values[i].string.text)) + for (i = 0; i < supported->num_values; i ++) + if (!strcasecmp(format, supported->values[i].string.text)) break; - if (i >= attr->num_values) - { + if (i >= supported->num_values) respond_unsupported(client, attr); - } } /* diff --git a/test/ipptool.c b/test/ipptool.c index 9c096cd9a..969f15435 100644 --- a/test/ipptool.c +++ b/test/ipptool.c @@ -3,7 +3,7 @@ * * ipptool command for CUPS. * - * Copyright 2007-2010 by Apple Inc. + * Copyright 2007-2011 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -175,7 +175,7 @@ static char *get_token(FILE *fp, char *buf, int buflen, static char *get_variable(_cups_vars_t *vars, const char *name); static char *iso_date(ipp_uchar_t *date); static const char *password_cb(const char *prompt); -static void print_attr(ipp_attribute_t *attr); +static void print_attr(ipp_attribute_t *attr, ipp_tag_t *group); static void print_col(ipp_t *col); static void print_csv(ipp_attribute_t *attr, int num_displayed, char **displayed, size_t *widths); @@ -1314,7 +1314,37 @@ do_tests(_cups_vars_t *vars, /* I - Variables */ case IPP_TAG_INTEGER : case IPP_TAG_ENUM : - ippAddInteger(request, group, value, attr, atoi(token)); + if (!strchr(token, ',')) + ippAddInteger(request, group, value, attr, + strtol(token, &tokenptr, 0)); + else + { + int values[100], /* Values */ + num_values = 1; /* Number of values */ + + values[0] = strtol(token, &tokenptr, 10); + while (tokenptr && *tokenptr && + num_values < (int)(sizeof(values) / sizeof(values[0]))) + { + if (*tokenptr == ',') + tokenptr ++; + else if (!isdigit(*tokenptr & 255) && *tokenptr != '-') + break; + + values[num_values] = strtol(tokenptr, &tokenptr, 0); + num_values ++; + } + + ippAddIntegers(request, group, value, attr, num_values, values); + } + + if (!tokenptr || *tokenptr) + { + print_fatal_error("Bad %s value \"%s\" on line %d.", + ippTagString(value), token, linenum); + pass = 0; + goto test_exit; + } break; case IPP_TAG_RESOLUTION : @@ -1331,8 +1361,8 @@ do_tests(_cups_vars_t *vars, /* I - Variables */ } if (ptr <= token || xres <= 0 || yres <= 0 || !ptr || - (strcasecmp(ptr, "dpi") && strcasecmp(ptr, "dpc") && - strcasecmp(ptr, "other"))) + (strcasecmp(ptr, "dpi") && strcasecmp(ptr, "dpc") && + strcasecmp(ptr, "other"))) { print_fatal_error("Bad resolution value \"%s\" on line %d.", token, linenum); @@ -1827,10 +1857,14 @@ do_tests(_cups_vars_t *vars, /* I - Variables */ puts("Operation"); print_xml_string("string", ippOpString(op)); puts("RequestAttributes"); + puts(""); puts(""); - for (attrptr = request->attrs; attrptr; attrptr = attrptr->next) - print_attr(attrptr); + for (attrptr = request->attrs, group = attrptr->group_tag; + attrptr; + attrptr = attrptr->next) + print_attr(attrptr, &group); puts(""); + puts(""); } else if (Output == _CUPS_OUTPUT_TEST) { @@ -1839,7 +1873,7 @@ do_tests(_cups_vars_t *vars, /* I - Variables */ printf(" %s:\n", ippOpString(op)); for (attrptr = request->attrs; attrptr; attrptr = attrptr->next) - print_attr(attrptr); + print_attr(attrptr, NULL); } printf(" %-69.69s [", name); @@ -2099,12 +2133,15 @@ do_tests(_cups_vars_t *vars, /* I - Variables */ puts("StatusCode"); print_xml_string("string", ippErrorString(cupsLastError())); puts("ResponseAttributes"); + puts(""); puts(""); - for (attrptr = response ? response->attrs : NULL; + for (attrptr = response ? response->attrs : NULL, + group = attrptr ? attrptr->group_tag : IPP_TAG_ZERO; attrptr; attrptr = attrptr->next) - print_attr(attrptr); + print_attr(attrptr, &group); puts(""); + puts(""); } else if (Output == _CUPS_OUTPUT_TEST) { @@ -2121,7 +2158,7 @@ do_tests(_cups_vars_t *vars, /* I - Variables */ attrptr != NULL; attrptr = attrptr->next) { - print_attr(attrptr); + print_attr(attrptr, NULL); } } } @@ -2187,7 +2224,7 @@ do_tests(_cups_vars_t *vars, /* I - Variables */ { if (!strcmp(displayed[i], attrptr->name)) { - print_attr(attrptr); + print_attr(attrptr, NULL); break; } } @@ -2342,9 +2379,25 @@ do_tests(_cups_vars_t *vars, /* I - Variables */ if (i == num_statuses && num_statuses > 0) { - print_test_error("Bad status-code (%s)", - ippErrorString(cupsLastError())); - print_test_error("status-message=\"%s\"", cupsLastErrorString()); + for (i = 0; i < num_statuses; i ++) + { + if (statuses[i].if_defined && + !get_variable(vars, statuses[i].if_defined)) + continue; + + if (statuses[i].if_not_defined && + get_variable(vars, statuses[i].if_not_defined)) + continue; + + print_test_error("EXPECTED: STATUS %s (got %s)", + ippErrorString(statuses[i].status), + ippErrorString(cupsLastError())); + } + + if ((attrptr = ippFindAttribute(response, "status-message", + IPP_TAG_TEXT)) != NULL) + print_test_error("status-message=\"%s\"", + attrptr->values[0].string.text); } for (i = num_expects, expect = expects; i > 0; i --, expect ++) @@ -3134,7 +3187,8 @@ password_cb(const char *prompt) /* I - Prompt (unused) */ */ static void -print_attr(ipp_attribute_t *attr) /* I - Attribute to print */ +print_attr(ipp_attribute_t *attr, /* I - Attribute to print */ + ipp_tag_t *group) /* IO - Current group */ { int i; /* Looping var */ ipp_attribute_t *colattr; /* Collection attribute */ @@ -3142,12 +3196,18 @@ print_attr(ipp_attribute_t *attr) /* I - Attribute to print */ if (Output == _CUPS_OUTPUT_PLIST) { - if (!attr->name) + if (!attr->name || (group && *group != attr->group_tag)) { - printf("%s\n\n", ippTagString(attr->group_tag)); - return; + puts(""); + puts(""); + + if (group) + *group = attr->group_tag; } + if (!attr->name) + return; + print_xml_string("key", attr->name); if (attr->num_values > 1) puts(""); @@ -3249,7 +3309,7 @@ print_attr(ipp_attribute_t *attr) /* I - Attribute to print */ puts(""); } else - printf("\"%s\",%s ", attr->values[i].string.text, + printf("\"%s\"(%s) ", attr->values[i].string.text, attr->values[i].string.charset); break; @@ -3262,7 +3322,7 @@ print_attr(ipp_attribute_t *attr) /* I - Attribute to print */ for (colattr = attr->values[i].collection->attrs; colattr; colattr = colattr->next) - print_attr(colattr); + print_attr(colattr, NULL); puts(""); } else -- 2.39.2