int					/* O - Exit status */
main(int  argc,				/* I - Number of command-line args */
     char *argv[])			/* I - Command-line arguments */
{
  http_addrlist_t	*host;		/* Host addresses */
  int			snmp_fd;	/* SNMP socket */
  int			page_count,	/* Current page count */
			printer_state;	/* Current printer state */


  if (argc != 2)
  {
    puts("Usage: testsupplies ip-or-hostname");
    return (1);
  }

  if ((host = httpAddrGetList(argv[1], AF_UNSPEC, "9100")) == NULL)
  {
    perror(argv[1]);
    return (1);
  }

  if ((snmp_fd = _cupsSNMPOpen(host->addr.addr.sa_family)) < 0)
  {
    perror(argv[1]);
    return (1);
  }

  for (;;)
  {
    fputs("backendSNMPSupplies: ", stdout);

    if (backendSNMPSupplies(snmp_fd, &(host->addr), &page_count,
                            &printer_state))
    {
      puts("FAIL");
      return (1);
    }

    printf("backendSNMPSupplies: %s (page_count=%d, printer_state=%d)\n",
	   page_count < 0 || printer_state < CUPS_TC_other ||
	       printer_state > CUPS_TC_warmup ? "FAIL" : "PASS",
	   page_count, printer_state);

    sleep(5);
  }
}
示例#2
0
文件: socket.c 项目: AnotherView/cups
int					/* O - Exit status */
main(int  argc,				/* I - Number of command-line arguments (6 or 7) */
     char *argv[])			/* I - Command-line arguments */
{
  const char	*device_uri;		/* Device URI */
  char		scheme[255],		/* Scheme 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 */
#ifdef __APPLE__
  time_t	current_time,		/* Current time */
		wait_time;		/* Time to wait before shutting down socket */
#endif /* __APPLE__ */
  int		contimeout;		/* Connection timeout */
  int		waiteof;		/* Wait for end-of-file? */
  int		port;			/* Port number */
  char		portname[255];		/* Port name */
  int		delay;			/* Delay for retries... */
  int		device_fd;		/* AppSocket */
  int		error;			/* Error code (if any) */
  http_addrlist_t *addrlist,		/* Address list */
		*addr;			/* Connected address */
  char		addrname[256];		/* Address name */
  int		snmp_fd,		/* SNMP socket */
		start_count,		/* Page count via SNMP at start */
		page_count,		/* Page count via SNMP */
		have_supplies;		/* Printer supports supply levels? */
  ssize_t	bytes = 0,		/* Initial bytes read */
		tbytes;			/* Total number of bytes written */
  char		buffer[1024];		/* Initial print buffer */
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
  struct sigaction action;		/* Actions for POSIX signals */
#endif /* HAVE_SIGACTION && !HAVE_SIGSET */


 /*
  * 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)
  {
    printf("network socket \"Unknown\" \"%s\"\n",
           _cupsLangString(cupsLangDefault(), _("AppSocket/HP JetDirect")));
    return (CUPS_BACKEND_OK);
  }
  else if (argc < 6 || argc > 7)
  {
    _cupsLangPrintf(stderr,
                    _("Usage: %s job-id user title copies options [file]"),
                    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)
    {
      _cupsLangPrintError("ERROR", _("Unable to open print file"));
      return (CUPS_BACKEND_FAILED);
    }

    copies = atoi(argv[4]);
  }

 /*
  * Extract the hostname and port number from the URI...
  */

  while ((device_uri = cupsBackendDeviceURI(argv)) == NULL)
  {
    _cupsLangPrintFilter(stderr, "INFO", _("Unable to locate printer."));
    sleep(10);

    if (getenv("CLASS") != NULL)
      return (CUPS_BACKEND_FAILED);
  }

  httpSeparateURI(HTTP_URI_CODING_ALL, device_uri, scheme, sizeof(scheme),
                  username, sizeof(username), hostname, sizeof(hostname), &port,
		  resource, sizeof(resource));

  if (port == 0)
    port = 9100;	/* Default to HP JetDirect/Tektronix PhaserShare */

 /*
  * Get options, if any...
  */

  waiteof    = 1;
  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 (!_cups_strcasecmp(name, "waiteof"))
      {
       /*
        * Set the wait-for-eof value...
	*/

        waiteof = !value[0] || !_cups_strcasecmp(value, "on") ||
		  !_cups_strcasecmp(value, "yes") || !_cups_strcasecmp(value, "true");
      }
      else if (!_cups_strcasecmp(name, "contimeout"))
      {
       /*
        * Set the connection timeout...
	*/

	if (atoi(value) > 0)
	  contimeout = atoi(value);
      }
    }
  }

 /*
  * Then try finding the remote host...
  */

  start_time = time(NULL);

  sprintf(portname, "%d", port);

  fputs("STATE: +connecting-to-device\n", stderr);
  fprintf(stderr, "DEBUG: Looking up \"%s\"...\n", hostname);

  while ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
  {
    _cupsLangPrintFilter(stderr, "INFO",
                         _("Unable to locate printer \"%s\"."), hostname);
    sleep(10);

    if (getenv("CLASS") != NULL)
    {
      fputs("STATE: -connecting-to-device\n", stderr);
      return (CUPS_BACKEND_STOP);
    }
  }

 /*
  * See if the printer supports SNMP...
  */

  if ((snmp_fd = _cupsSNMPOpen(addrlist->addr.addr.sa_family)) >= 0)
  {
    have_supplies = !backendSNMPSupplies(snmp_fd, &(addrlist->addr),
                                         &start_count, NULL);
  }
  else
    have_supplies = start_count = 0;

 /*
  * Wait for data from the filter...
  */

  if (print_fd == 0)
  {
    if (!backendWaitLoop(snmp_fd, &(addrlist->addr), 1, backendNetworkSideCB))
      return (CUPS_BACKEND_OK);
    else if ((bytes = read(0, buffer, sizeof(buffer))) <= 0)
      return (CUPS_BACKEND_OK);
  }

 /*
  * Connect to the printer...
  */

  fprintf(stderr, "DEBUG: Connecting to %s:%d\n", hostname, port);
  _cupsLangPrintFilter(stderr, "INFO", _("Connecting to printer."));

  for (delay = 5;;)
  {
    if ((addr = httpAddrConnect(addrlist, &device_fd)) == NULL)
    {
      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.
	*/

        _cupsLangPrintFilter(stderr, "INFO",
			     _("Unable to contact printer, queuing on next "
			       "printer in class."));

       /*
        * Sleep 5 seconds to keep the job from requeuing too rapidly...
	*/

	sleep(5);

        return (CUPS_BACKEND_FAILED);
      }

      fprintf(stderr, "DEBUG: Connection error: %s\n", strerror(error));

      if (error == ECONNREFUSED || error == EHOSTDOWN ||
          error == EHOSTUNREACH)
      {
        if (contimeout && (time(NULL) - start_time) > contimeout)
	{
	  _cupsLangPrintFilter(stderr, "ERROR",
	                       _("The printer is not responding."));
	  return (CUPS_BACKEND_FAILED);
	}

	switch (error)
	{
	  case EHOSTDOWN :
	      _cupsLangPrintFilter(stderr, "WARNING",
				   _("The printer may not exist or "
				     "is unavailable at this time."));
	      break;

	  case EHOSTUNREACH :
	      _cupsLangPrintFilter(stderr, "WARNING",
				   _("The printer is unreachable at this "
				     "time."));
	      break;

	  case ECONNREFUSED :
	  default :
	      _cupsLangPrintFilter(stderr, "WARNING",
	                           _("The printer is in use."));
	      break;
        }

	sleep(delay);

	if (delay < 30)
	  delay += 5;
      }
      else
      {
	_cupsLangPrintFilter(stderr, "ERROR",
	                     _("The printer is not responding."));
	sleep(30);
      }
    }
    else
      break;
  }

  fputs("STATE: -connecting-to-device\n", stderr);
  _cupsLangPrintFilter(stderr, "INFO", _("Connected to printer."));

  fprintf(stderr, "DEBUG: Connected to %s:%d...\n",
	  httpAddrString(&(addr->addr), addrname, sizeof(addrname)),
	  _httpAddrPort(&(addr->addr)));

 /*
  * Print everything...
  */

  tbytes = 0;

  if (bytes > 0)
    tbytes += write(device_fd, buffer, bytes);

  while (copies > 0 && tbytes >= 0)
  {
    copies --;

    if (print_fd != 0)
    {
      fputs("PAGE: 1 1\n", stderr);
      lseek(print_fd, 0, SEEK_SET);
    }

    tbytes = backendRunLoop(print_fd, device_fd, snmp_fd, &(addrlist->addr), 1,
                            0, backendNetworkSideCB);

    if (print_fd != 0 && tbytes >= 0)
      _cupsLangPrintFilter(stderr, "INFO", _("Print file sent."));
  }

