Example #1
0
ipp_attribute_t	* ippFindAttribute(ipp_t *ipp,const char *name,ipp_tag_t  type)
{
  if (!ipp || !name)
    return (NULL);

  ipp->current = NULL;

  return (ippFindNextAttribute(ipp, name, type));
}
Example #2
0
int				/* O - Exit status */
main(int  argc,			/* I - Number of command-line arguments */
     char *argv[])		/* I - Command-line arguments */
{
  _ippdata_t	data;		/* IPP buffer */
  ipp_uchar_t	buffer[8192];	/* Write buffer data */
  ipp_t		*cols[2],	/* Collections */
		*size;		/* media-size collection */
  ipp_t		*request;	/* Request */
  ipp_attribute_t *media_col,	/* media-col attribute */
		*media_size,	/* media-size attribute */
		*attr;		/* Other attribute */
  ipp_state_t	state;		/* State */
  size_t	length;		/* Length of data */
  cups_file_t	*fp;		/* File pointer */
  size_t	i;		/* Looping var */
  int		status;		/* Status of tests (0 = success, 1 = fail) */
#ifdef DEBUG
  const char	*name;		/* Option name */
#endif /* DEBUG */


  status = 0;

  if (argc == 1)
  {
   /*
    * Test request generation code...
    */

    printf("Create Sample Request: ");

    request = ippNew();
    request->request.op.version[0]   = 0x01;
    request->request.op.version[1]   = 0x01;
    request->request.op.operation_id = IPP_OP_PRINT_JOB;
    request->request.op.request_id   = 1;

    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
        	 "attributes-charset", NULL, "utf-8");
    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
        	 "attributes-natural-language", NULL, "en");
    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
        	 "printer-uri", NULL, "ipp://localhost/printers/foo");

    cols[0] = ippNew();
    size    = ippNew();
    ippAddInteger(size, IPP_TAG_ZERO, IPP_TAG_INTEGER, "x-dimension", 21590);
    ippAddInteger(size, IPP_TAG_ZERO, IPP_TAG_INTEGER, "y-dimension", 27940);
    ippAddCollection(cols[0], IPP_TAG_JOB, "media-size", size);
    ippDelete(size);
    ippAddString(cols[0], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-color", NULL,
                 "blue");
    ippAddString(cols[0], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-type", NULL,
                 "plain");

    cols[1] = ippNew();
    size    = ippNew();
    ippAddInteger(size, IPP_TAG_ZERO, IPP_TAG_INTEGER, "x-dimension", 21000);
    ippAddInteger(size, IPP_TAG_ZERO, IPP_TAG_INTEGER, "y-dimension", 29700);
    ippAddCollection(cols[1], IPP_TAG_JOB, "media-size", size);
    ippDelete(size);
    ippAddString(cols[1], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-color", NULL,
                 "plaid");
    ippAddString(cols[1], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-type", NULL,
		 "glossy");

    ippAddCollections(request, IPP_TAG_JOB, "media-col", 2,
                      (const ipp_t **)cols);
    ippDelete(cols[0]);
    ippDelete(cols[1]);

    length = ippLength(request);
    if (length != sizeof(collection))
    {
      printf("FAIL - wrong ippLength(), %d instead of %d bytes!\n",
             (int)length, (int)sizeof(collection));
      status = 1;
    }
    else
      puts("PASS");

   /*
    * Write test #1...
    */

    printf("Write Sample to Memory: ");

    data.wused   = 0;
    data.wsize   = sizeof(buffer);
    data.wbuffer = buffer;

    while ((state = ippWriteIO(&data, (ipp_iocb_t)write_cb, 1, NULL,
                               request)) != IPP_STATE_DATA)
      if (state == IPP_STATE_ERROR)
	break;

    if (state != IPP_STATE_DATA)
    {
      printf("FAIL - %d bytes written.\n", (int)data.wused);
      status = 1;
    }
    else if (data.wused != sizeof(collection))
    {
      printf("FAIL - wrote %d bytes, expected %d bytes!\n", (int)data.wused,
             (int)sizeof(collection));
      hex_dump("Bytes Written", data.wbuffer, data.wused);
      hex_dump("Baseline", collection, sizeof(collection));
      status = 1;
    }
    else if (memcmp(data.wbuffer, collection, data.wused))
    {
      for (i = 0; i < data.wused; i ++)
        if (data.wbuffer[i] != collection[i])
	  break;

      printf("FAIL - output does not match baseline at 0x%04x!\n", (unsigned)i);
      hex_dump("Bytes Written", data.wbuffer, data.wused);
      hex_dump("Baseline", collection, sizeof(collection));
      status = 1;
    }
    else
      puts("PASS");

    ippDelete(request);

   /*
    * Read the data back in and confirm...
    */

    printf("Read Sample from Memory: ");

    request     = ippNew();
    data.rpos = 0;

    while ((state = ippReadIO(&data, (ipp_iocb_t)read_cb, 1, NULL,
                              request)) != IPP_STATE_DATA)
      if (state == IPP_STATE_ERROR)
	break;

    length = ippLength(request);

    if (state != IPP_STATE_DATA)
    {
      printf("FAIL - %d bytes read.\n", (int)data.rpos);
      status = 1;
    }
    else if (data.rpos != data.wused)
    {
      printf("FAIL - read %d bytes, expected %d bytes!\n", (int)data.rpos,
             (int)data.wused);
      print_attributes(request, 8);
      status = 1;
    }
    else if (length != sizeof(collection))
    {
      printf("FAIL - wrong ippLength(), %d instead of %d bytes!\n",
             (int)length, (int)sizeof(collection));
      print_attributes(request, 8);
      status = 1;
    }
    else
      puts("PASS");

    fputs("ippFindAttribute(media-col): ", stdout);
    if ((media_col = ippFindAttribute(request, "media-col",
                                      IPP_TAG_BEGIN_COLLECTION)) == NULL)
    {
      if ((media_col = ippFindAttribute(request, "media-col",
                                        IPP_TAG_ZERO)) == NULL)
        puts("FAIL (not found)");
      else
        printf("FAIL (wrong type - %s)\n", ippTagString(media_col->value_tag));

      status = 1;
    }
    else if (media_col->num_values != 2)
    {
      printf("FAIL (wrong count - %d)\n", media_col->num_values);
      status = 1;
    }
    else
      puts("PASS");

    if (media_col)
    {
      fputs("ippFindAttribute(media-size 1): ", stdout);
      if ((media_size = ippFindAttribute(media_col->values[0].collection,
					 "media-size",
					 IPP_TAG_BEGIN_COLLECTION)) == NULL)
      {
	if ((media_size = ippFindAttribute(media_col->values[0].collection,
					   "media-col",
					   IPP_TAG_ZERO)) == NULL)
	  puts("FAIL (not found)");
	else
	  printf("FAIL (wrong type - %s)\n",
	         ippTagString(media_size->value_tag));

	status = 1;
      }
      else
      {
	if ((attr = ippFindAttribute(media_size->values[0].collection,
				     "x-dimension", IPP_TAG_INTEGER)) == NULL)
	{
	  if ((attr = ippFindAttribute(media_size->values[0].collection,
				       "x-dimension", IPP_TAG_ZERO)) == NULL)
	    puts("FAIL (missing x-dimension)");
	  else
	    printf("FAIL (wrong type for x-dimension - %s)\n",
		   ippTagString(attr->value_tag));

	  status = 1;
	}
	else if (attr->values[0].integer != 21590)
	{
	  printf("FAIL (wrong value for x-dimension - %d)\n",
		 attr->values[0].integer);
	  status = 1;
	}
	else if ((attr = ippFindAttribute(media_size->values[0].collection,
					  "y-dimension",
					  IPP_TAG_INTEGER)) == NULL)
	{
	  if ((attr = ippFindAttribute(media_size->values[0].collection,
				       "y-dimension", IPP_TAG_ZERO)) == NULL)
	    puts("FAIL (missing y-dimension)");
	  else
	    printf("FAIL (wrong type for y-dimension - %s)\n",
		   ippTagString(attr->value_tag));

	  status = 1;
	}
	else if (attr->values[0].integer != 27940)
	{
	  printf("FAIL (wrong value for y-dimension - %d)\n",
		 attr->values[0].integer);
	  status = 1;
	}
	else
	  puts("PASS");
      }

      fputs("ippFindAttribute(media-size 2): ", stdout);
      if ((media_size = ippFindAttribute(media_col->values[1].collection,
					 "media-size",
					 IPP_TAG_BEGIN_COLLECTION)) == NULL)
      {
	if ((media_size = ippFindAttribute(media_col->values[1].collection,
					   "media-col",
					   IPP_TAG_ZERO)) == NULL)
	  puts("FAIL (not found)");
	else
	  printf("FAIL (wrong type - %s)\n",
	         ippTagString(media_size->value_tag));

	status = 1;
      }
      else
      {
	if ((attr = ippFindAttribute(media_size->values[0].collection,
				     "x-dimension",
				     IPP_TAG_INTEGER)) == NULL)
	{
	  if ((attr = ippFindAttribute(media_size->values[0].collection,
				       "x-dimension", IPP_TAG_ZERO)) == NULL)
	    puts("FAIL (missing x-dimension)");
	  else
	    printf("FAIL (wrong type for x-dimension - %s)\n",
		   ippTagString(attr->value_tag));

	  status = 1;
	}
	else if (attr->values[0].integer != 21000)
	{
	  printf("FAIL (wrong value for x-dimension - %d)\n",
		 attr->values[0].integer);
	  status = 1;
	}
	else if ((attr = ippFindAttribute(media_size->values[0].collection,
					  "y-dimension",
					  IPP_TAG_INTEGER)) == NULL)
	{
	  if ((attr = ippFindAttribute(media_size->values[0].collection,
				       "y-dimension", IPP_TAG_ZERO)) == NULL)
	    puts("FAIL (missing y-dimension)");
	  else
	    printf("FAIL (wrong type for y-dimension - %s)\n",
		   ippTagString(attr->value_tag));

	  status = 1;
	}
	else if (attr->values[0].integer != 29700)
	{
	  printf("FAIL (wrong value for y-dimension - %d)\n",
		 attr->values[0].integer);
	  status = 1;
	}
	else
	  puts("PASS");
      }
    }

   /*
    * Test hierarchical find...
    */

    fputs("ippFindAttribute(media-col/media-size/x-dimension): ", stdout);
    if ((attr = ippFindAttribute(request, "media-col/media-size/x-dimension", IPP_TAG_INTEGER)) != NULL)
    {
      if (ippGetInteger(attr, 0) != 21590)
      {
        printf("FAIL (wrong value for x-dimension - %d)\n", ippGetInteger(attr, 0));
        status = 1;
      }
      else
        puts("PASS");
    }
    else
    {
      puts("FAIL (not found)");
      status = 1;
    }

    fputs("ippFindNextAttribute(media-col/media-size/x-dimension): ", stdout);
    if ((attr = ippFindNextAttribute(request, "media-col/media-size/x-dimension", IPP_TAG_INTEGER)) != NULL)
    {
      if (ippGetInteger(attr, 0) != 21000)
      {
        printf("FAIL (wrong value for x-dimension - %d)\n", ippGetInteger(attr, 0));
        status = 1;
      }
      else
        puts("PASS");
    }
    else
    {
      puts("FAIL (not found)");
      status = 1;
    }

    fputs("ippFindNextAttribute(media-col/media-size/x-dimension) again: ", stdout);
    if ((attr = ippFindNextAttribute(request, "media-col/media-size/x-dimension", IPP_TAG_INTEGER)) != NULL)
    {
      printf("FAIL (got %d, expected nothing)\n", ippGetInteger(attr, 0));
      status = 1;
    }
    else
      puts("PASS");

    ippDelete(request);

   /*
    * Read the mixed data and confirm we converted everything to rangeOfInteger
    * values...
    */

    printf("Read Mixed integer/rangeOfInteger from Memory: ");

    request = ippNew();
    data.rpos    = 0;
    data.wused   = sizeof(mixed);
    data.wsize   = sizeof(mixed);
    data.wbuffer = mixed;

    while ((state = ippReadIO(&data, (ipp_iocb_t)read_cb, 1, NULL,
                              request)) != IPP_STATE_DATA)
      if (state == IPP_STATE_ERROR)
	break;

    length = ippLength(request);

    if (state != IPP_STATE_DATA)
    {
      printf("FAIL - %d bytes read.\n", (int)data.rpos);
      status = 1;
    }
    else if (data.rpos != sizeof(mixed))
    {
      printf("FAIL - read %d bytes, expected %d bytes!\n", (int)data.rpos,
             (int)sizeof(mixed));
      print_attributes(request, 8);
      status = 1;
    }
    else if (length != (sizeof(mixed) + 4))
    {
      printf("FAIL - wrong ippLength(), %d instead of %d bytes!\n",
             (int)length, (int)sizeof(mixed) + 4);
      print_attributes(request, 8);
      status = 1;
    }
    else
      puts("PASS");

    fputs("ippFindAttribute(notify-lease-duration-supported): ", stdout);
    if ((attr = ippFindAttribute(request, "notify-lease-duration-supported",
                                 IPP_TAG_ZERO)) == NULL)
    {
      puts("FAIL (not found)");
      status = 1;
    }
    else if (attr->value_tag != IPP_TAG_RANGE)
    {
      printf("FAIL (wrong type - %s)\n", ippTagString(attr->value_tag));
      status = 1;
    }
    else if (attr->num_values != 2)
    {
      printf("FAIL (wrong count - %d)\n", attr->num_values);
      status = 1;
    }
    else if (attr->values[0].range.lower != 1 ||
             attr->values[0].range.upper != 1 ||
             attr->values[1].range.lower != 16 ||
             attr->values[1].range.upper != 32)
    {
      printf("FAIL (wrong values - %d,%d and %d,%d)\n",
             attr->values[0].range.lower,
             attr->values[0].range.upper,
             attr->values[1].range.lower,
             attr->values[1].range.upper);
      status = 1;
    }
    else
      puts("PASS");

    ippDelete(request);

