/*
* IPP backend for CUPS.
*
- * Copyright © 2007-2019 by Apple Inc.
+ * Copyright © 2021 by OpenPrinting
+ * Copyright © 2007-2021 by Apple Inc.
* Copyright © 1997-2007 by Easy Software Products, all rights reserved.
*
* Licensed under Apache License v2.0. See the file "LICENSE" for more
int waitjob, /* Wait for job complete? */
waitjob_tries = 0, /* Number of times we've waited */
waitprinter; /* Wait for printer ready? */
- time_t waittime; /* Wait time for held jobs */
_cups_monitor_t monitor; /* Monitoring data */
ipp_attribute_t *job_id_attr; /* job-id attribute */
int job_id; /* job-id value */
get_job_attrs = 0, /* Does printer support Get-Job-Attributes? */
send_document = 0, /* Does printer support Send-Document? */
validate_job = 0, /* Does printer support Validate-Job? */
+ validate_retried = 0, /* Was Validate-Job request retried? */
copies, /* Number of copies for job */
copies_remaining; /* Number of copies remaining */
const char *content_type, /* CONTENT_TYPE environment variable */
ipp_status == IPP_STATUS_ERROR_BAD_REQUEST)
break;
else if (job_auth == NULL && ipp_status > IPP_STATUS_ERROR_BAD_REQUEST)
+ {
+ if (!validate_retried)
+ {
+ // Retry Validate-Job operation once, to work around known printer bug...
+ validate_retried = 1;
+ sleep(10);
+ continue;
+ }
+
goto cleanup;
+ }
}
/*
_cupsLangPrintFilter(stderr, "INFO", _("Waiting for job to complete."));
- for (delay = _cupsNextDelay(0, &prev_delay), waittime = time(NULL) + 30; !job_canceled;)
+ for (delay = _cupsNextDelay(0, &prev_delay); !job_canceled;)
{
/*
* Check for side-channel requests...
job_sheets->values[0].integer);
/*
- * Stop polling if the job is finished or pending-held for 30 seconds...
+ * Stop polling if the job is finished or pending-held...
*/
- if (job_state->values[0].integer > IPP_JSTATE_STOPPED ||
- (job_state->values[0].integer == IPP_JSTATE_HELD && time(NULL) > waittime))
+ if (job_state->values[0].integer > IPP_JSTATE_STOPPED || job_state->values[0].integer == IPP_JSTATE_HELD)
{
ippDelete(response);
break;
else if (ipp_status == IPP_STATUS_ERROR_CUPS_ACCOUNT_AUTHORIZATION_FAILED)
fputs("JOBSTATE: account-authorization-failed\n", stderr);
- if (job_canceled)
+ // job_canceled can be -1 which should not be treated as CUPS_BACKEND_OK
+ if (job_canceled > 0)
return (CUPS_BACKEND_OK);
else if (ipp_status == IPP_STATUS_ERROR_NOT_AUTHORIZED || ipp_status == IPP_STATUS_ERROR_FORBIDDEN || ipp_status == IPP_STATUS_ERROR_CUPS_AUTHENTICATION_CANCELED)
return (CUPS_BACKEND_AUTH_REQUIRED);
*/
_httpDecodeURI(phone, keyword, sizeof(phone));
- for (ptr = phone; *ptr;)
+ ptr = phone;
+
+ /*
+ * Weed out "Custom." in the beginning, this allows to put the
+ * "phone" option as custom string option into the PPD so that
+ * print dialogs not supporting fax display the option and
+ * allow entering the phone number. Print dialogs also send "None"
+ * if no phone number got entered, filter this, too.
+ */
+ if (!_cups_strcasecmp(phone, "None"))
+ *ptr = '\0';
+ if (!_cups_strncasecmp(phone, "Custom.", 7))
+ _cups_strcpy(ptr, ptr + 7);
+
+ for (; *ptr;)
{
if (*ptr == ',')
*ptr = 'p';
ptr ++;
}
- httpAssembleURI(HTTP_URI_CODING_ALL, tel_uri, sizeof(tel_uri), "tel", NULL, NULL, 0, phone);
- ippAddString(destination, IPP_TAG_JOB, IPP_TAG_URI, "destination-uri", NULL, tel_uri);
-
- if ((keyword = cupsGetOption("faxPrefix", num_options,
- options)) != NULL && *keyword)
+ if (strlen(phone) > 0)
{
- char predial[1024]; /* Pre-dial string */
+ httpAssembleURI(HTTP_URI_CODING_ALL, tel_uri, sizeof(tel_uri), "tel", NULL, NULL, 0, phone);
+ ippAddString(destination, IPP_TAG_JOB, IPP_TAG_URI, "destination-uri", NULL, tel_uri);
+ fprintf(stderr, "DEBUG: Faxing to phone %s; destination-uri: %s\n", phone, tel_uri);
- _httpDecodeURI(predial, keyword, sizeof(predial));
- ippAddString(destination, IPP_TAG_JOB, IPP_TAG_TEXT, "pre-dial-string", NULL, predial);
- }
+ if ((keyword = cupsGetOption("faxPrefix", num_options, options)) != NULL && *keyword)
+ {
+ char predial[1024]; /* Pre-dial string */
+
+ _httpDecodeURI(predial, keyword, sizeof(predial));
+ ptr = predial;
+ if (!_cups_strcasecmp(ptr, "None"))
+ *ptr = '\0';
+ if (!_cups_strncasecmp(ptr, "Custom.", 7))
+ ptr += 7;
+ if (strlen(ptr) > 0)
+ {
+ ippAddString(destination, IPP_TAG_JOB, IPP_TAG_TEXT, "pre-dial-string", NULL, ptr);
+ fprintf(stderr, "DEBUG: Pre-dialing %s; pre-dial-string: %s\n", ptr, ptr);
+ }
+ else
+ fprintf(stderr, "WARNING: Pre-dial number for fax not valid! Sending fax without pre-dial number.\n");
+ }
- ippAddCollection(request, IPP_TAG_JOB, "destination-uris", destination);
- ippDelete(destination);
+ ippAddCollection(request, IPP_TAG_JOB, "destination-uris", destination);
+ ippDelete(destination);
+ }
+ else
+ fprintf(stderr, "ERROR: Phone number for fax not valid! Fax cannot be sent.\n");
}
}
else
* Report alerts and messages...
*/
- if ((pa = ippFindAttribute(ipp, "printer-alert", IPP_TAG_TEXT)) != NULL)
+ if ((pa = ippFindAttribute(ipp, "printer-alert", IPP_TAG_STRING)) != NULL)
report_attr(pa);
if ((pam = ippFindAttribute(ipp, "printer-alert-message",
if (*ptr < ' ' && *ptr > 0 && *ptr != '\t')
{
/*
- * Substitute "<XX>" for the control character; sprintf is safe because
- * we always leave 6 chars free at the end...
+ * Substitute "<XX>" for the control character...
*/
- sprintf(valptr, "<%02X>", *ptr);
+ snprintf(valptr, sizeof(value) - (size_t)(valptr - value), "<%02X>", *ptr);
valptr += 4;
}
else
const char *device_uri, /* I - Device URI */
int fd) /* I - File to print */
{
- const char *auth_negotiate;/* AUTH_NEGOTIATE env var */
+ const char *auth_negotiate,/* AUTH_NEGOTIATE env var */
+ *content_type; /* [FINAL_]CONTENT_TYPE env vars */
xpc_connection_t conn; /* Connection to XPC service */
xpc_object_t request; /* Request message dictionary */
__block xpc_object_t response; /* Response message dictionary */
getenv("AUTH_INFO_REQUIRED"));
if ((auth_negotiate = getenv("AUTH_NEGOTIATE")) != NULL)
xpc_dictionary_set_string(request, "auth-negotiate", auth_negotiate);
+ if ((content_type = getenv("CONTENT_TYPE")) != NULL)
+ xpc_dictionary_set_string(request, "content-type", content_type);
+ if ((content_type = getenv("FINAL_CONTENT_TYPE")) != NULL)
+ xpc_dictionary_set_string(request, "final-content-type", content_type);
xpc_dictionary_set_fd(request, "stdin", fd);
xpc_dictionary_set_fd(request, "stderr", 2);
xpc_dictionary_set_fd(request, "side-channel", CUPS_SC_FD);
{
(void)sig; /* remove compiler warnings... */
- write(2, "DEBUG: Got SIGTERM.\n", 20);
+ backendMessage("DEBUG: Got SIGTERM.\n");
#if defined(HAVE_GSSAPI) && defined(HAVE_XPC)
if (child_pid)
* Flag that the job should be canceled...
*/
- write(2, "DEBUG: sigterm_handler: job_canceled = 1.\n", 25);
+ backendMessage("DEBUG: sigterm_handler: job_canceled = 1.\n");
job_canceled = 1;
return;