예제 #1
0
파일: main.c 프로젝트: ChErePOdaViLka/cups
static void
launchd_checkin(void)
{
  size_t		i,		/* Looping var */
			count;		/* Number of listeners */
  launch_data_t		ld_msg,		/* Launch data message */
			ld_resp,	/* Launch data response */
			ld_array,	/* Launch data array */
			ld_sockets,	/* Launch data sockets dictionary */
			tmp;		/* Launch data */
  cupsd_listener_t	*lis;		/* Listeners array */
  http_addr_t		addr;		/* Address variable */
  socklen_t		addrlen;	/* Length of address */
  int			fd;		/* File descriptor */
  char			s[256];		/* String addresss */


  cupsdLogMessage(CUPSD_LOG_DEBUG, "launchd_checkin: pid=%d", (int)getpid());

 /*
  * Check-in with launchd...
  */

  ld_msg = launch_data_new_string(LAUNCH_KEY_CHECKIN);
  if ((ld_resp = launch_msg(ld_msg)) == NULL)
  {
    cupsdLogMessage(CUPSD_LOG_ERROR,
		    "launchd_checkin: launch_msg(\"" LAUNCH_KEY_CHECKIN
		    "\") IPC failure");
    exit(EXIT_FAILURE);
    return; /* anti-compiler-warning */
  }

  if (launch_data_get_type(ld_resp) == LAUNCH_DATA_ERRNO)
  {
    errno = launch_data_get_errno(ld_resp);
    cupsdLogMessage(CUPSD_LOG_ERROR, "launchd_checkin: Check-in failed: %s",
                    strerror(errno));
    exit(EXIT_FAILURE);
    return; /* anti-compiler-warning */
  }

 /*
  * Get the sockets dictionary...
  */

  if ((ld_sockets = launch_data_dict_lookup(ld_resp, LAUNCH_JOBKEY_SOCKETS))
          == NULL)
  {
    cupsdLogMessage(CUPSD_LOG_ERROR,
                    "launchd_checkin: No sockets found to answer requests on!");
    exit(EXIT_FAILURE);
    return; /* anti-compiler-warning */
  }

 /*
  * Get the array of listener sockets...
  */

  if ((ld_array = launch_data_dict_lookup(ld_sockets, "Listeners")) == NULL)
  {
    cupsdLogMessage(CUPSD_LOG_ERROR,
                    "launchd_checkin: No sockets found to answer requests on!");
    exit(EXIT_FAILURE);
    return; /* anti-compiler-warning */
  }

 /*
  * Add listening fd(s) to the Listener array...
  */

  if (launch_data_get_type(ld_array) == LAUNCH_DATA_ARRAY)
  {
    count = launch_data_array_get_count(ld_array);

    for (i = 0; i < count; i ++)
    {
     /*
      * Get the launchd file descriptor and address...
      */

      if ((tmp = launch_data_array_get_index(ld_array, i)) != NULL)
      {
	fd      = launch_data_get_fd(tmp);
	addrlen = sizeof(addr);

	if (getsockname(fd, (struct sockaddr *)&addr, &addrlen))
	{
	  cupsdLogMessage(CUPSD_LOG_ERROR,
			  "launchd_checkin: Unable to get local address - %s",
			  strerror(errno));
	  continue;
	}

       /*
	* Try to match the launchd socket address to one of the listeners...
	*/

	for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
	     lis;
	     lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
	  if (httpAddrEqual(&lis->address, &addr))
	    break;

       /*
	* Add a new listener If there's no match...
	*/

	if (lis)
	{
	  cupsdLogMessage(CUPSD_LOG_DEBUG,
		  "launchd_checkin: Matched existing listener %s with fd %d...",
		  httpAddrString(&(lis->address), s, sizeof(s)), fd);
	}
	else
	{
	  cupsdLogMessage(CUPSD_LOG_DEBUG,
		  "launchd_checkin: Adding new listener %s with fd %d...",
		  httpAddrString(&addr, s, sizeof(s)), fd);

	  if ((lis = calloc(1, sizeof(cupsd_listener_t))) == NULL)
	  {
	    cupsdLogMessage(CUPSD_LOG_ERROR,
			    "launchd_checkin: Unable to allocate listener - "
			    "%s.", strerror(errno));
	    exit(EXIT_FAILURE);
	  }

	  cupsArrayAdd(Listeners, lis);

	  memcpy(&lis->address, &addr, sizeof(lis->address));
	}

	lis->fd = fd;

#  ifdef HAVE_SSL
	if (_httpAddrPort(&(lis->address)) == 443)
	  lis->encryption = HTTP_ENCRYPT_ALWAYS;
#  endif /* HAVE_SSL */
      }
    }
  }

  launch_data_free(ld_msg);
  launch_data_free(ld_resp);
}
예제 #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
static void
cups_create_localizations(
    http_t       *http,			/* I - Connection to destination */
    cups_dinfo_t *dinfo)		/* I - Destination informations */
{
  http_t		*http2;		/* Connection for strings file */
  http_status_t		status;		/* Request status */
  ipp_attribute_t	*attr;		/* "printer-strings-uri" attribute */
  char			scheme[32],	/* URI scheme */
  			userpass[256],	/* Username/password info */
  			hostname[256],	/* Hostname */
  			resource[1024],	/* Resource */
  			http_hostname[256],
  					/* Hostname of connection */
			tempfile[1024];	/* Temporary filename */
  int			port;		/* Port number */
  http_encryption_t	encryption;	/* Encryption to use */
  cups_file_t		*temp;		/* Temporary file */


 /*
  * Create an empty message catalog...
  */

  dinfo->localizations = _cupsMessageNew(NULL);

 /*
  * See if there are any localizations...
  */

  if ((attr = ippFindAttribute(dinfo->attrs, "printer-strings-uri",
                               IPP_TAG_URI)) == NULL)
  {
   /*
    * Nope...
    */

    DEBUG_puts("4cups_create_localizations: No printer-strings-uri (uri) "
               "value.");
    return;				/* Nope */
  }

 /*
  * Pull apart the URI and determine whether we need to try a different
  * server...
  */

  if (httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[0].string.text,
                      scheme, sizeof(scheme), userpass, sizeof(userpass),
                      hostname, sizeof(hostname), &port, resource,
                      sizeof(resource)) < HTTP_URI_OK)
  {
    DEBUG_printf(("4cups_create_localizations: Bad printer-strings-uri value "
                  "\"%s\".", attr->values[0].string.text));
    return;
  }

  httpGetHostname(http, http_hostname, sizeof(http_hostname));

  if (!_cups_strcasecmp(http_hostname, hostname) &&
      port == _httpAddrPort(http->hostaddr))
  {
   /*
    * Use the same connection...
    */

    http2 = http;
  }
  else
  {
   /*
    * Connect to the alternate host...
    */

    if (!strcmp(scheme, "https"))
      encryption = HTTP_ENCRYPT_ALWAYS;
    else
      encryption = HTTP_ENCRYPT_IF_REQUESTED;

    if ((http2 = httpConnectEncrypt(hostname, port, encryption)) == NULL)
    {
      DEBUG_printf(("4cups_create_localizations: Unable to connect to "
                    "%s:%d: %s", hostname, port, cupsLastErrorString()));
      return;
    }
  }

 /*
  * Get a temporary file...
  */

  if ((temp = cupsTempFile2(tempfile, sizeof(tempfile))) == NULL)
  {
    DEBUG_printf(("4cups_create_localizations: Unable to create temporary "
                  "file: %s", cupsLastErrorString()));
    if (http2 != http)
      httpClose(http2);
    return;
  }

  status = cupsGetFd(http2, resource, cupsFileNumber(temp));

  DEBUG_printf(("4cups_create_localizations: GET %s = %s", resource,
                httpStatus(status)));

  if (status == HTTP_OK)
  {
   /*
    * Got the file, read it...
    */

    char		buffer[8192],	/* Message buffer */
    			*id,		/* ID string */
    			*str;		/* Translated message */
    _cups_message_t	*m;		/* Current message */

    lseek(cupsFileNumber(temp), 0, SEEK_SET);

    while (cups_read_strings(temp, buffer, sizeof(buffer), &id, &str))
    {
      if ((m = malloc(sizeof(_cups_message_t))) == NULL)
        break;

      m->id  = strdup(id);
      m->str = strdup(str);

      if (m->id && m->str)
        cupsArrayAdd(dinfo->localizations, m);
      else
      {
        if (m->id)
          free(m->id);

        if (m->str)
          free(m->str);

        free(m);
        break;
      }
    }
  }

  DEBUG_printf(("4cups_create_localizations: %d messages loaded.",
                cupsArrayCount(dinfo->localizations)));

 /*
  * Cleanup...
  */

  unlink(tempfile);
  cupsFileClose(temp);

  if (http2 != http)
    httpClose(http2);
}
예제 #4
0
파일: lpd.c 프로젝트: nafaspoil/cups
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);
}
예제 #5
0
파일: listen.c 프로젝트: AnotherView/cups
void
cupsdStartListening(void)
{
  int			status;		/* Bind result */
  int			p,		/* Port number */
			val;		/* Parameter value */
  cupsd_listener_t	*lis;		/* Current listening socket */
  char			s[256];		/* String addresss */
  const char		*have_domain;	/* Have a domain socket? */
  static const char * const encryptions[] =
		{			/* Encryption values */
		  "IfRequested",
		  "Never",
		  "Required",
		  "Always"
		};


  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartListening: %d Listeners",
                  cupsArrayCount(Listeners));

 /*
  * Setup socket listeners...
  */

  for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners), LocalPort = 0,
           have_domain = NULL;
       lis;
       lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
  {
    httpAddrString(&(lis->address), s, sizeof(s));
    p = _httpAddrPort(&(lis->address));

   /*
    * If needed, create a socket for listening...
    */

    if (lis->fd == -1)
    {
     /*
      * Create a socket for listening...
      */

      lis->fd = socket(lis->address.addr.sa_family, SOCK_STREAM, 0);

      if (lis->fd == -1)
      {
	cupsdLogMessage(CUPSD_LOG_ERROR,
			"Unable to open listen socket for address %s:%d - %s.",
			s, p, strerror(errno));

#ifdef AF_INET6
       /*
        * IPv6 is often disabled while DNS returns IPv6 addresses...
	*/

	if (lis->address.addr.sa_family != AF_INET6 &&
	    (FatalErrors & CUPSD_FATAL_LISTEN))
	  cupsdEndProcess(getpid(), 0);
#else
	if (FatalErrors & CUPSD_FATAL_LISTEN)
	  cupsdEndProcess(getpid(), 0);
#endif /* AF_INET6 */

	continue;
      }

     /*
      * Set things up to reuse the local address for this port.
      */

      val = 1;
#ifdef __sun
      setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
#else
      setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
#endif /* __sun */

     /*
      * Bind to the port we found...
      */

#ifdef AF_INET6
      if (lis->address.addr.sa_family == AF_INET6)
      {
#  ifdef IPV6_V6ONLY
       /*
	* Accept only IPv6 connections on this socket, to avoid
	* potential security issues and to make all platforms behave
	* the same.
	*/

	val = 1;
#    ifdef __sun
	setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&val, sizeof(val));
#    else
	setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
#    endif /* __sun */
#  endif /* IPV6_V6ONLY */

	status = bind(lis->fd, (struct sockaddr *)&(lis->address),
		      httpAddrLength(&(lis->address)));
      }
      else
#endif /* AF_INET6 */
#ifdef AF_LOCAL
      if (lis->address.addr.sa_family == AF_LOCAL)
      {
	mode_t	mask;			/* Umask setting */


       /*
	* Remove any existing domain socket file...
	*/

	unlink(lis->address.un.sun_path);

       /*
	* Save the current umask and set it to 0 so that all users can access
	* the domain socket...
	*/

	mask = umask(0);

       /*
	* Bind the domain socket...
	*/

	status = bind(lis->fd, (struct sockaddr *)&(lis->address),
		      httpAddrLength(&(lis->address)));

       /*
	* Restore the umask...
	*/

	umask(mask);
      }
      else
#endif /* AF_LOCAL */
      status = bind(lis->fd, (struct sockaddr *)&(lis->address),
		    sizeof(lis->address.ipv4));

      if (status < 0)
      {
	cupsdLogMessage(CUPSD_LOG_ERROR,
			"Unable to bind socket for address %s:%d - %s.",
			s, p, strerror(errno));
	close(lis->fd);
	lis->fd = -1;

	if (FatalErrors & CUPSD_FATAL_LISTEN)
	  cupsdEndProcess(getpid(), 0);

	continue;
      }

     /*
      * Listen for new clients.
      */

      if (listen(lis->fd, ListenBackLog) < 0)
      {
	cupsdLogMessage(CUPSD_LOG_ERROR,
			"Unable to listen for clients on address %s:%d - %s.",
			s, p, strerror(errno));

	close(lis->fd);
	lis->fd = -1;

	if (FatalErrors & CUPSD_FATAL_LISTEN)
	  cupsdEndProcess(getpid(), 0);

        continue;
      }
    }

    fcntl(lis->fd, F_SETFD, fcntl(lis->fd, F_GETFD) | FD_CLOEXEC);

    if (p)
      cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d on fd %d...",
        	      s, p, lis->fd);
    else
    {
      cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s on fd %d...",
        	      s, lis->fd);

      if (chmod(s, 0140777))
	cupsdLogMessage(CUPSD_LOG_ERROR,
			"Unable to change permisssions on domain socket "
			"\"%s\" - %s", s, strerror(errno));
    }

   /*
    * Save the first port that is bound to the local loopback or
    * "any" address...
    */

    if ((!LocalPort || LocalEncryption == HTTP_ENCRYPT_ALWAYS) && p > 0 &&
        (httpAddrLocalhost(&(lis->address)) ||
         httpAddrAny(&(lis->address))))
    {
      LocalPort       = p;
      LocalEncryption = lis->encryption;
    }

