diff options
Diffstat (limited to 'bjnp.c')
-rw-r--r-- | bjnp.c | 710 |
1 files changed, 347 insertions, 363 deletions
@@ -1,32 +1,28 @@ /* - * bjnp backend for the Common UNIX Printing System (CUPS). - * Copyright 2008 by Louis Lagendijk + * bjnp backend for the Common UNIX Printing System (CUPS). + * Copyright 2008-2014 by Louis Lagendijk * - * heavily based on cups AppSocket sources - * Copyright 2007 by Apple Inc. - * Copyright 1997-2007 by Easy Software Products, all rights reserved. + * Based on cups AppSocket sources + * Copyright 2007 by Apple Inc. + * Copyright 1997-2007 by Easy Software Products, all rights reserved. * - * These coded instructions, statements, and computer programs are the - * property of Apple Inc. and are protected by Federal copyright - * law. Distribution and use rights are outlined in the file "LICENSE.txt" - * "LICENSE" which should have been included with this file. If this - * file is missing or damaged, see the license at "http://www.cups.org/". + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 only. * - * This file is subject to the Apple OS-Developed Software exception. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * Contents: - * - * main() - Send a file to the printer or server. - * side_cb() - removed and integrated in main loop of RunLoop - * wait_bc() - removed as bjnp does not have a true backchannel - * it is used to send acks only + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* * Include necessary headers. */ -#include "bjnp.h" #include <stdio.h> #include <stdarg.h> #include <sys/types.h> @@ -44,6 +40,7 @@ # include <arpa/inet.h> # include <netdb.h> #endif /* WIN32 */ +#include "bjnp.h" /* @@ -54,399 +51,386 @@ * printer-uri job-id user title copies options [file] */ -int /* O - Exit status */ -main (int argc, /* I - Number of command-line arguments (6 or 7) */ - char *argv[]) /* I - Command-line arguments */ +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + /* (6 or 7) */ + char *argv[]) /* I - Command-line arguments */ { - char method[255], /* Method in URI */ - hostname[1024], /* Hostname */ - username[255], /* Username info (not used) */ - resource[1024], /* Resource info (not used) */ - *options, /* Pointer to options */ - *name, /* Name of option */ - *value, /* Value of option */ - sep; /* Option separator */ - int print_fd; /* Print file */ - int copies; /* Number of copies to print */ - time_t start_time; /* Time of first connect */ - int recoverable; /* Recoverable error shown? */ - int contimeout; /* Connection timeout */ - int port; /* Port number */ - char portname[255]; /* Port name */ - int delay; /* Delay for retries... */ - int device_fd; /* AppSocket */ - int error; /* Error code (if any) */ - int i; /* loop variable */ - http_addrlist_t *addrlist; /* Address list */ - http_addr_t *addr; /* Connected address */ - char addrname[256]; /* Address name */ - ssize_t tbytes; /* Total number of bytes written */ - char *bjnp_debugstr; /* environment string */ + char method[255]; /* Method in URI */ + char hostname[1024]; /* Hostname */ + char username[255]; /* Username info (not used) */ + char resource[1024]; /* Resource info */ + char *options; /* Pointer to options in device URI*/ + char *name; /* Name of option in device URI*/ + char *value; /* Value of option in device URI*/ + char sep; /* Option separator */ + int print_fd; /* Print file */ + int copies; /* Number of copies to print */ + time_t start_time; /* Time of first connect */ + int recoverable; /* Recoverable error shown? */ + int contimeout; /* Connection timeout */ + int port; /* Port number */ + char portname[255]; /* Port name */ + char family[BJNP_FAMILY_MAX]; /* address family */ + int i; /* loop variable */ + int bjnp_error; /* printer error */ + http_addrlist_t *addrlist; /* Address list */ + printer_t *printer; /* Connected printer */ + char addrname[256]; /* Address name */ + ssize_t tbytes; /* Total number of bytes written */ + char *debug_level = NULL; /* debug level to be applied */ + char *debug_file_name = NULL; /* filename for own debugging */ #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) - struct sigaction action; /* Actions for POSIX signals */ + struct sigaction action; /* Actions for POSIX signals */ #endif /* HAVE_SIGACTION && !HAVE_SIGSET */ - /* - * Make sure status messages are not buffered... - */ + /* + * Make sure status messages are not buffered... + */ - setbuf (stderr, NULL); + setbuf(stderr, NULL); - /* - * Ignore SIGPIPE signals... - */ + /* + * Ignore SIGPIPE signals... + */ #ifdef HAVE_SIGSET - sigset (SIGPIPE, SIG_IGN); + sigset(SIGPIPE, SIG_IGN); #elif defined(HAVE_SIGACTION) - memset (&action, 0, sizeof (action)); - action.sa_handler = SIG_IGN; - sigaction (SIGPIPE, &action, NULL); + memset(&action, 0, sizeof(action)); + action.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &action, NULL); #else - signal (SIGPIPE, SIG_IGN); + signal(SIGPIPE, SIG_IGN); #endif /* HAVE_SIGSET */ - /* - * get debug level for printer discovery based on environment settings - */ - - if ((bjnp_debugstr = getenv ("BJNP_DEBUG")) != NULL) - bjnp_set_debug_level (bjnp_debugstr); - - /* - * Check command-line... - */ - - if (argc == 1) - { - struct printer_list printers[BJNP_PRINTERS_MAX]; - int num_printers; - int i; - - if ((num_printers = bjnp_discover_printers (printers)) == 0) - puts ("network bjnp \"Unknown\" \"Canon network printer\""); - else - for (i = 0; i < num_printers; i++) - { - printf ("network bjnp://%s:%u \"%s\" \"%s %s\" \"%s\"\n", - printers[i].hostname, - printers[i].port, - printers[i].model, - printers[i].model, - printers[i].hostname, printers[i].IEEE1284_id); - } - - return (CUPS_BACKEND_OK); + /* + * Check command-line... + */ + + if (argc == 1) { + struct printer_list printers[BJNP_PRINTERS_MAX]; + int num_printers; + int i; + + /* + * get debug level for printer discovery based on environment settings + */ + + debug_level = getenv("BJNP_DEBUG_LEVEL"); + debug_file_name = getenv("BJNP_DEBUG_FILE"); + + bjnp_set_debug_level(debug_level, debug_file_name); + + if ((num_printers = bjnp_discover_printers(printers)) == 0) { + puts("network bjnp \"Unknown\" \"Canon network printer\""); + } else { + for (i = 0; i < num_printers; i++) { + printf("network bjnp://%s:%u \"%s\" \"%s %s\" \"%s\"\n", + printers[i].hostname, + printers[i].port, + printers[i].model, + printers[i].model, + printers[i].hostname, + printers[i].IEEE1284_id); + } + } + + return (CUPS_BACKEND_OK); + } else if (argc < 6 || argc > 7) { + fprintf(stderr, "cups BJNP backend - version %s\n", VERSION); + _cupsLangPrintf(stderr, + _("Usage: %s job-id user title copies options [file]\n"), + argv[0]); + return CUPS_BACKEND_FAILED; } - else if (argc < 6 || argc > 7) - { - fprintf (stderr, "cups BJNP backend - version %s\n", VERSION); - _cupsLangPrintf (stderr, - _ ("Usage: %s job-id user title copies options [file]\n"), - argv[0]); - return (CUPS_BACKEND_FAILED); + + /* + * If we have 7 arguments, print the file named on the command-line. + * Otherwise, send stdin instead... + */ + + if (argc == 6) { + print_fd = 0; + copies = 1; + } else { + /* + * Try to open the print file... + */ + + if ((print_fd = open(argv[6], O_RDONLY)) < 0) { + perror("ERROR: unable to open print file"); + return CUPS_BACKEND_FAILED; + } + + copies = atoi(argv[4]); } - /* - * If we have 7 arguments, print the file named on the command-line. - * Otherwise, send stdin instead... - */ + /* + * Extract the hostname and port number from the URI... + */ - if (argc == 6) - { - print_fd = 0; - copies = 1; - } - else - { - /* - * Try to open the print file... - */ - - if ((print_fd = open (argv[6], O_RDONLY)) < 0) - { - perror ("ERROR: unable to open print file"); - return (CUPS_BACKEND_FAILED); - } - - copies = atoi (argv[4]); + httpSeparateURI(HTTP_URI_CODING_ALL, cupsBackendDeviceURI(argv), + method, sizeof(method), username, sizeof(username), + hostname, sizeof(hostname), &port, + resource, sizeof(resource)); + + if (port == 0) { + port = BJNP_PORT_PRINT; } - /* - * Extract the hostname and port number from the URI... - */ - - httpSeparateURI (HTTP_URI_CODING_ALL, cupsBackendDeviceURI (argv), - method, sizeof (method), username, sizeof (username), - hostname, sizeof (hostname), &port, - resource, sizeof (resource)); - - if (port == 0) - port = BJNP_PORT_PRINT; - - /* - * Get options, if any... - */ - - contimeout = 7 * 24 * 60 * 60; - - 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... - */ - - name = options; - - while (*options && *options != '=' && *options != '+' - && *options != '&') - options++; - - if ((sep = *options) != '\0') - *options++ = '\0'; - - if (sep == '=') - { - /* - * Get the value... - */ - - value = options; - - while (*options && *options != '+' && *options != '&') - options++; - - if (*options) - *options++ = '\0'; - } - else - value = (char *) ""; - - /* - * Process the option... - */ - - if (!strcasecmp (name, "contimeout")) - { - /* - * Set the connection timeout... - */ - - if (atoi (value) > 0) - contimeout = atoi (value); - } - else if (!strcasecmp (name, "debuglevel")) - { - bjnp_set_debug_level (value); - } - } + /* + * Get options from the URI, if any... + */ + + contimeout = 7 * 24 * 60 * 60; + + 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... + */ + + name = options; + + while (*options && *options != '=' && *options != '+' + && *options != '&') { + options++; + } + + if ((sep = *options) != '\0') { + *options++ = '\0'; + } + + if (sep == '=') { + /* + * Get the value... + */ + + value = options; + + while (*options && *options != '+' && *options != '&') { + options++; + } + + if (*options) { + *options++ = '\0'; + } + } else { + value = (char *) ""; + } + + /* + * Process the option... + */ + + if (!strcasecmp(name, "contimeout")) { + /* + * Set the connection timeout... + */ + + if (atoi(value) > 0) { + contimeout = atoi(value); + } + } else if (!strcasecmp(name, "debuglevel")) { + debug_level = value; + } else if (!strcasecmp(name, "debugfile")) { + debug_file_name = value; + } + } } - - /* - * print command line arguments to debug log - * We can not do that sooner, as we first need to initialize - * the debug system - */ - - for (i = 0; i < argc; i++) - { - bjnp_debug(LOG_DEBUG, "cups-bjnp: argv[%d] = %s\n", i, argv[i]); + + bjnp_set_debug_level(debug_level, debug_file_name); + + /* + * print command line arguments to debug log + * We cannot do that sooner, as we first need to initialize + * the debug system + */ + + for (i = 0; i < argc; i++) { + bjnp_debug(LOG_DEBUG, "cups-bjnp: argv[%d] = %s\n", i, argv[i]); } - /* - * Then try to connect to the remote host... - */ + /* + * Then try to connect to the remote host... + */ - recoverable = 0; - start_time = time (NULL); + recoverable = 0; + start_time = time(NULL); - sprintf (portname, "%d", port); + sprintf(portname, "%d", port); - if ((addrlist = httpAddrGetList (hostname, AF_UNSPEC, portname)) == NULL) - { - _cupsLangPrintf (stderr, _("ERROR: Unable to locate printer \'%s\'!\n"), - hostname); - return (CUPS_BACKEND_STOP); + if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL) { + _cupsLangPrintf(stderr, _("ERROR: Unable to locate printer \'%s\'!\n"), + hostname); + return (CUPS_BACKEND_STOP); } - _cupsLangPrintf (stderr, - _("INFO: Attempting to connect to host %s on port %d\n"), - hostname, port); - - fputs ("STATE: +connecting-to-device\n", stderr); - - for (delay = 5;;) - { - if ( ( (addr = bjnp_start_job (addrlist, argv[2], argv[3]) ) == NULL) || - ( device_fd = bjnp_addr_connect (addr)) < 0 ) - { - error = errno; - device_fd = -1; - - if (getenv ("CLASS") != NULL) - { - /* - * If the CLASS environment variable is set, the job was submitted - * to a class and not to a specific queue. In this case, we want - * to abort immediately so that the job can be requeued on the next - * available printer in the class. - */ - - _cupsLangPuts (stderr, - _ - ("INFO: Unable to contact printer, queuing on next " - "printer in class...\n")); - - /* - * Sleep 5 seconds to keep the job from requeuing too rapidly... - */ - - sleep (5); - - return (CUPS_BACKEND_FAILED); - } - - if (error == ECONNREFUSED || error == EHOSTDOWN || - error == EHOSTUNREACH) - { - if (contimeout && (time (NULL) - start_time) > contimeout) - { - _cupsLangPuts (stderr, - _("ERROR: Printer not responding!\n")); - return (CUPS_BACKEND_FAILED); - } - - recoverable = 1; - - _cupsLangPrintf (stderr, - _ - ("WARNING: recoverable: Network host \'%s\' is busy; " - "will retry in %d seconds...\n"), hostname, - delay); - - sleep (delay); - - if (delay < 30) - delay += 5; - } - else - { - recoverable = 1; - - _cupsLangPrintf (stderr, "DEBUG: Connection error: %s\n", - strerror (errno)); - _cupsLangPuts (stderr, - _ - ("ERROR: recoverable: Unable to connect to printer; " - "will retry in 30 seconds...\n")); - sleep (30); - } - } - else - break; + _cupsLangPrintf(stderr, + _("INFO: Attempting to connect to host %s on port %d\n"), + hostname, port); + + fputs("STATE: +connecting-to-device\n", stderr); + + printer = NULL; + + while (1) { + if (((printer = bjnp_printer_connect(printer, addrlist, argv[2], argv[3], &bjnp_error)) == NULL) || + bjnp_error != 0) { + + if (getenv("CLASS") != NULL) { + /* + * If the CLASS environment variable is set, the job was submitted + * to a class and not to a specific queue. In this case, we want + * to abort immediately so that the job can be requeued on the next + * available printer in the class. + */ + + _cupsLangPuts(stderr, + _ + ("INFO: Unable to contact printer, queuing on next " + "printer in class...\n")); + + /* + * Sleep 5 seconds to keep the job from requeuing too rapidly... + */ + + sleep(5); + + return CUPS_BACKEND_FAILED; + } + + if (contimeout && (time(NULL) - start_time) > contimeout) { + _cupsLangPuts(stderr, + _("ERROR: Printer not ready to print!\n")); + return CUPS_BACKEND_FAILED; + } + + recoverable = 1; + + if (bjnp_error != 0) { + if (bjnp_error & BJNP_PRINTER_BUSY) { + _cupsLangPrintf(stderr, + _("WARNING: recoverable: Network printer \'%s\' is busy, "), + hostname); + } + + if (bjnp_error & BJNP_NO_INK) { + _cupsLangPrintf(stderr, + _("WARNING: recoverable: Network printer \'%s\' is out of ink, "), + hostname); + } + + if (bjnp_error & BJNP_NO_PAPER) { + _cupsLangPrintf(stderr, + _("WARNING: recoverable: Network host \'%s\' is out of paper, "), + hostname); + } + + _cupsLangPrintf(stderr, + _("will retry in 30 seconds...\n")); + sleep(30); + + } else { + _cupsLangPrintf(stderr, "DEBUG: Connection error: %s\n", + strerror(errno)); + _cupsLangPuts(stderr, + _ + ("ERROR: recoverable: Unable to connect to printer; " + "will retry in 30 seconds...\n")); + + sleep(30); + } + } else { + break; + } } - 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... - */ + 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); + fputs("INFO: recovered: \n", stderr); + sleep(5); } - fputs ("STATE: -connecting-to-device\n", stderr); - _cupsLangPrintf (stderr, _("INFO: Connected to %s...\n"), hostname); + fputs("STATE: -connecting-to-device\n", stderr); + _cupsLangPrintf(stderr, _("INFO: Connected to %s...\n"), hostname); - get_address_info( addr, addrname, &port); - fprintf (stderr, "DEBUG: Connected to [%s]:%d (%s)...\n", - addrname, port, (addr->addr.sa_family == AF_INET ? "IPv4" : "IPV6") ); + get_printer_address_info(printer, addrname, &port, family); + fprintf(stderr, "DEBUG: Connected to [%s]:%d (%s)...\n", + addrname, port, family); - /* - * Print everything... - */ + /* + * Print everything... + */ - tbytes = 0; + tbytes = 0; - while (copies > 0 && tbytes >= 0) - { - copies--; + while (copies > 0 && tbytes >= 0) { + copies--; - if (print_fd != 0) - { - fputs ("PAGE: 1 1\n", stderr); - lseek (print_fd, 0, SEEK_SET); - } + if (print_fd != 0) { + fputs("PAGE: 1 1\n", stderr); + lseek(print_fd, 0, SEEK_SET); + } - tbytes = bjnp_backendRunLoop (print_fd, device_fd, addr); + tbytes = bjnp_backendRunLoop(print_fd, printer); - if (print_fd != 0 && tbytes >= 0) - { + if (print_fd != 0 && tbytes >= 0) { #ifdef HAVE_LONG_LONG - _cupsLangPrintf (stderr, - _("INFO: Sent print file, %lld bytes...\n"), - CUPS_LLCAST tbytes); + _cupsLangPrintf(stderr, + _("INFO: Sent print file, %lld bytes...\n"), + CUPS_LLCAST tbytes); #else - _cupsLangPrintf (stderr, - _("INFO: Sent print file, %ld bytes...\n"), - CUPS_LLCAST tbytes); + _cupsLangPrintf(stderr, + _("INFO: Sent print file, %ld bytes...\n"), + CUPS_LLCAST tbytes); #endif /* HAVE_LONG_LONG */ - } + } } + /* + * tell printer to finsh the print job and to close the connection + */ + bjnp_close_printer(printer); + printer = NULL; + httpAddrFreeList(addrlist); + addrlist = NULL; - /* - * Close the socket connection... - */ + /* + * Close the input file and return... + */ - close (device_fd); - - /* - * and tell printer to finsh job - */ - bjnp_finish_job (addr); - free(addr); - addr = NULL; - httpAddrFreeList (addrlist); - addrlist = NULL; - - /* - * delay a bit as otherwise next job may hang (reported by Zedonet for PIXMA MX7600) - */ - - sleep(15); + if (print_fd != 0) { + close(print_fd); + } - /* - * Close the input file and return... - */ + /* + * delay a bit as otherwise next job may hang (reported by Zedonet for PIXMA MX7600) + */ - if (print_fd != 0) - close (print_fd); + sleep(15); - if (tbytes >= 0) - _cupsLangPuts (stderr, _("INFO: Ready to print.\n")); + if (tbytes >= 0) { + _cupsLangPuts(stderr, _("INFO: Ready to print.\n")); + } - return (tbytes < 0 ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK); + return (tbytes < 0 ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK); } - -/* - * End of "$Id: socket.c 6911 2007-09-04 20:35:08Z mike $". - */ - |