#ifdef __APPLE__
 /*
  * Wait up to 5 seconds to get any pending back-channel data...
  */

  wait_time = time(NULL) + 5;
  while (wait_time >= time(&current_time))
    if (wait_bc(device_fd, wait_time - current_time) <= 0)
      break;
#endif /* __APPLE__ */

  if (waiteof)
  {
   /*
    * Shutdown the socket and wait for the other end to finish...
    */

    _cupsLangPrintFilter(stderr, "INFO", _("Waiting for printer to finish."));

    shutdown(device_fd, 1);

    while (wait_bc(device_fd, 90) > 0);
  }

 /*
  * Collect the final page count as needed...
  */

  if (have_supplies &&
      !backendSNMPSupplies(snmp_fd, &(addrlist->addr), &page_count, NULL) &&
      page_count > start_count)
    fprintf(stderr, "PAGE: total %d\n", page_count - start_count);

 /*
  * Close the socket connection...
  */

  close(device_fd);

  httpAddrFreeList(addrlist);

 /*
  * Close the input file and return...
  */

  if (print_fd != 0)
    close(print_fd);

  return (CUPS_BACKEND_OK);
}
示例#3
0
int					/* O - 1 if data is ready, 0 if not */
backendWaitLoop(
    int          snmp_fd,		/* I - SNMP socket or -1 if none */
    http_addr_t  *addr,			/* I - Address of device */
    int          use_bc,		/* I - Use back-channel? */
    _cups_sccb_t side_cb)		/* I - Side-channel callback */
{
  int			nfds;		/* Number of file descriptors */
  fd_set		input;		/* Input set for reading */
  time_t		curtime = 0,	/* Current time */
			snmp_update = 0;/* Last SNMP status update */
  struct timeval	timeout;	/* Timeout for select() */


  fprintf(stderr, "DEBUG: backendWaitLoop(snmp_fd=%d, addr=%p, side_cb=%p)\n",
	  snmp_fd, addr, side_cb);

 /*
  * Now loop until we receive data from stdin...
  */

  if (snmp_fd >= 0)
    snmp_update = time(NULL) + 5;

  for (;;)
  {
   /*
    * Use select() to determine whether we have data to copy around...
    */

    FD_ZERO(&input);
    FD_SET(0, &input);
    if (side_cb)
      FD_SET(CUPS_SC_FD, &input);

    if (snmp_fd >= 0)
    {
      curtime         = time(NULL);
      timeout.tv_sec  = curtime >= snmp_update ? 0 : snmp_update - curtime;
      timeout.tv_usec = 0;

      nfds = select(CUPS_SC_FD + 1, &input, NULL, NULL, &timeout);
    }
    else
      nfds = select(CUPS_SC_FD + 1, &input, NULL, NULL, NULL);

    if (nfds < 0)
    {
     /*
      * Pause printing to clear any pending errors...
      */

      if (errno == EINTR)
      {
	fputs("DEBUG: Received an interrupt before any bytes were "
	      "written, aborting.\n", stderr);
	return (0);
      }

      sleep(1);
      continue;
    }

   /*
    * Check for input on stdin...
    */

    if (FD_ISSET(0, &input))
      break;

   /*
    * Check if we have a side-channel request ready...
    */

    if (side_cb && FD_ISSET(CUPS_SC_FD, &input))
    {
     /*
      * Do the side-channel request, then start back over in the select
      * loop since it may have read from print_fd...
      */

      if ((*side_cb)(0, -1, snmp_fd, addr, use_bc))
        side_cb = NULL;
      continue;
    }

   /*
    * Do SNMP updates periodically...
    */

    if (snmp_fd >= 0 && curtime >= snmp_update)
    {
      if (backendSNMPSupplies(snmp_fd, addr, NULL, NULL))
        snmp_fd = -1;
      else
        snmp_update = curtime + 5;
    }
  }

 /*
  * Return with success...
  */

  return (1);
}
示例#4
0
ssize_t					/* O - Total bytes on success, -1 on error */
backendRunLoop(
    int          print_fd,		/* I - Print file descriptor */
    int          device_fd,		/* I - Device file descriptor */
    int          snmp_fd,		/* I - SNMP socket or -1 if none */
    http_addr_t  *addr,			/* I - Address of device */
    int          use_bc,		/* I - Use back-channel? */
    int          update_state,		/* I - Update printer-state-reasons? */
    _cups_sccb_t side_cb)		/* I - Side-channel callback */
{
  int		nfds;			/* Maximum file descriptor value + 1 */
  fd_set	input,			/* Input set for reading */
		output;			/* Output set for writing */
  ssize_t	print_bytes,		/* Print bytes read */
		bc_bytes,		/* Backchannel bytes read */
		total_bytes,		/* Total bytes written */
		bytes;			/* Bytes written */
  int		paperout;		/* "Paper out" status */
  int		offline;		/* "Off-line" status */
  char		print_buffer[8192],	/* Print data buffer */
		*print_ptr,		/* Pointer into print data buffer */
		bc_buffer[1024];	/* Back-channel data buffer */
  struct timeval timeout;		/* Timeout for select() */
  time_t	curtime,		/* Current time */
		snmp_update = 0;
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
  struct sigaction action;		/* Actions for POSIX signals */
#endif /* HAVE_SIGACTION && !HAVE_SIGSET */


  fprintf(stderr,
          "DEBUG: backendRunLoop(print_fd=%d, device_fd=%d, snmp_fd=%d, "
	  "addr=%p, use_bc=%d, side_cb=%p)\n",
          print_fd, device_fd, snmp_fd, addr, use_bc, side_cb);

 /*
  * If we are printing data from a print driver on stdin, ignore SIGTERM
  * so that the driver can finish out any page data, e.g. to eject the
  * current page.  We only do this for stdin printing as otherwise there
  * is no way to cancel a raw print job...
  */

  if (!print_fd)
  {
#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 */
  }
  else if (print_fd < 0)
  {
   /*
    * Copy print data from stdin, but don't mess with the signal handlers...
    */

    print_fd = 0;
  }

 /*
  * Figure out the maximum file descriptor value to use with select()...
  */

  nfds = (print_fd > device_fd ? print_fd : device_fd) + 1;

 /*
  * Now loop until we are out of data from print_fd...
  */

  for (print_bytes = 0, print_ptr = print_buffer, offline = -1,
           paperout = -1, total_bytes = 0;;)
  {
   /*
    * Use select() to determine whether we have data to copy around...
    */

    FD_ZERO(&input);
    if (!print_bytes)
      FD_SET(print_fd, &input);
    if (use_bc)
      FD_SET(device_fd, &input);
    if (!print_bytes && side_cb)
      FD_SET(CUPS_SC_FD, &input);

    FD_ZERO(&output);
    if (print_bytes || (!use_bc && !side_cb))
      FD_SET(device_fd, &output);

    if (use_bc || side_cb)
    {
      timeout.tv_sec  = 5;
      timeout.tv_usec = 0;

      if (select(nfds, &input, &output, NULL, &timeout) < 0)
      {
       /*
	* Pause printing to clear any pending errors...
	*/

	if (errno == ENXIO && offline != 1 && update_state)
	{
	  fputs("STATE: +offline-report\n", stderr);
	  _cupsLangPrintFilter(stderr, "INFO",
	                       _("The printer is not connected."));
	  offline = 1;
	}
	else if (errno == EINTR && total_bytes == 0)
	{
	  fputs("DEBUG: Received an interrupt before any bytes were "
	        "written, aborting.\n", stderr);
          return (0);
	}

	sleep(1);
	continue;
      }
    }

   /*
    * Check if we have a side-channel request ready...
    */

    if (side_cb && FD_ISSET(CUPS_SC_FD, &input))
    {
     /*
      * Do the side-channel request, then start back over in the select
      * loop since it may have read from print_fd...
      */

      if ((*side_cb)(print_fd, device_fd, snmp_fd, addr, use_bc))
        side_cb = NULL;
      continue;
    }

   /*
    * Check if we have back-channel data ready...
    */

    if (FD_ISSET(device_fd, &input))
    {
      if ((bc_bytes = read(device_fd, bc_buffer, sizeof(bc_buffer))) > 0)
      {
	fprintf(stderr,
	        "DEBUG: Received " CUPS_LLFMT " bytes of back-channel data\n",
	        CUPS_LLCAST bc_bytes);
        cupsBackChannelWrite(bc_buffer, bc_bytes, 1.0);
      }
      else if (bc_bytes < 0 && errno != EAGAIN && errno != EINTR)
      {
        fprintf(stderr, "DEBUG: Error reading back-channel data: %s\n",
	        strerror(errno));
	use_bc = 0;
      }
      else if (bc_bytes == 0)
        use_bc = 0;
    }

   /*
    * Check if we have print data ready...
    */

    if (FD_ISSET(print_fd, &input))
    {
      if ((print_bytes = read(print_fd, print_buffer,
                              sizeof(print_buffer))) < 0)
      {
       /*
        * Read error - bail if we don't see EAGAIN or EINTR...
	*/

	if (errno != EAGAIN || errno != EINTR)
	{
	  fprintf(stderr, "DEBUG: Read failed: %s\n", strerror(errno));
	  _cupsLangPrintFilter(stderr, "ERROR",
	                       _("Unable to read print data."));
	  return (-1);
	}

        print_bytes = 0;
      }
      else if (print_bytes == 0)
      {
       /*
        * End of file, break out of the loop...
	*/

        break;
      }

      print_ptr = print_buffer;

      fprintf(stderr, "DEBUG: Read %d bytes of print data...\n",
              (int)print_bytes);
    }

   /*
    * Check if the device is ready to receive data and we have data to
    * send...
    */

    if (print_bytes && FD_ISSET(device_fd, &output))
    {
      if ((bytes = write(device_fd, print_ptr, print_bytes)) < 0)
      {
       /*
        * Write error - bail if we don't see an error we can retry...
	*/

        if (errno == ENOSPC)
	{
	  if (paperout != 1 && update_state)
	  {
	    fputs("STATE: +media-empty-warning\n", stderr);
	    fputs("DEBUG: Out of paper\n", stderr);
	    paperout = 1;
	  }
        }
	else if (errno == ENXIO)
	{
	  if (offline != 1 && update_state)
	  {
	    fputs("STATE: +offline-report\n", stderr);
	    _cupsLangPrintFilter(stderr, "INFO",
	                         _("The printer is not connected."));
	    offline = 1;
	  }
	}
	else if (errno != EAGAIN && errno != EINTR && errno != ENOTTY)
	{
	  _cupsLangPrintError("ERROR", _("Unable to write print data"));
	  return (-1);
	}
      }
      else
      {
        if (paperout && update_state)
	{
	  fputs("STATE: -media-empty-warning\n", stderr);
	  paperout = 0;
	}

	if (offline && update_state)
	{
	  fputs("STATE: -offline-report\n", stderr);
	  _cupsLangPrintFilter(stderr, "INFO",
	                       _("The printer is now connected."));
	  offline = 0;
	}

        fprintf(stderr, "DEBUG: Wrote %d bytes of print data...\n", (int)bytes);

        print_bytes -= bytes;
	print_ptr   += bytes;
	total_bytes += bytes;
      }
    }

   /*
    * Do SNMP updates periodically...
    */

    if (snmp_fd >= 0 && time(&curtime) >= snmp_update)
    {
      if (backendSNMPSupplies(snmp_fd, addr, NULL, NULL))
        snmp_update = INT_MAX;
      else
        snmp_update = curtime + 5;
    }
  }

 /*
  * Return with success...
  */

  return (total_bytes);
}
示例#5
0
static int				/* O - Zero on success, non-zero on failure */
lpd_queue(const char      *hostname,	/* I - Host to connect to */
          http_addrlist_t *addrlist,	/* I - List of host addresses */
          const char      *printer,	/* I - Printer/queue name */
	  int             print_fd,	/* I - File to print */
	  int             snmp_fd,	/* I - SNMP socket */
	  int             mode,		/* I - Print mode */
          const char      *user,	/* I - Requesting user */
	  const char      *title,	/* I - Job title */
	  int             copies,	/* I - Number of copies */
	  int             banner,	/* I - Print LPD banner? */
          int             format,	/* I - Format specifier */
          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             contimeout,	/* I - Connection timeout */
	  const char      *orighost)	/* I - job-originating-host-name */
{
  char			localhost[255];	/* Local host name */
  int			error;		/* Error number */
  struct stat		filestats;	/* File statistics */
  int			lport;		/* LPD connection local port */
  int			fd;		/* LPD socket */
  char			control[10240],	/* LPD control 'file' */
			*cptr;		/* Pointer into control file string */
  char			status;		/* Status byte from command */
  int			delay;		/* Delay for retries... */
  char			addrname[256];	/* Address name */
  http_addrlist_t	*addr;		/* Socket address */
  int			have_supplies;	/* Printer supports supply levels? */
  int			copy;		/* Copies written */
  time_t		start_time;	/* Time of first connect */
  size_t		nbytes;		/* Number of bytes written */
  off_t			tbytes;		/* Total bytes written */
  char			buffer[32768];	/* Output buffer */
#ifdef WIN32
  DWORD			tv;		/* Timeout in milliseconds */
#else
  struct timeval	tv;		/* Timeout in secs and usecs */
#endif /* WIN32 */


 /*
  * Remember when we started trying to connect to the printer...
  */

  start_time = time(NULL);

 /*
  * Loop forever trying to print the file...
  */

  while (!abort_job)
  {
   /*
    * First try to reserve a port for this connection...
    */

    fprintf(stderr, "DEBUG: Connecting to %s:%d for printer %s\n", hostname,
            httpAddrPort(&(addrlist->addr)), printer);
    _cupsLangPrintFilter(stderr, "INFO", _("Connecting to printer."));

    for (lport = reserve == RESERVE_RFC1179 ? 732 : 1024, addr = addrlist,
             delay = 5;;
         addr = addr->next)
    {
     /*
      * Stop if this job has been canceled...
      */

      if (abort_job)
        return (CUPS_BACKEND_FAILED);

     /*
      * Choose the next priviledged port...
      */

      if (!addr)
        addr = addrlist;

      lport --;

      if (lport < 721 && reserve == RESERVE_RFC1179)
	lport = 731;
      else if (lport < 1)
	lport = 1023;

#ifdef HAVE_GETEUID
      if (geteuid() || !reserve)
#else
      if (getuid() || !reserve)
#endif /* HAVE_GETEUID */
      {
       /*
	* Just create a regular socket...
	*/

	if ((fd = socket(addr->addr.addr.sa_family, SOCK_STREAM, 0)) < 0)
	{
	  perror("DEBUG: Unable to create socket");
	  sleep(1);

          continue;
	}

        lport = 0;
      }
      else
      {
       /*
	* We're running as root and want to comply with RFC 1179.  Reserve a
	* priviledged lport between 721 and 731...
	*/

	if ((fd = rresvport_af(&lport, addr->addr.addr.sa_family)) < 0)
	{
	  perror("DEBUG: Unable to reserve port");
	  sleep(1);

	  continue;
	}
      }

     /*
      * Connect to the printer or server...
      */

      if (abort_job)
      {
	close(fd);

	return (CUPS_BACKEND_FAILED);
      }

      if (!connect(fd, &(addr->addr.addr), httpAddrLength(&(addr->addr))))
	break;

      error = errno;
      close(fd);

      if (addr->next)
        continue;

      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.
	*/

        _cupsLangPrintFilter(stderr, "INFO",
			     _("Unable to contact printer, queuing on next "
			       "printer in class."));

       /*
        * Sleep 5 seconds to keep the job from requeuing too rapidly...
	*/

	sleep(5);

        return (CUPS_BACKEND_FAILED);
      }

      fprintf(stderr, "DEBUG: Connection error: %s\n", strerror(error));

      if (error == ECONNREFUSED || error == EHOSTDOWN ||
          error == EHOSTUNREACH)
      {
        if (contimeout && (time(NULL) - start_time) > contimeout)
	{
	  _cupsLangPrintFilter(stderr, "ERROR",
			       _("The printer is not responding."));
	  return (CUPS_BACKEND_FAILED);
	}

	switch (error)
	{
	  case EHOSTDOWN :
	      _cupsLangPrintFilter(stderr, "WARNING",
			           _("The printer may not exist or "
			             "is unavailable at this time."));
	      break;

	  case EHOSTUNREACH :
	      _cupsLangPrintFilter(stderr, "WARNING",
			           _("The printer is unreachable at "
				     "this time."));
	      break;

	  case ECONNREFUSED :
	  default :
	      _cupsLangPrintFilter(stderr, "WARNING",
	                           _("The printer is in use."));
	      break;
        }

	sleep(delay);

	if (delay < 30)
	  delay += 5;
      }
      else if (error == EADDRINUSE)
      {
       /*
	* Try on another port...
	*/

	sleep(1);
      }
      else
      {
	_cupsLangPrintFilter(stderr, "ERROR",
	                     _("The printer is not responding."));
	sleep(30);
      }
    }

   /*
    * Set the timeout...
    */

#ifdef WIN32
    tv = (DWORD)(timeout * 1000);

    setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv));
    setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv));