#ifdef DEBUG
   /*
    * Test that private option array is sorted...
    */

    fputs("_ippCheckOptions: ", stdout);
    if ((name = _ippCheckOptions()) == NULL)
      puts("PASS");
    else
    {
      printf("FAIL (\"%s\" out of order)\n", name);
      status = 1;
    }
#endif /* DEBUG */

   /*
    * Test _ippFindOption() private API...
    */

    fputs("_ippFindOption(\"printer-type\"): ", stdout);
    if (_ippFindOption("printer-type"))
      puts("PASS");
    else
    {
      puts("FAIL");
      status = 1;
    }

   /*
    * Summarize...
    */

    putchar('\n');

    if (status)
      puts("Core IPP tests failed.");
    else
      puts("Core IPP tests passed.");
  }
  else
  {
   /*
    * Read IPP files...
    */

    for (i = 1; i < (size_t)argc; i ++)
    {
      if ((fp = cupsFileOpen(argv[i], "r")) == NULL)
      {
	printf("Unable to open \"%s\" - %s\n", argv[i], strerror(errno));
	status = 1;
	continue;
      }

      request = ippNew();
      while ((state = ippReadIO(fp, (ipp_iocb_t)cupsFileRead, 1, NULL,
                                request)) == IPP_STATE_ATTRIBUTE);

      if (state != IPP_STATE_DATA)
      {
	printf("Error reading IPP message from \"%s\"!\n", argv[i]);
	status = 1;
      }
      else
      {
	printf("\n%s:\n", argv[i]);
	print_attributes(request, 4);
      }

      ippDelete(request);
      cupsFileClose(fp);
    }
  }

  return (status);
}
int
main(int  argc,				/* I - Number of command-line arguments */
     char *argv[])			/* I - Command-line arguments */
{
  int		i;			/* Looping var */
  const char	*uri;			/* URI to use */
  int		num_events;		/* Number of events */
  const char	*events[100];		/* Events */
  int		subscription_id,	/* notify-subscription-id */
		sequence_number,	/* notify-sequence-number */
		interval;		/* Interval between polls */
  http_t	*http;			/* HTTP connection */
  ipp_t		*request,		/* IPP request */
		*response;		/* IPP response */
  ipp_attribute_t *attr;		/* Current attribute */
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
  struct sigaction action;		/* Actions for POSIX signals */
#endif /* HAVE_SIGACTION && !HAVE_SIGSET */


 /*
  * Parse command-line...
  */

  num_events = 0;
  uri        = NULL;

  for (i = 1; i < argc; i ++)
    if (!strcmp(argv[i], "-E"))
      cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
    else if (!strcmp(argv[i], "-e"))
    {
      i ++;
      if (i >= argc || num_events >= 100)
        usage();

      events[num_events] = argv[i];
      num_events ++;
    }
    else if (!strcmp(argv[i], "-h"))
    {
      i ++;
      if (i >= argc)
        usage();

      cupsSetServer(argv[i]);
    }
    else if (uri || strncmp(argv[i], "ipp://", 6))
      usage();
    else
      uri = argv[i];

  if (!uri)
    usage();

  if (num_events == 0)
  {
    events[0]  = "all";
    num_events = 1;
  }

 /*
  * Connect to the server...
  */

  if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
                                 cupsEncryption())) == NULL)
  {
    perror(cupsServer());
    return (1);
  }

 /*
  * Catch CTRL-C and SIGTERM...
  */

