Re: [Utopia] [patch] HAL backend for CUPS



Here is a little patch to this that fixes the hal backend so that it
uses the first argument (argv[0]) as the URI.  There is also a fix that
outputs a dummy printer when no printers are found.  This is needed
because when cups starts up it enumerates the backends by executing them
without arguments and parses their output.  If no printers are plugged
in and hal does not output a dummy printer you will not be able to use
lpadmin to add a hal device since it will assume there is no hal
backend.  In other words the hal:// URI will be filtered out as an
invalid URI.

On Wed, 2004-06-09 at 13:16, Joe Shaw wrote:
> Hi,
> 
> Here's a patch against cups 1.1.20 which adds a HAL backend.  It's based
> pretty heavily on the existing USB backend.  URIs are UDIs with "hal://"
> prepended.  Here's an example run on my machine:
> 
> [joe platitude ~/cups-1.1.20.joe/backend]$ ./hal
> direct hal:///org/freedesktop/Hal/devices/usb_4b8_5_100_-1_L49030309021330450 "EPSON Stylus C64" "EPSON Stylus C64"
> 
> So yeah, that's pretty cool.  The downside is that if the USB backend is
> also enabled you get two entries for the same printer.  In my case 3,
> since there's also an Epson backend which seems to poke at the USB
> devices as well.  So you'll probably want to disable the USB backend
> since it becomes redundant with the HAL backend.
> 
> This makes it a lot easier for HAL callouts to determine if a certain
> printer is configured.  CUPS has its own heuristics for creating a
> special USB URI which can be tricky to figure out.  With the HAL
> backend, it's easy because it's always the UDI.
> 
> You'll need to rerun "autoconf" after applying this, and you'll need to
> pass in --enable-hal to the configure line.
> 
> Share and enjoy,
> Joe
> 
> ______________________________________________________________________
> --- cups-1.1.20/configure.in	2003-03-14 12:04:08.000000000 -0500
> +++ cups-1.1.20.joe/configure.in	2004-06-09 12:56:36.027559960 -0400
> @@ -38,6 +38,7 @@ sinclude(config-scripts/cups-network.m4)
>  sinclude(config-scripts/cups-openslp.m4)
>  sinclude(config-scripts/cups-openssl.m4)
>  sinclude(config-scripts/cups-pam.m4)
> +sinclude(config-scripts/cups-hal.m4)
>  
>  sinclude(config-scripts/cups-scripting.m4)
>  
> --- cups-1.1.20/Makedefs.in	2003-09-17 15:35:21.000000000 -0400
> +++ cups-1.1.20.joe/Makedefs.in	2004-06-09 13:03:28.981781376 -0400
> @@ -85,7 +85,7 @@ LIBZ		=	@LIBZ@
>  
>  ARFLAGS		=	@ARFLAGS@
>  BACKLIBS	=	@BACKLIBS@
> -CFLAGS		=	$(RC_CFLAGS) $(SSLFLAGS) @CPPFLAGS@ @CFLAGS@ -I.. $(OPTIONS)
> +CFLAGS		=	$(RC_CFLAGS) $(SSLFLAGS) $(HALFLAGS) @CPPFLAGS@ @CFLAGS@ -I.. $(OPTIONS)
>  COMMONLIBS	=	@COMMONLIBS@
>  CXXFLAGS	=	$(RC_CFLAGS) @CPPFLAGS@ @CXXFLAGS@ -I.. $(OPTIONS)
>  CXXLIBS		=	@CXXLIBS@
> @@ -102,6 +102,8 @@ OPTIONS		=
>  PAMLIBS		=	@PAMLIBS@
>  SSLFLAGS	=	@SSLFLAGS@
>  SSLLIBS		=	@SSLLIBS@
> +HALFLAGS        =       @HAL_CFLAGS@
> +HALLIBS         =       @HAL_LIBS@
>  
>  #
>  # Directories...
> --- cups-1.1.20/config-scripts/cups-hal.m4	1969-12-31 19:00:00.000000000 -0500
> +++ cups-1.1.20.joe/config-scripts/cups-hal.m4	2004-06-09 13:00:23.727944240 -0400
> @@ -0,0 +1,82 @@
> +dnl
> +dnl "$Id: cups-openssl.m4,v 1.14 2003/09/17 19:35:22 mike Exp $"
> +dnl
> +dnl   HAL config stuff; pkg-config stuff lifted from pkg.m4
> +dnl
> +dnl   Copyright (C) 2004 Novell, Inc.
> +dnl
> +
> +dnl pkg-config stuff
> +
> +dnl PKG_CHECK_MODULES(GSTUFF, gtk+-2.0 >= 1.3 glib = 1.3.4, action-if, action-not)
> +dnl defines GSTUFF_LIBS, GSTUFF_CFLAGS, see pkg-config man page
> +dnl also defines GSTUFF_PKG_ERRORS on error
> +AC_DEFUN([PKG_CHECK_MODULES], [
> +  succeeded=no
> +
> +  if test -z "$PKG_CONFIG"; then
> +    AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
> +  fi
> +
> +  if test "$PKG_CONFIG" = "no" ; then
> +     echo "*** The pkg-config script could not be found. Make sure it is"
> +     echo "*** in your path, or set the PKG_CONFIG environment variable"
> +     echo "*** to the full path to pkg-config."
> +     echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config."
> +  else
> +     PKG_CONFIG_MIN_VERSION=0.9.0
> +     if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then
> +        AC_MSG_CHECKING(for $2)
> +
> +        if $PKG_CONFIG --exists "$2" ; then
> +            AC_MSG_RESULT(yes)
> +            succeeded=yes
> +
> +            AC_MSG_CHECKING($1_CFLAGS)
> +            $1_CFLAGS=`$PKG_CONFIG --cflags "$2"`
> +            AC_MSG_RESULT($$1_CFLAGS)
> +
> +            AC_MSG_CHECKING($1_LIBS)
> +            $1_LIBS=`$PKG_CONFIG --libs "$2"`
> +            AC_MSG_RESULT($$1_LIBS)
> +        else
> +            $1_CFLAGS=""
> +            $1_LIBS=""
> +            ## If we have a custom action on failure, don't print errors, but 
> +            ## do set a variable so people can do so.
> +            $1_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"`
> +            ifelse([$4], ,echo $$1_PKG_ERRORS,)
> +        fi
> +
> +        AC_SUBST($1_CFLAGS)
> +        AC_SUBST($1_LIBS)
> +     else
> +        echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer."
> +        echo "*** See http://www.freedesktop.org/software/pkgconfig";
> +     fi
> +  fi
> +
> +  if test $succeeded = yes; then
> +     ifelse([$3], , :, [$3])
> +  else
> +     ifelse([$4], , AC_MSG_ERROR([Library requirements ($2) not met; consider adjusting the PKG_CONFIG_PATH environment variable if your libraries are in a nonstandard prefix so pkg-config can find them.]), [$4])
> +  fi
> +])
> +
> +dnl hal stuff
> +
> +AC_ARG_ENABLE(hal, [  --enable-hal            build the HAL backend],enable_hal=$enableval,enable_hal=no)
> +
> +if test x$enable_hal = xyes; then
> +    PKG_CHECK_MODULES(HAL, hal)
> +else
> +    HAL_CFLAGS=""
> +    HAL_LIBS=""
> +fi
> +
> +AC_SUBST(HAL_CFLAGS)
> +AC_SUBST(HAL_LIBS)
> +
> +dnl
> +dnl End of "$Id: cups-openssl.m4,v 1.14 2003/09/17 19:35:22 mike Exp $".
> +dnl
> --- cups-1.1.20/backend/Makefile	2002-12-17 13:56:33.000000000 -0500
> +++ cups-1.1.20.joe/backend/Makefile	2004-06-09 13:03:46.111177312 -0400
> @@ -26,9 +26,9 @@
>  
>  include ../Makedefs
>  
> -BACKENDS =	ipp lpd parallel scsi serial socket usb
> +BACKENDS =	ipp lpd parallel scsi serial socket usb hal
>  TARGETS	=	betest $(BACKENDS)
> -OBJS	=	betest.o ipp.o lpd.o parallel.o scsi.o serial.o socket.o usb.o
> +OBJS	=	betest.o ipp.o lpd.o parallel.o scsi.o serial.o socket.o usb.o hal.o
>  
> 
>  #
> @@ -144,6 +144,15 @@ usb:	usb.o ../cups/$(LIBCUPS)
>  
> 
>  #
> +# hal
> +#
> +
> +hal:	hal.o ../cups/$(LIBCUPS)
> +	echo Linking $    
> +	$(CC) $(LDFLAGS) -o hal hal.o $(BACKLIBS) $(LIBS) -Wl,-Bstatic $(HALLIBS) -Wl,-Bdynamic
> +
> +
> +#
>  # Dependencies...
>  #
>  
> --- cups-1.1.20/backend/hal.c	1969-12-31 19:00:00.000000000 -0500
> +++ cups-1.1.20.joe/backend/hal.c	2004-06-09 13:10:49.939745576 -0400
> @@ -0,0 +1,393 @@
> +/*
> + * "$Id: usb.c,v 1.49 2003/09/02 20:19:17 mike Exp $"
> + *
> + *   HAL backend for the Common UNIX Printing System (CUPS).
> + *
> + *   Copyright 1997-2003 by Easy Software Products, all rights reserved.
> + *   Copyright (C) 2004 Novell, Inc.
> + *
> + *   These coded instructions, statements, and computer programs are the
> + *   property of Easy Software Products and are protected by Federal
> + *   copyright law.  Distribution and use rights are outlined in the file
> + *   "LICENSE" which should have been included with this file.  If this
> + *   file is missing or damaged please contact Easy Software Products
> + *   at:
> + *
> + *       Attn: CUPS Licensing Information
> + *       Easy Software Products
> + *       44141 Airport View Drive, Suite 204
> + *       Hollywood, Maryland 20636-3111 USA
> + *
> + *       Voice: (301) 373-9603
> + *       EMail: cups-info cups org
> + *         WWW: http://www.cups.org
> + *
> + *   This file is subject to the Apple OS-Developed Software exception.
> + *
> + * Contents:
> + *
> + *   main()         - Send a file to the specified HAL device.
> + *   list_devices() - List all HAL printer devices.
> + */
> +
> +/*
> + * Include necessary headers.
> + */
> +
> +#include <cups/cups.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <errno.h>
> +#include <cups/string.h>
> +#include <signal.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <termios.h>
> +
> +#include <libhal.h>
> +
> +/*
> + * 'list_devices()' - List all HAL printer devices.
> + */
> +
> +void
> +list_devices(void)
> +{
> +	LibHalContext *hal_ctx;
> +	char **printer_list;
> +	int num_printers, i;
> +
> +	hal_ctx = hal_initialize (NULL, FALSE);
> +
> +	if (hal_ctx == NULL) {
> +		fprintf (stderr, "ERROR: Unable to access HAL daemon\n");
> +		return;
> +	}
> +
> +	printer_list = hal_find_device_by_capability (hal_ctx, "printer",
> +						      &num_printers);
> +
> +	for (i = 0; i < num_printers; i++) {
> +		const char *vendor, *product, *description;
> +		char make_model[1024];
> +
> +		/* We only want printers that have device nodes */
> +		if (!hal_device_property_exists (hal_ctx, printer_list[i],
> +						 "printer.device"))
> +			continue;
> +
> +		vendor = hal_device_get_property_string (hal_ctx,
> +							 printer_list[i],
> +							 "printer.vendor");
> +
> +		product = hal_device_get_property_string (hal_ctx,
> +							  printer_list[i],
> +							  "printer.product");
> +
> +		description = hal_device_get_property_string (hal_ctx,
> +							      printer_list[i],
> +							      "printer.description");
> +
> +		/* Try our hardest to get a good name */
> +		if (product != NULL) {
> +			if (vendor != NULL) {
> +				snprintf (make_model, sizeof (make_model),
> +					  "%s %s", vendor, product);
> +			} else {
> +				strncpy (make_model, product,
> +					 sizeof (make_model));
> +			}
> +		} else if (description != NULL) {
> +			strncpy (make_model, description, sizeof (make_model));
> +		} else if (vendor != NULL) {
> +			snprintf (make_model, sizeof (make_model),
> +				  "%s printer", vendor);
> +		} else {
> +			strncpy (make_model, "Unknown", sizeof (make_model));
> +		}
> +
> +		printf ("direct hal://%s \"%s\" \"%s\"\n",
> +			printer_list[i], make_model,
> +			description != NULL ? description : make_model);
> +	}
> +
> +	hal_shutdown (hal_ctx);
> +}
> +
> +/*
> + * 'get_device_file()' - Get a device file from a HAL device UDI
> + */
> +const char *
> +get_device_file (const char *uri)
> +{
> +	LibHalContext *hal_ctx;
> +	const char *udi;
> +	const char *device_file;
> +
> +	hal_ctx = hal_initialize (NULL, FALSE);
> +
> +	if (hal_ctx == NULL)
> +		return NULL;
> +
> +	if (strncmp (uri, "hal://", 6) != 0)
> +		return NULL;
> +
> +	udi = uri + 6;
> +
> +	device_file = hal_device_get_property_string (hal_ctx, udi,
> +						      "printer.device");
> +
> +	return device_file;
> +}
> +
> +/*
> + * 'main()' - Send a file to the specified HAL printer device.
> + *
> + * Usage:
> + *
> + *    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		fp;		/* Print file */
> +  int		copies;		/* Number of copies to print */
> +  const char    *device_file;   /* Device file to open */
> +  int		fd;		/* Device file descriptor */
> +  int		wbytes;		/* Number of bytes written */
> +  size_t	nbytes,		/* Number of bytes read */
> +		tbytes;		/* Total number of bytes written */
> +  char		buffer[8192],	/* Output buffer */
> +		*bufptr;	/* Pointer into buffer */
> +  struct termios opts;		/* Parallel port options */
> +#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
> +  struct sigaction action;	/* Actions for POSIX signals */
> +#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
> +#if defined(__linux) && defined(LP_POUTPA)
> +  unsigned char	status;		/* Port status (off-line, out-of-paper, etc.) */
> +#endif /* __linux */
> +
> +
> + /*
> +  * Make sure status messages are not buffered...
> +  */
> +
> +  setbuf(stderr, NULL);
> +
> + /*
> +  * Ignore SIGPIPE signals...
> +  */
> +
> +#ifdef HAVE_SIGSET
> +  sigset(SIGPIPE, SIG_IGN);
> +#elif defined(HAVE_SIGACTION)
> +  memset(&action, 0, sizeof(action));
> +  action.sa_handler = SIG_IGN;
> +  sigaction(SIGPIPE, &action, NULL);
> +#else
> +  signal(SIGPIPE, SIG_IGN);
> +#endif /* HAVE_SIGSET */
> +
> + /*
> +  * Check command-line...
> +  */
> +
> +  if (argc == 1)
> +  {
> +    list_devices();
> +    return (0);
> +  }
> +  else if (argc < 6 || argc > 7)
> +  {
> +    fputs("Usage: hal URI job-id user title copies options [file]\n", stderr);
> +    return (1);
> +  }
> +
> + /*
> +  * If we have 7 arguments, print the file named on the command-line.
> +  * Otherwise, send stdin instead...
> +  */
> +
> +  if (argc == 6)
> +  {
> +    fp     = 0;
> +    copies = 1;
> +  }
> +  else
> +  {
> +   /*
> +    * Try to open the print file...
> +    */
> +
> +    if ((fp = open(argv[6], O_RDONLY)) < 0)
> +    {
> +      perror("ERROR: unable to open print file");
> +      return (1);
> +    }
> +
> +    copies = atoi(argv[4]);
> +  }
> +
> +  device_file = get_device_file (argv[1]);
> +
> +  if (device_file == NULL) {
> +	  fprintf (stderr, "ERROR: Unable to open HAL device \"%s\"\n",
> +		   argv[1]);
> +	  return 1;
> +  }
> +	  
> + /*
> +  * Open the port device...
> +  */
> +
> +  do
> +  {
> +    if ((fd = open (device_file, O_RDWR | O_EXCL)) == -1)
> +    {
> +      if (errno == EBUSY)
> +      {
> +        fputs("INFO: Device busy; will retry in 30 seconds...\n", stderr);
> +	sleep(30);
> +      }
> +      else if (errno == ENXIO || errno == EIO || errno == ENOENT)
> +      {
> +        fputs("INFO: Printer not connected; will retry in 30 seconds...\n", stderr);
> +	sleep(30);
> +      }
> +      else
> +      {
> +	fprintf(stderr, "ERROR: Unable to open device \"%s\": %s\n",
> +	        argv[0], strerror(errno));
> +	return (1);
> +      }
> +    }
> +  }
> +  while (fd < 0);
> +
> + /*
> +  * Set any options provided...
> +  */
> +
> +  tcgetattr(fd, &opts);
> +
> +  opts.c_lflag &= ~(ICANON | ECHO | ISIG);	/* Raw mode */
> +
> +  /**** No options supported yet ****/
> +
> +  tcsetattr(fd, TCSANOW, &opts);
> +
> + /*
> +  * Now that we are "connected" to the port, ignore SIGTERM so that we
> +  * can finish out any page data the driver sends (e.g. to eject the
> +  * current page...  Only ignore SIGTERM if we are printing data from
> +  * stdin (otherwise you can't cancel raw jobs...)
> +  */
> +
> +  if (argc < 7)
> +  {
> +#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
> +    sigset(SIGTERM, SIG_IGN);
> +#elif defined(HAVE_SIGACTION)
> +    memset(&action, 0, sizeof(action));
> +
> +    sigemptyset(&action.sa_mask);
> +    action.sa_handler = SIG_IGN;
> +    sigaction(SIGTERM, &action, NULL);
> +#else
> +    signal(SIGTERM, SIG_IGN);
> +#endif /* HAVE_SIGSET */
> +  }
> +
> +#if defined(__linux) && defined(LP_POUTPA)
> + /*
> +  * Show the printer status before we send the file; normally, we'd
> +  * do this while we write data to the printer, however at least some
> +  * Linux kernels have buggy USB drivers which don't like to be
> +  * queried while sending data to the printer...
> +  *
> +  * Also, we're using the 8255 constants instead of the ones that are
> +  * supposed to be used, as it appears that the USB driver also doesn't
> +  * follow standards...
> +  */
> +
> +  if (ioctl(fd, LPGETSTATUS, &status) == 0)
> +  {
> +    fprintf(stderr, "DEBUG: LPGETSTATUS returned a port status of %02X...\n", status);
> +
> +    if (!(status & LP_POUTPA))
> +      fputs("WARNING: Media tray empty!\n", stderr);
> +    else if (!(status & LP_PERRORP))
> +      fputs("WARNING: Printer fault!\n", stderr);
> +    else if (!(status & LP_PSELECD))
> +      fputs("WARNING: Printer off-line.\n", stderr);
> +  }
> +#endif /* __linux && LP_POUTPA */
> +
> + /*
> +  * Finally, send the print file...
> +  */
> +
> +  while (copies > 0)
> +  {
> +    copies --;
> +
> +    if (fp != 0)
> +    {
> +      fputs("PAGE: 1 1\n", stderr);
> +      lseek(fp, 0, SEEK_SET);
> +    }
> +
> +    tbytes = 0;
> +    while ((nbytes = read(fp, buffer, sizeof(buffer))) > 0)
> +    {
> +     /*
> +      * Write the print data to the printer...
> +      */
> +
> +      tbytes += nbytes;
> +      bufptr = buffer;
> +
> +      while (nbytes > 0)
> +      {
> +
> +	if ((wbytes = write(fd, bufptr, nbytes)) < 0)
> +	  if (errno == ENOTTY)
> +	    wbytes = write(fd, bufptr, nbytes);
> +
> +	if (wbytes < 0)
> +	{
> +	  perror("ERROR: Unable to send print file to printer");
> +	  break;
> +	}
> +
> +	nbytes -= wbytes;
> +	bufptr += wbytes;
> +      }
> +
> +      if (wbytes < 0)
> +        break;
> +
> +      if (argc > 6)
> +	fprintf(stderr, "INFO: Sending print file, %lu bytes...\n",
> +	        (unsigned long)tbytes);
> +    }
> +  }
> +
> + /*
> +  * Close the socket connection and input file and return...
> +  */
> +
> +  close(fd);
> +  if (fp != 0)
> +    close(fp);
> +
> +  fputs("INFO: Ready to print.\n", stderr);
> +
> +  return (0);
> +}
> +						      
> +/*
> + * End of "$Id: usb.c,v 1.49 2003/09/02 20:19:17 mike Exp $".
> + */
> 
> ______________________________________________________________________
> _______________________________________________
> utopia-list mailing list
> utopia-list gnome org
> http://mail.gnome.org/mailman/listinfo/utopia-list
-- 
John (J5) Palmieri
Associate Software Engineer
Desktop Group
Red Hat, Inc.
Blog: http://martianrock.com
--- cups-1.1.20/backend/hal.c.hal	2004-06-11 16:00:35.000000000 -0400
+++ cups-1.1.20/backend/hal.c	2004-06-16 14:16:59.000000000 -0400
@@ -66,6 +66,8 @@
 
 	printer_list = hal_find_device_by_capability (hal_ctx, "printer",
 						      &num_printers);
+	if (num_printers == 0)
+		printf("direct hal \"Unknown\" \"Hal printing backend\"\n"); 
 
 	for (i = 0; i < num_printers; i++) {
 		const char *vendor, *product, *description;
@@ -169,7 +171,6 @@
   unsigned char	status;		/* Port status (off-line, out-of-paper, etc.) */
 #endif /* __linux */
 
-
  /*
   * Make sure status messages are not buffered...
   */
@@ -201,7 +202,7 @@
   }
   else if (argc < 6 || argc > 7)
   {
-    fputs("Usage: hal URI job-id user title copies options [file]\n", stderr);
+    fputs("Usage: URI job-id user title copies options [file]\n", stderr);
     return (1);
   }
 
@@ -230,11 +231,11 @@
     copies = atoi(argv[4]);
   }
 
-  device_file = get_device_file (argv[1]);
+  device_file = get_device_file (argv[0]);
 
   if (device_file == NULL) {
 	  fprintf (stderr, "ERROR: Unable to open HAL device \"%s\"\n",
-		   argv[1]);
+		   argv[0]);
 	  return 1;
   }
 	  


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]