#else
    tv.tv_sec  = timeout;
    tv.tv_usec = 0;

    setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
    setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
#endif /* WIN32 */

    fputs("STATE: -connecting-to-device\n", stderr);
    _cupsLangPrintFilter(stderr, "INFO", _("Connected to printer."));

    fprintf(stderr, "DEBUG: Connected to %s:%d (local port %d)...\n",
	    httpAddrString(&(addr->addr), addrname, sizeof(addrname)),
	    httpAddrPort(&(addr->addr)), lport);

   /*
    * See if the printer supports SNMP...
    */

    if (snmp_fd >= 0)
      have_supplies = !backendSNMPSupplies(snmp_fd, &(addrlist->addr), NULL,
                                           NULL);
    else
      have_supplies = 0;

   /*
    * Check for side-channel requests...
    */

    backendCheckSideChannel(snmp_fd, &(addrlist->addr));

   /*
    * Next, open the print file and figure out its size...
    */

    if (print_fd)
    {
     /*
      * Use the size from the print file...
      */

      if (fstat(print_fd, &filestats))
      {
	close(fd);

	perror("DEBUG: unable to stat print file");
	return (CUPS_BACKEND_FAILED);
      }

      filestats.st_size *= manual_copies;
    }
    else
    {
     /*
      * Use a "very large value" for the size so that the printer will
      * keep printing until we close the connection...
      */

#ifdef _LARGEFILE_SOURCE
      filestats.st_size = (size_t)(999999999999.0);
#else
      filestats.st_size = 2147483647;
#endif /* _LARGEFILE_SOURCE */
    }

   /*
    * Send a job header to the printer, specifying no banner page and
    * literal output...
    */

    if (lpd_command(fd, "\002%s\n",
                    printer))		/* Receive print job(s) */
    {
      close(fd);
      return (CUPS_BACKEND_FAILED);
    }

    if (orighost && _cups_strcasecmp(orighost, "localhost"))
      strlcpy(localhost, orighost, sizeof(localhost));
    else
      httpGetHostname(NULL, localhost, sizeof(localhost));

    snprintf(control, sizeof(control),
             "H%.31s\n"		/* RFC 1179, Section 7.2 - host name <= 31 chars */
	     "P%.31s\n"		/* RFC 1179, Section 7.2 - user name <= 31 chars */
	     "J%.99s\n",	/* RFC 1179, Section 7.2 - job name <= 99 chars */
	     localhost, user, title);
    cptr = control + strlen(control);

    if (banner)
    {
      snprintf(cptr, sizeof(control) - (cptr - control),
               "C%.31s\n"	/* RFC 1179, Section 7.2 - class name <= 31 chars */
	       "L%s\n",
               localhost, user);
      cptr   += strlen(cptr);
    }

    while (copies > 0)
    {
      snprintf(cptr, sizeof(control) - (cptr - control), "%cdfA%03d%.15s\n",
               format, (int)getpid() % 1000, localhost);
      cptr   += strlen(cptr);
      copies --;
    }

    snprintf(cptr, sizeof(control) - (cptr - control),
             "UdfA%03d%.15s\n"
	     "N%.131s\n",	/* RFC 1179, Section 7.2 - sourcefile name <= 131 chars */
             (int)getpid() % 1000, localhost, title);

    fprintf(stderr, "DEBUG: Control file is:\n%s", control);

    if (order == ORDER_CONTROL_DATA)
    {
     /*
      * Check for side-channel requests...
      */

      backendCheckSideChannel(snmp_fd, &(addr->addr));

     /*
      * Send the control file...
      */

      if (lpd_command(fd, "\002%d cfA%03.3d%.15s\n", strlen(control),
                      (int)getpid() % 1000, localhost))
      {
	close(fd);

        return (CUPS_BACKEND_FAILED);
      }

      fprintf(stderr, "DEBUG: Sending control file (%u bytes)\n",
	      (unsigned)strlen(control));

      if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1))
      {
	status = errno;
	perror("DEBUG: Unable to write control file");

      }
      else
      {
        if (read(fd, &status, 1) < 1)
	{
	  _cupsLangPrintFilter(stderr, "WARNING",
	                       _("The printer did not respond."));
	  status = errno;
	}
      }

      if (status != 0)
	_cupsLangPrintFilter(stderr, "ERROR",
			     _("Remote host did not accept control file (%d)."),
			     status);
      else
	_cupsLangPrintFilter(stderr, "INFO",
	                     _("Control file sent successfully."));
    }
    else
      status = 0;

    if (status == 0)
    {
     /*
      * Check for side-channel requests...
      */

      backendCheckSideChannel(snmp_fd, &(addr->addr));

     /*
      * Send the print file...
      */

      if (lpd_command(fd, "\003" CUPS_LLFMT " dfA%03.3d%.15s\n",
                      CUPS_LLCAST filestats.st_size, (int)getpid() % 1000,
		      localhost))
      {
	close(fd);

        return (CUPS_BACKEND_FAILED);
      }

      fprintf(stderr, "DEBUG: Sending data file (" CUPS_LLFMT " bytes)\n",
	      CUPS_LLCAST filestats.st_size);

      tbytes = 0;
      for (copy = 0; copy < manual_copies; copy ++)
      {
	lseek(print_fd, 0, SEEK_SET);

	while ((nbytes = read(print_fd, buffer, sizeof(buffer))) > 0)
	{
	  _cupsLangPrintFilter(stderr, "INFO",
			       _("Spooling job, %.0f%% complete."),
			       100.0 * tbytes / filestats.st_size);

	  if (lpd_write(fd, buffer, nbytes) < nbytes)
	  {
	    perror("DEBUG: Unable to send print file to printer");
            break;
	  }
	  else
            tbytes += nbytes;
	}
      }

      if (mode == MODE_STANDARD)
      {
	if (tbytes < filestats.st_size)
	  status = errno;
	else if (lpd_write(fd, "", 1) < 1)
	{
	  perror("DEBUG: Unable to send trailing nul to printer");
	  status = errno;
	}
	else
	{
	 /*
          * Read the status byte from the printer; if we can't read the byte
	  * back now, we should set status to "errno", however at this point
	  * we know the printer got the whole file and we don't necessarily
	  * want to requeue it over and over...
	  */

          if (recv(fd, &status, 1, 0) < 1)
	  {
	    _cupsLangPrintFilter(stderr, "WARNING",
			         _("The printer did not respond."));
	    status = 0;
          }
	}
      }
      else
        status = 0;

      if (status != 0)
	_cupsLangPrintFilter(stderr, "ERROR",
			     _("Remote host did not accept data file (%d)."),
			     status);
      else
	_cupsLangPrintFilter(stderr, "INFO",
	                     _("Data file sent successfully."));
    }

    if (status == 0 && order == ORDER_DATA_CONTROL)
    {
     /*
      * Check for side-channel requests...
      */

      backendCheckSideChannel(snmp_fd, &(addr->addr));

     /*
      * Send control file...
      */

      if (lpd_command(fd, "\002%d cfA%03.3d%.15s\n", strlen(control),
                      (int)getpid() % 1000, localhost))
      {
	close(fd);

        return (CUPS_BACKEND_FAILED);
      }

      fprintf(stderr, "DEBUG: Sending control file (%lu bytes)\n",
	      (unsigned long)strlen(control));

      if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1))
      {
	status = errno;
	perror("DEBUG: Unable to write control file");
      }
      else
      {
        if (read(fd, &status, 1) < 1)
	{
	  _cupsLangPrintFilter(stderr, "WARNING",
			       _("The printer did not respond."));
	  status = errno;
	}
      }

      if (status != 0)
	_cupsLangPrintFilter(stderr, "ERROR",
			     _("Remote host did not accept control file (%d)."),
			     status);
      else
	_cupsLangPrintFilter(stderr, "INFO",
	                     _("Control file sent successfully."));
    }

   /*
    * Collect the final supply levels as needed...
    */

    if (have_supplies)
      backendSNMPSupplies(snmp_fd, &(addr->addr), NULL, NULL);

   /*
    * Close the socket connection and input file...
    */

    close(fd);

    if (status == 0)
      return (CUPS_BACKEND_OK);

   /*
    * Waiting for a retry...
    */

    sleep(30);
  }

 /*
  * If we get here, then the job has been canceled...
  */

  return (CUPS_BACKEND_FAILED);
}