#ifdef AF_LOCAL
    if (lis->address.addr.sa_family == AF_LOCAL && !have_domain)
      have_domain = lis->address.un.sun_path;
#endif /* AF_LOCAL */
  }

 /*
  * Make sure that we are listening on localhost!
  */

  if (!LocalPort && !have_domain)
  {
    cupsdLogMessage(CUPSD_LOG_EMERG,
                    "No Listen or Port lines were found to allow access via "
		    "localhost!");

    if (FatalErrors & (CUPSD_FATAL_CONFIG | CUPSD_FATAL_LISTEN))
      cupsdEndProcess(getpid(), 0);
  }

 /*
  * Set the CUPS_SERVER, IPP_PORT, and CUPS_ENCRYPTION variables based on
  * the listeners...
  */

  if (have_domain)
  {
   /*
    * Use domain sockets for the local connection...
    */

    cupsdSetEnv("CUPS_SERVER", have_domain);

    LocalEncryption = HTTP_ENCRYPT_IF_REQUESTED;
  }
  else
  {
   /*
    * Use the default local loopback address for the server...
    */

    cupsdSetEnv("CUPS_SERVER", "localhost");
  }

  cupsdSetEnv("CUPS_ENCRYPTION", encryptions[LocalEncryption]);

  if (LocalPort)
    cupsdSetEnvf("IPP_PORT", "%d", LocalPort);

 /*
  * Resume listening for connections...
  */

  cupsdResumeListening();
}
예제 #6
0
파일: util.c 프로젝트: AnotherView/cups
http_status_t				/* O  - HTTP status */
cupsGetPPD3(http_t     *http,		/* I  - HTTP connection or @code CUPS_HTTP_DEFAULT@ */
            const char *name,		/* I  - Destination name */
	    time_t     *modtime,	/* IO - Modification time */
	    char       *buffer,		/* I  - Filename buffer */
	    size_t     bufsize)		/* I  - Size of filename buffer */
{
  int		http_port;		/* Port number */
  char		http_hostname[HTTP_MAX_HOST];
					/* Hostname associated with connection */
  http_t	*http2;			/* Alternate HTTP connection */
  int		fd;			/* PPD file */
  char		localhost[HTTP_MAX_URI],/* Local hostname */
		hostname[HTTP_MAX_URI],	/* Hostname */
		resource[HTTP_MAX_URI];	/* Resource name */
  int		port;			/* Port number */
  http_status_t	status;			/* HTTP status from server */
  char		tempfile[1024] = "";	/* Temporary filename */
  _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */


 /*
  * Range check input...
  */

  DEBUG_printf(("cupsGetPPD3(http=%p, name=\"%s\", modtime=%p(%d), buffer=%p, "
                "bufsize=%d)", http, name, modtime,
		modtime ? (int)*modtime : 0, buffer, (int)bufsize));

  if (!name)
  {
    _cupsSetError(IPP_INTERNAL_ERROR, _("No printer name"), 1);
    return (HTTP_NOT_ACCEPTABLE);
  }

  if (!modtime)
  {
    _cupsSetError(IPP_INTERNAL_ERROR, _("No modification time"), 1);
    return (HTTP_NOT_ACCEPTABLE);
  }

  if (!buffer || bufsize <= 1)
  {
    _cupsSetError(IPP_INTERNAL_ERROR, _("Bad filename buffer"), 1);
    return (HTTP_NOT_ACCEPTABLE);
  }

#ifndef WIN32
 /*
  * See if the PPD file is available locally...
  */

  if (!cg->servername[0])
    cupsServer();

  if (!_cups_strcasecmp(cg->servername, "localhost"))
  {
    char	ppdname[1024];		/* PPD filename */
    struct stat	ppdinfo;		/* PPD file information */


    snprintf(ppdname, sizeof(ppdname), "%s/ppd/%s.ppd", cg->cups_serverroot,
             name);
    if (!stat(ppdname, &ppdinfo))
    {
     /*
      * OK, the file exists, use it!
      */

      if (buffer[0])
      {
        unlink(buffer);

	if (symlink(ppdname, buffer) && errno != EEXIST)
        {
          _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0);

	  return (HTTP_SERVER_ERROR);
	}
      }
      else
      {
        int		tries;		/* Number of tries */
        const char	*tmpdir;	/* TMPDIR environment variable */
	struct timeval	curtime;	/* Current time */

       /*
	* Previously we put root temporary files in the default CUPS temporary
	* directory under /var/spool/cups.  However, since the scheduler cleans
	* out temporary files there and runs independently of the user apps, we
	* don't want to use it unless specifically told to by cupsd.
	*/

	if ((tmpdir = getenv("TMPDIR")) == NULL)
#  ifdef __APPLE__
	  tmpdir = "/private/tmp";	/* /tmp is a symlink to /private/tmp */
#  else
          tmpdir = "/tmp";
#  endif /* __APPLE__ */

       /*
	* Make the temporary name using the specified directory...
	*/

	tries = 0;

	do
	{
	 /*
	  * Get the current time of day...
	  */

	  gettimeofday(&curtime, NULL);

	 /*
	  * Format a string using the hex time values...
	  */

	  snprintf(buffer, bufsize, "%s/%08lx%05lx", tmpdir,
		   (unsigned long)curtime.tv_sec,
		   (unsigned long)curtime.tv_usec);

	 /*
	  * Try to make a symlink...
	  */

	  if (!symlink(ppdname, buffer))
	    break;

	  tries ++;
	}
	while (tries < 1000);

        if (tries >= 1000)
	{
          _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0);

	  return (HTTP_SERVER_ERROR);
	}
      }

      if (*modtime >= ppdinfo.st_mtime)
        return (HTTP_NOT_MODIFIED);
      else
      {
        *modtime = ppdinfo.st_mtime;
	return (HTTP_OK);
      }
    }
  }
