/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Authors: Jeffrey Stedfast * Authors: Klaus Singvogel * * Copyright 2005 Novell, Inc. (www.novell.com) * * 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; either version 2 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. * */ #include #include #include #include #include #include #include #include #include #include static LibHalContext * get_hal_ctx (void) { DBusConnection *connection; LibHalContext *hal_ctx; DBusError error; if (!(hal_ctx = libhal_ctx_new ())) { fprintf (stderr, "ERROR: Unable to create HAL context\n"); return NULL; } dbus_error_init (&error); if (!(connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error))) { fprintf (stderr, "ERROR: Unable to connect to DBUS: %s\n", error.message); libhal_ctx_free (hal_ctx); dbus_error_free (&error); return NULL; } libhal_ctx_set_dbus_connection (hal_ctx, connection); if (!libhal_ctx_init (hal_ctx, &error)) { fprintf (stderr, "ERROR: Unable to init HAL context: %s\n", error.message); libhal_ctx_free (hal_ctx); dbus_error_free (&error); return NULL; } return hal_ctx; } /* * 'list_devices()' - List all HAL printer devices. */ static void list_devices (void) { LibHalContext *hal_ctx; char **printers; int i, n; if (!(hal_ctx = get_hal_ctx ())) return; printers = libhal_find_device_by_capability (hal_ctx, "printer", &n, NULL); if (n == 0) printf("direct hal \"Unknown\" \"Hal printing backend\"\n"); for (i = 0; i < n; i++) { char *vendor, *product, *description; char make_model[1024]; /* We only want printers that have device nodes */ if (!libhal_device_property_exists (hal_ctx, printers[i], "printer.device", NULL)) continue; vendor = libhal_device_get_property_string (hal_ctx, printers[i], "printer.vendor", NULL); product = libhal_device_get_property_string (hal_ctx, printers[i], "printer.product", NULL); description = libhal_device_get_property_string (hal_ctx, printers[i], "printer.description", NULL); /* 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) - 1); make_model[sizeof (make_model) - 1] = '\0'; } } else if (description != NULL) { strncpy (make_model, description, sizeof (make_model) - 1); make_model[sizeof (make_model) - 1] = '\0'; } else if (vendor != NULL) { snprintf (make_model, sizeof (make_model), "%s printer", vendor); } else { strcpy (make_model, "Unknown"); } printf ("direct hal://%s \"%s\" \"%s\"\n", printers[i], make_model, description != NULL ? description : make_model); libhal_free_string (vendor); libhal_free_string (product); libhal_free_string (description); } libhal_ctx_shutdown (hal_ctx, NULL); libhal_ctx_free (hal_ctx); } /* * 'get_device_file()' - Get a device file from a HAL device UDI */ static char * get_device_file (const char *uri) { LibHalContext *hal_ctx; const char *udi; char *device; if (strncmp (uri, "hal://", 6) != 0) return NULL; if (!(hal_ctx = get_hal_ctx ())) return NULL; udi = uri + 6; device = libhal_device_get_property_string (hal_ctx, udi, "printer.device", NULL); libhal_ctx_shutdown (hal_ctx, NULL); libhal_ctx_free (hal_ctx); return device; } /* * 'main()' - Send a file to the specified HAL printer device. * * Usage: * * printer-uri job-id user title copies options [file] */ int main (int argc, char *argv[]) { int fp; /* Print file */ int copies; /* Number of copies to print */ char *device; /* Device file to open */ int fd; /* Device file descriptor */ ssize_t nwritten; /* Number of bytes written */ size_t nbytes; /* Number of bytes read */ size_t tbytes; /* Total number of bytes written */ char buffer[8192]; /* Output buffer */ char *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: 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 { if ((fp = open (argv[6], O_RDONLY)) == -1) { perror ("ERROR: unable to open print file"); return 1; } copies = atoi (argv[4]); } if (!(device = get_device_file (argv[0]))) { fprintf (stderr, "ERROR: Unable to open HAL device \"%s\"\n", argv[0]); return 1; } do { if ((fd = open (device, 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 == -1); libhal_free_string (device); /* * 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) 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 ((nwritten = write (fd, bufptr, nbytes)) == -1) if (errno == ENOTTY) nwritten = write (fd, bufptr, nbytes); if (nwritten == -1) { perror ("ERROR: Unable to send print file to printer"); break; } nbytes -= nwritten; bufptr += nwritten; } if (nwritten == -1) 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; }