# include <arpa/inet.h>
# include <netdb.h>
#endif /* WIN32 */
+#ifdef __APPLE__
+# include <CoreFoundation/CFNumber.h>
+# include <CoreFoundation/CFPreferences.h>
+#endif /* __APPLE__ */
/*
const char *filename,
const char *user, const char *title, int copies,
int banner, int format, int order, int reserve,
- int manual_copies, int timeout);
+ int manual_copies, int timeout, int contimeout);
static void lpd_timeout(int sig);
static int lpd_write(int lpd_fd, char *buffer, int length);
#ifndef HAVE_RRESVPORT_AF
int sanitize_title; /* Sanitize title string? */
int manual_copies, /* Do manual copies? */
timeout, /* Timeout */
+ contimeout, /* Connection timeout */
copies; /* Number of copies */
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
struct sigaction action; /* Actions for POSIX signals */
* See if there are any options...
*/
- banner = 0;
- format = 'l';
- order = ORDER_CONTROL_DATA;
- reserve = RESERVE_ANY;
- manual_copies = 1;
- timeout = 300;
- sanitize_title = 1;
+ banner = 0;
+ format = 'l';
+ order = ORDER_CONTROL_DATA;
+ reserve = RESERVE_ANY;
+ manual_copies = 1;
+ timeout = 300;
+ contimeout = 7 * 24 * 60 * 60;
-#if defined(__APPLE__)
+#ifdef __APPLE__
/* We want to pass utf-8 characters, not re-map them (3071945) */
- sanitize_title= 0;
-#endif
+ sanitize_title = 0;
+
+ {
+ CFPropertyListRef pvalue; /* Preference value */
+ SInt32 toval; /* Timeout value */
+
+
+ pvalue = CFPreferencesCopyValue(CFSTR("timeout"),
+ CFSTR("com.apple.print.backends"),
+ kCFPreferencesAnyUser,
+ kCFPreferencesCurrentHost);
+ if (pvalue)
+ {
+ if (CFGetTypeID(pvalue) == CFNumberGetTypeID())
+ {
+ CFNumberGetValue(pvalue, kCFNumberSInt32Type, &toval);
+ contimeout = (int)toval;
+ }
+
+ CFRelease(pvalue);
+ }
+ }
+#else
+ sanitize_title = 1;
+#endif /* __APPLE__ */
if ((options = strchr(resource, '?')) != NULL)
{
*ptr++ = *options++;
*ptr = '\0';
- if (*options == '+')
+ if (*options == '+' || *options == '&')
options ++;
}
else
* Process the option...
*/
- if (strcasecmp(name, "banner") == 0)
+ if (!strcasecmp(name, "banner"))
{
/*
* Set the banner...
*/
- banner = !value[0] ||
- strcasecmp(value, "on") == 0 ||
- strcasecmp(value, "yes") == 0 ||
- strcasecmp(value, "true") == 0;
+ banner = !value[0] || !strcasecmp(value, "on") ||
+ !strcasecmp(value, "yes") || !strcasecmp(value, "true");
}
- else if (strcasecmp(name, "format") == 0 && value[0])
+ else if (!strcasecmp(name, "format") && value[0])
{
/*
* Set output format...
*/
- if (strchr("cdfglnoprtv", value[0]) != NULL)
+ if (strchr("cdfglnoprtv", value[0]))
format = value[0];
else
fprintf(stderr, "ERROR: Unknown format character \"%c\"\n", value[0]);
}
- else if (strcasecmp(name, "order") == 0 && value[0])
+ else if (!strcasecmp(name, "order") && value[0])
{
/*
* Set control/data order...
*/
- if (strcasecmp(value, "control,data") == 0)
+ if (!strcasecmp(value, "control,data"))
order = ORDER_CONTROL_DATA;
- else if (strcasecmp(value, "data,control") == 0)
+ else if (!strcasecmp(value, "data,control"))
order = ORDER_DATA_CONTROL;
else
fprintf(stderr, "ERROR: Unknown file order \"%s\"\n", value);
}
- else if (strcasecmp(name, "reserve") == 0)
+ else if (!strcasecmp(name, "reserve"))
{
/*
* Set port reservation mode...
*/
- if (!value[0] ||
- !strcasecmp(value, "on") ||
- !strcasecmp(value, "yes") ||
- !strcasecmp(value, "true") ||
+ if (!value[0] || !strcasecmp(value, "on") ||
+ !strcasecmp(value, "yes") || !strcasecmp(value, "true") ||
!strcasecmp(value, "rfc1179"))
reserve = RESERVE_RFC1179;
else if (!strcasecmp(value, "any"))
else
reserve = RESERVE_NONE;
}
- else if (strcasecmp(name, "manual_copies") == 0)
+ else if (!strcasecmp(name, "manual_copies"))
{
/*
* Set manual copies...
*/
- manual_copies = !value[0] ||
- strcasecmp(value, "on") == 0 ||
- strcasecmp(value, "yes") == 0 ||
- strcasecmp(value, "true") == 0;
+ manual_copies = !value[0] || !strcasecmp(value, "on") ||
+ !strcasecmp(value, "yes") || !strcasecmp(value, "true");
}
- else if (strcasecmp(name, "sanitize_title") == 0)
+ else if (!strcasecmp(name, "sanitize_title"))
{
/*
* Set sanitize title...
*/
- sanitize_title = !value[0] ||
- strcasecmp(value, "on") == 0 ||
- strcasecmp(value, "yes") == 0 ||
- strcasecmp(value, "true") == 0;
+ sanitize_title = !value[0] || !strcasecmp(value, "on") ||
+ !strcasecmp(value, "yes") || !strcasecmp(value, "true");
}
- else if (strcasecmp(name, "timeout") == 0)
+ else if (!strcasecmp(name, "timeout"))
{
/*
* Set the timeout...
if (atoi(value) > 0)
timeout = atoi(value);
}
+ else if (!strcasecmp(name, "contimeout"))
+ {
+ /*
+ * Set the timeout...
+ */
+
+ if (atoi(value) > 0)
+ contimeout = atoi(value);
+ }
}
}
status = lpd_queue(hostname, port, resource + 1, filename,
username, title, copies,
- banner, format, order, reserve, manual_copies, timeout);
+ banner, format, order, reserve, manual_copies,
+ timeout, contimeout);
if (!status)
fprintf(stderr, "PAGE: 1 %d\n", atoi(argv[4]));
else
status = lpd_queue(hostname, port, resource + 1, filename,
username, title, 1,
- banner, format, order, reserve, 1, timeout);
+ banner, format, order, reserve, 1,
+ timeout, contimeout);
/*
* Remove the temporary file if necessary...
int order, /* I - Order of data/control files */
int reserve, /* I - Reserve ports? */
int manual_copies, /* I - Do copies by hand... */
- int timeout) /* I - Timeout... */
+ int timeout, /* I - Timeout... */
+ int contimeout) /* I - Connection timeout */
{
FILE *fp; /* Job file */
char localhost[255]; /* Local host name */
http_addrlist_t *addrlist, /* Address list */
*addr; /* Socket address */
int copy; /* Copies written */
+ time_t start_time; /* Time of first connect */
+#ifdef __APPLE__
+ int recoverable; /* Recoverable error shown? */
+#endif /* __APPLE__ */
size_t nbytes; /* Number of bytes written */
off_t tbytes; /* Total bytes written */
char buffer[65536]; /* Output buffer */
return (CUPS_BACKEND_STOP);
}
+ /*
+ * Remember when we starting trying to connect to the printer...
+ */
+
+#ifdef __APPLE__
+ recoverable = 0;
+#endif /* __APPLE__ */
+ start_time = time(NULL);
+
/*
* Loop forever trying to print the file...
*/
if (error == ECONNREFUSED || error == EHOSTDOWN ||
error == EHOSTUNREACH)
{
- fprintf(stderr, "WARNING: Network host \'%s\' is busy, down, or unreachable; will retry in 30 seconds...\n",
+ if (contimeout && (time(NULL) - start_time) > contimeout)
+ {
+ fputs("ERROR: Printer not responding!\n", stderr);
+ return (CUPS_BACKEND_FAILED);
+ }
+
+#ifdef __APPLE__
+ recoverable = 1;
+ fprintf(stderr, "WARNING: recoverable: "
+#else
+ fprintf(stderr, "WARNING: "
+#endif /* __APPLE__ */
+ "Network host \'%s\' is busy, down, or "
+ "unreachable; will retry in 30 seconds...\n",
hostname);
sleep(30);
}
}
else
{
- perror("ERROR: Unable to connect to printer; will retry in 30 seconds...");
+#ifdef __APPLE__
+ recoverable = 1;
+ perror("ERROR: recoverable: "
+#else
+ perror("ERROR: "
+#endif /* __APPLE__ */
+ "Unable to connect to printer; will retry in 30 seconds...");
sleep(30);
}
}
+ if (recoverable)
+ {
+ /*
+ * If we've shown a recoverable error make sure the printer proxies
+ * have a chance to see the recovered message. Not pretty but
+ * necessary for now...
+ */
+
+ fputs("INFO: recovered: \n", stderr);
+ sleep(5);
+ }
+
fprintf(stderr, "INFO: Connected to %s...\n", hostname);
fprintf(stderr, "DEBUG: Connected on ports %d (local %d)...\n", port,
lport);
char method[255], /* Method in URI */
hostname[1024], /* Hostname */
username[255], /* Username info (not used) */
- resource[1024]; /* Resource info (not used) */
+ resource[1024], /* Resource info (not used) */
+ *options, /* Pointer to options */
+ name[255], /* Name of option */
+ value[255], /* Value of option */
+ *ptr; /* Pointer into name or value */
int fp; /* Print file */
int copies; /* Number of copies to print */
+ int waiteof; /* Wait for end-of-file? */
int port; /* Port number */
char portname[255]; /* Port name */
int delay; /* Delay for retries... */
if (port == 0)
port = 9100; /* Default to HP JetDirect/Tektronix PhaserShare */
+ /*
+ * Get options, if any...
+ */
+
+ waiteof = 1;
+
+ if ((options = strchr(resource, '?')) != NULL)
+ {
+ /*
+ * Yup, terminate the device name string and move to the first
+ * character of the options...
+ */
+
+ *options++ = '\0';
+
+ /*
+ * Parse options...
+ */
+
+ while (*options)
+ {
+ /*
+ * Get the name...
+ */
+
+ for (ptr = name; *options && *options != '=';)
+ if (ptr < (name + sizeof(name) - 1))
+ *ptr++ = *options++;
+ *ptr = '\0';
+
+ if (*options == '=')
+ {
+ /*
+ * Get the value...
+ */
+
+ options ++;
+
+ for (ptr = value; *options && *options != '+' && *options != '&';)
+ if (ptr < (value + sizeof(value) - 1))
+ *ptr++ = *options++;
+ *ptr = '\0';
+
+ if (*options == '+' || *options == '&')
+ options ++;
+ }
+ else
+ value[0] = '\0';
+
+ /*
+ * Process the option...
+ */
+
+ if (!strcasecmp(name, "waiteof"))
+ {
+ /*
+ * Set the wait-for-eof value...
+ */
+
+ waiteof = !value[0] || !strcasecmp(value, "on") ||
+ !strcasecmp(value, "yes") || !strcasecmp(value, "true");
+ }
+ }
+ }
+
/*
* Then try to connect to the remote host...
*/
(unsigned long)tbytes);
}
- /*
- * Shutdown the socket and wait for the other end to finish...
- */
-
- fputs("INFO: Print file sent, waiting for printer to finish...\n", stderr);
-
- shutdown(fd, 1);
-
- for (;;)
+ if (waiteof)
{
/*
- * Wait a maximum of 90 seconds for backchannel data or a closed
- * connection...
+ * Shutdown the socket and wait for the other end to finish...
*/
- timeout.tv_sec = 90;
- timeout.tv_usec = 0;
+ fputs("INFO: Print file sent, waiting for printer to finish...\n", stderr);
- FD_ZERO(&input);
- FD_SET(fd, &input);
+ shutdown(fd, 1);
-#ifdef __hpux
- if (select(fd + 1, (int *)&input, NULL, NULL, &timeout) > 0)
-#else
- if (select(fd + 1, &input, NULL, NULL, &timeout) > 0)
-#endif /* __hpux */
+ for (;;)
{
/*
- * Grab the data coming back and spit it out to stderr...
+ * Wait a maximum of 90 seconds for backchannel data or a closed
+ * connection...
*/
- if ((rbytes = recv(fd, resource, sizeof(resource), 0)) > 0)
+ timeout.tv_sec = 90;
+ timeout.tv_usec = 0;
+
+ FD_ZERO(&input);
+ FD_SET(fd, &input);
+
+ #ifdef __hpux
+ if (select(fd + 1, (int *)&input, NULL, NULL, &timeout) > 0)
+ #else
+ if (select(fd + 1, &input, NULL, NULL, &timeout) > 0)
+ #endif /* __hpux */
{
- fprintf(stderr, "DEBUG: Received %d bytes of back-channel data!\n",
- rbytes);
- cupsBackchannelWrite(resource, rbytes, 1.0);
- }
+ /*
+ * Grab the data coming back and spit it out to stderr...
+ */
+
+ if ((rbytes = recv(fd, resource, sizeof(resource), 0)) > 0)
+ {
+ fprintf(stderr, "DEBUG: Received %d bytes of back-channel data!\n",
+ rbytes);
+ cupsBackchannelWrite(resource, rbytes, 1.0);
+ }
+ else
+ break;
+ }
else
break;
}
- else
- break;
}
/*
*/
int
-main(int argc, /* I - Number of command-line arguments */
- char *argv[]) /* I - Command-line arguments */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
{
- int i, j; /* Looping var */
- int job_id; /* Job ID */
- char ch; /* Option character */
- char *printer, /* Destination printer or class */
- *instance; /* Instance */
- const char *title, /* Job title */
- *val; /* Environment variable name */
- int num_copies; /* Number of copies per file */
- int num_files; /* Number of files to print */
- const char *files[1000]; /* Files to print */
- int num_dests; /* Number of destinations */
- cups_dest_t *dests, /* Destinations */
- *dest; /* Selected destination */
- int num_options; /* Number of options */
- cups_option_t *options; /* Options */
- int deletefile; /* Delete file after print? */
- char buffer[8192]; /* Copy buffer */
- int temp; /* Temporary file descriptor */
- cups_lang_t *language; /* Language information */
+ int i, j; /* Looping var */
+ int job_id; /* Job ID */
+ char ch; /* Option character */
+ char *printer, /* Destination printer or class */
+ *instance; /* Instance */
+ const char *title, /* Job title */
+ *val; /* Environment variable name */
+ int num_copies; /* Number of copies per file */
+ int num_files; /* Number of files to print */
+ const char *files[1000]; /* Files to print */
+ int num_dests; /* Number of destinations */
+ cups_dest_t *dests, /* Destinations */
+ *dest; /* Selected destination */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+ int deletefile; /* Delete file after print? */
+ char buffer[8192]; /* Copy buffer */
+ ssize_t bytes; /* Bytes copied */
+ off_t filesize; /* Size of temp file */
+ int temp; /* Temporary file descriptor */
+ cups_lang_t *language; /* Language information */
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
- struct sigaction action; /* Signal action */
- struct sigaction oldaction; /* Old signal action */
+ struct sigaction action; /* Signal action */
+ struct sigaction oldaction; /* Old signal action */
#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
return (1);
}
- while ((i = read(0, buffer, sizeof(buffer))) > 0)
- if (write(temp, buffer, i) < 0)
+ while ((bytes = read(0, buffer, sizeof(buffer))) > 0)
+ if (write(temp, buffer, bytes) < 0)
{
_cupsLangPrintf(stderr,
_("%s: Error - unable to write to temporary file "
return (1);
}
- i = lseek(temp, 0, SEEK_CUR);
+ filesize = lseek(temp, 0, SEEK_CUR);
close(temp);
- if (i == 0)
+ if (filesize <= 0)
{
_cupsLangPrintf(stderr,
_("%s: Error - stdin is empty, so no job has been sent.\n"),
*/
void
-sighandler(int s) /* I - Signal number */
+sighandler(int s) /* I - Signal number */
{
/*
* Remove the temporary file we're using to print from stdin...
*dest; /* Selected destination */
int num_options; /* Number of options */
cups_option_t *options; /* Options */
+ int end_options; /* No more options? */
int silent; /* Silent or verbose output? */
char buffer[8192]; /* Copy buffer */
+ ssize_t bytes; /* Bytes copied */
+ off_t filesize; /* Size of temp file */
int temp; /* Temporary file descriptor */
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
struct sigaction action; /* Signal action */
num_files = 0;
title = NULL;
job_id = 0;
+ end_options = 0;
for (i = 1; i < argc; i ++)
- if (argv[i][0] == '-' && argv[i][1])
+ if (argv[i][0] == '-' && argv[i][1] && !end_options)
switch (argv[i][1])
{
case 'E' : /* Encrypt */
num_options = cupsAddOption("notify-recipient", email,
num_options, &options);
}
+
+ silent = 1;
break;
case 'n' : /* Number of copies */
argv[0]);
break;
+ case '-' : /* Stop processing options */
+ end_options = 1;
+ break;
+
default :
_cupsLangPrintf(stderr, _("%s: Error - unknown option \'%c\'!\n"),
argv[0], argv[i][1]);
return (1);
}
- while ((i = read(0, buffer, sizeof(buffer))) > 0)
- if (write(temp, buffer, i) < 0)
+ while ((bytes = read(0, buffer, sizeof(buffer))) > 0)
+ if (write(temp, buffer, bytes) < 0)
{
_cupsLangPrintf(stderr,
_("%s: Error - unable to write to temporary file "
return (1);
}
- i = lseek(temp, 0, SEEK_CUR);
+ filesize = lseek(temp, 0, SEEK_CUR);
close(temp);
- if (i == 0)
+ if (filesize <= 0)
{
_cupsLangPrintf(stderr,
_("%s: Error - stdin is empty, so no job has been sent.\n"),
*/
void
-sighandler(int s) /* I - Signal number */
+sighandler(int s) /* I - Signal number */
{
/*
* Remove the temporary file we're using to print from stdin...