#endif /* !WIN32 */

 /*
  * Try finding a printer URI for this printer...
  */

  if (!http)
    if ((http = _cupsConnect()) == NULL)
      return (HTTP_SERVICE_UNAVAILABLE);

  if (!cups_get_printer_uri(http, name, hostname, sizeof(hostname), &port,
                            resource, sizeof(resource), 0))
    return (HTTP_NOT_FOUND);

  DEBUG_printf(("2cupsGetPPD3: Printer hostname=\"%s\", port=%d", hostname,
                port));

 /*
  * Remap local hostname to localhost...
  */

  httpGetHostname(NULL, localhost, sizeof(localhost));

  DEBUG_printf(("2cupsGetPPD3: Local hostname=\"%s\"", localhost));

  if (!_cups_strcasecmp(localhost, hostname))
    strcpy(hostname, "localhost");

 /*
  * Get the hostname and port number we are connected to...
  */

  httpGetHostname(http, http_hostname, sizeof(http_hostname));
  http_port = _httpAddrPort(http->hostaddr);

  DEBUG_printf(("2cupsGetPPD3: Connection hostname=\"%s\", port=%d",
                http_hostname, http_port));

 /*
  * Reconnect to the correct server as needed...
  */

  if (!_cups_strcasecmp(http_hostname, hostname) && port == http_port)
    http2 = http;
  else if ((http2 = httpConnectEncrypt(hostname, port,
                                       cupsEncryption())) == NULL)
  {
    DEBUG_puts("1cupsGetPPD3: Unable to connect to server");

    return (HTTP_SERVICE_UNAVAILABLE);
  }

 /*
  * Get a temp file...
  */

  if (buffer[0])
    fd = open(buffer, O_CREAT | O_TRUNC | O_WRONLY, 0600);
  else
    fd = cupsTempFd(tempfile, sizeof(tempfile));

  if (fd < 0)
  {
   /*
    * Can't open file; close the server connection and return NULL...
    */

    _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0);

    if (http2 != http)
      httpClose(http2);

    return (HTTP_SERVER_ERROR);
  }

 /*
  * And send a request to the HTTP server...
  */

  strlcat(resource, ".ppd", sizeof(resource));

  if (*modtime > 0)
    httpSetField(http2, HTTP_FIELD_IF_MODIFIED_SINCE,
                 httpGetDateString(*modtime));

  status = cupsGetFd(http2, resource, fd);

  close(fd);

 /*
  * See if we actually got the file or an error...
  */

  if (status == HTTP_OK)
  {
    *modtime = httpGetDateTime(httpGetField(http2, HTTP_FIELD_DATE));

    if (tempfile[0])
      strlcpy(buffer, tempfile, bufsize);
  }
  else if (status != HTTP_NOT_MODIFIED)
  {
    _cupsSetHTTPError(status);

    if (buffer[0])
      unlink(buffer);
    else if (tempfile[0])
      unlink(tempfile);
  }
  else if (tempfile[0])
    unlink(tempfile);

  if (http2 != http)
    httpClose(http2);

 /*
  * Return the PPD file...
  */

  DEBUG_printf(("1cupsGetPPD3: Returning status %d", status));

  return (status);
}
예제 #7
0
파일: util.c 프로젝트: AnotherView/cups
static int				/* O - 1 on success, 0 on failure */
cups_get_printer_uri(
    http_t     *http,			/* I - Connection to server */
    const char *name,			/* I - Name of printer or class */
    char       *host,			/* I - Hostname buffer */
    int        hostsize,		/* I - Size of hostname buffer */
    int        *port,			/* O - Port number */
    char       *resource,		/* I - Resource buffer */
    int        resourcesize,		/* I - Size of resource buffer */
    int        depth)			/* I - Depth of query */
{
  int		i;			/* Looping var */
  int		http_port;		/* Port number */
  http_t	*http2;			/* Alternate HTTP connection */
  ipp_t		*request,		/* IPP request */
		*response;		/* IPP response */
  ipp_attribute_t *attr;		/* Current attribute */
  char		uri[HTTP_MAX_URI],	/* printer-uri attribute */
		scheme[HTTP_MAX_URI],	/* Scheme name */
		username[HTTP_MAX_URI],	/* Username:password */
		classname[255],		/* Temporary class name */
		http_hostname[HTTP_MAX_HOST];
					/* Hostname associated with connection */
  static const char * const requested_attrs[] =
		{			/* Requested attributes */
		  "member-uris",
		  "printer-uri-supported",
		  "printer-type"
		};


  DEBUG_printf(("7cups_get_printer_uri(http=%p, name=\"%s\", host=%p, "
                "hostsize=%d, resource=%p, resourcesize=%d, depth=%d)",
		http, name, host, hostsize, resource, resourcesize, depth));

 /*
  * Setup the printer URI...
  */

  if (httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
                       "localhost", 0, "/printers/%s", name) != HTTP_URI_OK)
  {
    _cupsSetError(IPP_INTERNAL_ERROR, _("Unable to create printer-uri"), 1);

    *host     = '\0';
    *resource = '\0';

    return (0);
  }

  DEBUG_printf(("9cups_get_printer_uri: printer-uri=\"%s\"", uri));

 /*
  * Get the hostname and port number we are connected to...
  */

  httpGetHostname(http, http_hostname, sizeof(http_hostname));
  http_port = _httpAddrPort(http->hostaddr);

 /*
  * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
  * attributes:
  *
  *    attributes-charset
  *    attributes-natural-language
  *    printer-uri
  *    requested-attributes
  */

  request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);

  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
               NULL, uri);

  ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
                "requested-attributes",
		sizeof(requested_attrs) / sizeof(requested_attrs[0]),
		NULL, requested_attrs);

 /*
  * Do the request and get back a response...
  */

  if ((response = cupsDoRequest(http, request, "/")) != NULL)
  {
    if ((attr = ippFindAttribute(response, "member-uris", IPP_TAG_URI)) != NULL)
    {
     /*
      * Get the first actual printer name in the class...
      */

      for (i = 0; i < attr->num_values; i ++)
      {
	httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[i].string.text,
	                scheme, sizeof(scheme), username, sizeof(username),
			host, hostsize, port, resource, resourcesize);
	if (!strncmp(resource, "/printers/", 10))
	{
	 /*
	  * Found a printer!
	  */

          ippDelete(response);

	  return (1);
	}
      }

     /*
      * No printers in this class - try recursively looking for a printer,
      * but not more than 3 levels deep...
      */

      if (depth < 3)
      {
	for (i = 0; i < attr->num_values; i ++)
	{
	  httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[i].string.text,
	                  scheme, sizeof(scheme), username, sizeof(username),
			  host, hostsize, port, resource, resourcesize);
	  if (!strncmp(resource, "/classes/", 9))
	  {
	   /*
	    * Found a class!  Connect to the right server...
	    */

	    if (!_cups_strcasecmp(http_hostname, host) && *port == http_port)
	      http2 = http;
	    else if ((http2 = httpConnectEncrypt(host, *port,
						 cupsEncryption())) == NULL)
	    {
	      DEBUG_puts("8cups_get_printer_uri: Unable to connect to server");

	      continue;
	    }

           /*
	    * Look up printers on that server...
	    */

            strlcpy(classname, resource + 9, sizeof(classname));

            cups_get_printer_uri(http2, classname, host, hostsize, port,
	                         resource, resourcesize, depth + 1);

           /*
	    * Close the connection as needed...
	    */

	    if (http2 != http)
	      httpClose(http2);

            if (*host)
	      return (1);
	  }
	}
      }
    }
    else if ((attr = ippFindAttribute(response, "printer-uri-supported",
                                      IPP_TAG_URI)) != NULL)
    {
      httpSeparateURI(HTTP_URI_CODING_ALL,
                      _httpResolveURI(attr->values[0].string.text, uri,
		                      sizeof(uri), _HTTP_RESOLVE_DEFAULT,
				      NULL, NULL),
                      scheme, sizeof(scheme), username, sizeof(username),
		      host, hostsize, port, resource, resourcesize);
      ippDelete(response);

      if (!strncmp(resource, "/classes/", 9))
      {
        _cupsSetError(IPP_INTERNAL_ERROR,
	              _("No printer-uri found for class"), 1);

	*host     = '\0';
	*resource = '\0';

	return (0);
      }

      return (1);
    }

    ippDelete(response);
  }

  if (cupsLastError() != IPP_NOT_FOUND)
    _cupsSetError(IPP_INTERNAL_ERROR, _("No printer-uri found"), 1);

  *host     = '\0';
  *resource = '\0';

  return (0);
}