#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
  sigset(SIGINT, sigterm_handler);
  sigset(SIGTERM, sigterm_handler);
#elif defined(HAVE_SIGACTION)
  memset(&action, 0, sizeof(action));

  sigemptyset(&action.sa_mask);
  action.sa_handler = sigterm_handler;
  sigaction(SIGINT, &action, NULL);
  sigaction(SIGTERM, &action, NULL);
#else
  signal(SIGINT, sigterm_handler);
  signal(SIGTERM, sigterm_handler);
#endif /* HAVE_SIGSET */

 /*
  * Create the subscription...
  */

  if (strstr(uri, "/jobs/"))
  {
    request = ippNewRequest(IPP_CREATE_JOB_SUBSCRIPTION);
    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
  }
  else
  {
    request = ippNewRequest(IPP_CREATE_PRINTER_SUBSCRIPTION);
    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL,
                 uri);
  }

  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
               NULL, cupsUser());

  ippAddStrings(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD, "notify-events",
                num_events, NULL, events);
  ippAddString(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD,
               "notify-pull-method", NULL, "ippget");

  response = cupsDoRequest(http, request, uri);
  if (cupsLastError() >= IPP_BAD_REQUEST)
  {
    fprintf(stderr, "Create-%s-Subscription: %s\n",
            strstr(uri, "/jobs") ? "Job" : "Printer", cupsLastErrorString());
    ippDelete(response);
    httpClose(http);
    return (1);
  }

  if ((attr = ippFindAttribute(response, "notify-subscription-id",
                               IPP_TAG_INTEGER)) == NULL)
  {
    fputs("ERROR: No notify-subscription-id in response!\n", stderr);
    ippDelete(response);
    httpClose(http);
    return (1);
  }

  subscription_id = attr->values[0].integer;

  printf("Create-%s-Subscription: notify-subscription-id=%d\n",
         strstr(uri, "/jobs/") ? "Job" : "Printer", subscription_id);

  ippDelete(response);

 /*
  * Monitor for events...
  */

  sequence_number = 0;

  while (!terminate)
  {
   /*
    * Get the current events...
    */

    printf("\nGet-Notifications(%d,%d):", subscription_id, sequence_number);
    fflush(stdout);

    request = ippNewRequest(IPP_GET_NOTIFICATIONS);

    if (strstr(uri, "/jobs/"))
      ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
    else
      ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL,
                   uri);

    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
                 "requesting-user-name", NULL, cupsUser());

    ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
                  "notify-subscription-ids", subscription_id);
    if (sequence_number)
      ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
                    "notify-sequence-numbers", sequence_number + 1);

    response = cupsDoRequest(http, request, uri);

    printf(" %s\n", ippErrorString(cupsLastError()));

    if (cupsLastError() >= IPP_BAD_REQUEST)
      fprintf(stderr, "Get-Notifications: %s\n", cupsLastErrorString());
    else if (response)
    {
      print_attributes(response, 0);

      for (attr = ippFindAttribute(response, "notify-sequence-number",
                                   IPP_TAG_INTEGER);
           attr;
	   attr = ippFindNextAttribute(response, "notify-sequence-number",
	                               IPP_TAG_INTEGER))
        if (attr->values[0].integer > sequence_number)
	  sequence_number = attr->values[0].integer;
    }

    if ((attr = ippFindAttribute(response, "notify-get-interval",
                                 IPP_TAG_INTEGER)) != NULL &&
        attr->values[0].integer > 0)
      interval = attr->values[0].integer;
    else
      interval = 5;

    ippDelete(response);
    sleep(interval);
  }

 /*
  * Cancel the subscription...
  */

  printf("\nCancel-Subscription:");
  fflush(stdout);

  request = ippNewRequest(IPP_CANCEL_SUBSCRIPTION);

  if (strstr(uri, "/jobs/"))
    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
  else
    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL,
                 uri);

  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
               NULL, cupsUser());

  ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
                "notify-subscription-id", subscription_id);

  ippDelete(cupsDoRequest(http, request, uri));

  printf(" %s\n", ippErrorString(cupsLastError()));

  if (cupsLastError() >= IPP_BAD_REQUEST)
    fprintf(stderr, "Cancel-Subscription: %s\n", cupsLastErrorString());

 /*
  * Close the connection and return...
  */

  httpClose(http);

  return (0);
}
Example #4
0
void
cgiMoveJobs(http_t     *http,		/* I - Connection to server */
            const char *dest,		/* I - Destination or NULL */
            int        job_id)		/* I - Job ID or 0 for all */
{
  int		i;			/* Looping var */
  const char	*user;			/* Username */
  ipp_t		*request,		/* IPP request */
		*response;		/* IPP response */
  ipp_attribute_t *attr;		/* Current attribute */
  const char	*name;			/* Destination name */
  const char	*job_printer_uri;	/* JOB_PRINTER_URI form variable */
  char		current_dest[1024];	/* Current destination */


 /*
  * See who is logged in...
  */

  if ((user = getenv("REMOTE_USER")) == NULL)
    user = "******";

 /*
  * See if the user has already selected a new destination...
  */

  if ((job_printer_uri = cgiGetVariable("JOB_PRINTER_URI")) == NULL)
  {
   /*
    * Make sure necessary form variables are set...
    */

    if (job_id)
    {
      char	temp[255];		/* Temporary string */


      sprintf(temp, "%d", job_id);
      cgiSetVariable("JOB_ID", temp);
    }

    if (dest)
      cgiSetVariable("PRINTER_NAME", dest);

   /*
    * No new destination specified, show the user what the available
    * printers/classes are...
    */

    if (!dest)
    {
     /*
      * Get the current destination for job N...
      */

      char	job_uri[1024];		/* Job URI */


      request = ippNewRequest(IPP_GET_JOB_ATTRIBUTES);

      snprintf(job_uri, sizeof(job_uri), "ipp://localhost/jobs/%d", job_id);
      ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri",
                   NULL, job_uri);
      ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
                   "requested-attributes", NULL, "job-printer-uri");
      
      if ((response = cupsDoRequest(http, request, "/")) != NULL)
      {
        if ((attr = ippFindAttribute(response, "job-printer-uri",
	                             IPP_TAG_URI)) != NULL)
	{
	 /*
	  * Pull the name from the URI...
	  */

	  strlcpy(current_dest, strrchr(attr->values[0].string.text, '/') + 1,
	          sizeof(current_dest));
          dest = current_dest;
	}

        ippDelete(response);
      }

      if (!dest)
      {
       /*
        * Couldn't get the current destination...
	*/

        cgiStartHTML(cgiText(_("Move Job")));
	cgiShowIPPError(_("Unable to find destination for job!"));
	cgiEndHTML();
	return;
      }
    }

   /*
    * Get the list of available destinations...
    */

    request = ippNewRequest(CUPS_GET_PRINTERS);

    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
                 "requested-attributes", NULL, "printer-uri-supported");

    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
                 "requesting-user-name", NULL, user);

    if ((response = cupsDoRequest(http, request, "/")) != NULL)
    {
      for (i = 0, attr = ippFindAttribute(response, "printer-uri-supported",
                                          IPP_TAG_URI);
           attr;
	   attr = ippFindNextAttribute(response, "printer-uri-supported",
	                               IPP_TAG_URI))
      {
       /*
	* Pull the name from the URI...
	*/

	name = strrchr(attr->values[0].string.text, '/') + 1;

       /*
        * If the name is not the same as the current destination, add it!
	*/

        if (strcasecmp(name, dest))
	{
	  cgiSetArray("JOB_PRINTER_URI", i, attr->values[0].string.text);
	  cgiSetArray("JOB_PRINTER_NAME", i, name);
	  i ++;
	}
      }

      ippDelete(response);
    }

   /*
    * Show the form...
    */

    if (job_id)
      cgiStartHTML(cgiText(_("Move Job")));
    else
      cgiStartHTML(cgiText(_("Move All Jobs")));

    cgiCopyTemplateLang("job-move.tmpl");
  }
  else
  {
   /*
    * Try moving the job or jobs...
    */

    char	uri[1024],		/* Job/printer URI */
		resource[1024],		/* Post resource */
		refresh[1024];		/* Refresh URL */
    const char	*job_printer_name;	/* New printer name */


    request = ippNewRequest(CUPS_MOVE_JOB);

    if (job_id)
    {
     /*
      * Move 1 job...
      */

      snprintf(resource, sizeof(resource), "/jobs/%d", job_id);

      snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%d", job_id);
      ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri",
                   NULL, uri);
    }
    else
    {
     /*
      * Move all active jobs on a destination...
      */

      snprintf(resource, sizeof(resource), "/%s/%s",
               cgiGetVariable("SECTION"), dest);

      httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
                       "localhost", ippPort(), "/%s/%s",
		       cgiGetVariable("SECTION"), dest);
      ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
                   NULL, uri);
    }

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

    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
                 "requesting-user-name", NULL, user);

    ippDelete(cupsDoRequest(http, request, resource));

   /*
    * Show the results...
    */

    job_printer_name = strrchr(job_printer_uri, '/') + 1;

    if (cupsLastError() <= IPP_OK_CONFLICT)
    {
      const char *path = strstr(job_printer_uri, "/printers/");
      if (!path)
        path = strstr(job_printer_uri, "/classes/");

      if (path)
      {
        cgiFormEncode(uri, path, sizeof(uri));
        snprintf(refresh, sizeof(refresh), "2;URL=%s", uri);
	cgiSetVariable("refresh_page", refresh);
      }
    }

    if (job_id)
      cgiStartHTML(cgiText(_("Move Job")));
    else
      cgiStartHTML(cgiText(_("Move All Jobs")));

    if (cupsLastError() > IPP_OK_CONFLICT)
    {
      if (job_id)
	cgiShowIPPError(_("Unable to move job"));
      else
        cgiShowIPPError(_("Unable to move jobs"));
    }
    else
    {
      cgiSetVariable("JOB_PRINTER_NAME", job_printer_name);
      cgiCopyTemplateLang("job-moved.tmpl");
    }
  }

  cgiEndHTML();
}