validate_job(cupsd_client_t  *con,	/* I - Client connection */
	     ipp_attribute_t *uri)	/* I - Printer URI */
{
  http_status_t		status;		/* Policy status */
  ipp_attribute_t	*attr;		/* Current attribute */
#ifdef HAVE_SSL
  ipp_attribute_t	*auth_info;	/* auth-info attribute */
#endif /* HAVE_SSL */
  ipp_attribute_t	*format,	/* Document-format attribute */
			*name;		/* Job-name attribute */
  cups_ptype_t		dtype;		/* Destination type (printer/class) */
  char			super[MIME_MAX_SUPER],
					/* Supertype of file */
			type[MIME_MAX_TYPE];
					/* Subtype of file */
  cupsd_printer_t	*printer;	/* Printer */


  cupsdLogMessage(CUPSD_LOG_DEBUG2, "validate_job(%p[%d], %s)", con,
                  con->number, uri->values[0].string.text);

 /*
  * OK, see if the client is sending the document compressed - CUPS
  * doesn't support compression yet...
  */

  if ((attr = ippFindAttribute(con->request, "compression",
                               IPP_TAG_KEYWORD)) != NULL)
  {
    if (strcmp(attr->values[0].string.text, "none")
#ifdef HAVE_LIBZ
        && strcmp(attr->values[0].string.text, "gzip")
#endif /* HAVE_LIBZ */
      )
    {
      send_ipp_status(con, IPP_ATTRIBUTES,
                      _("Unsupported 'compression' value \"%s\"."),
        	      attr->values[0].string.text);
      ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD,
	           "compression", NULL, attr->values[0].string.text);
      return;
    }
  }

 /*
  * Is it a format we support?
  */

  if ((format = ippFindAttribute(con->request, "document-format",
                                 IPP_TAG_MIMETYPE)) != NULL)
  {
    if (sscanf(format->values[0].string.text, "%15[^/]/%255[^;]",
               super, type) != 2)
    {
      send_ipp_status(con, IPP_BAD_REQUEST,
                      _("Bad 'document-format' value \"%s\"."),
		      format->values[0].string.text);
      return;
    }

    if ((strcmp(super, "application") || strcmp(type, "octet-stream")) &&
	!mimeType(MimeDatabase, super, type))
    {
      cupsdLogMessage(CUPSD_LOG_INFO,
                      "Hint: Do you have the raw file printing rules enabled?");
      send_ipp_status(con, IPP_DOCUMENT_FORMAT,
                      _("Unsupported 'document-format' value \"%s\"."),
		      format->values[0].string.text);
      ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE,
                   "document-format", NULL, format->values[0].string.text);
      return;
    }
  }

 /*
  * Is the job-name valid?
  */

  if ((name = ippFindAttribute(con->request, "job-name", IPP_TAG_ZERO)) != NULL)
  {
    int bad_name = 0;			/* Is the job-name value bad? */

    if ((name->value_tag != IPP_TAG_NAME && name->value_tag != IPP_TAG_NAMELANG) ||
        name->num_values != 1)
    {
      bad_name = 1;
    }
    else
    {
     /*
      * Validate that job-name conforms to RFC 5198 (Network Unicode) and
      * IPP Everywhere requirements for "name" values...
      */

      const unsigned char *nameptr;	/* Pointer into "job-name" attribute */

      for (nameptr = (unsigned char *)name->values[0].string.text;
           *nameptr;
           nameptr ++)
      {
        if (*nameptr < ' ' && *nameptr != '\t')
          break;
        else if (*nameptr == 0x7f)
          break;
        else if ((*nameptr & 0xe0) == 0xc0)
        {
          if ((nameptr[1] & 0xc0) != 0x80)
            break;

          nameptr ++;
        }
        else if ((*nameptr & 0xf0) == 0xe0)
        {
          if ((nameptr[1] & 0xc0) != 0x80 ||
              (nameptr[2] & 0xc0) != 0x80)
	    break;

	  nameptr += 2;
	}
        else if ((*nameptr & 0xf8) == 0xf0)
        {
          if ((nameptr[1] & 0xc0) != 0x80 ||
	      (nameptr[2] & 0xc0) != 0x80 ||
	      (nameptr[3] & 0xc0) != 0x80)
	    break;

	  nameptr += 3;
	}
        else if (*nameptr & 0x80)
          break;
      }

      if (*nameptr)
        bad_name = 1;
    }

    if (bad_name)
    {
      if (StrictConformance)
      {
	send_ipp_status(con, IPP_ATTRIBUTES,
	                _("Unsupported 'job-name' value."));
	ippCopyAttribute(con->response, name, 0);
	return;
      }
      else
      {
        cupsdLogMessage(CUPSD_LOG_WARN,
                        "Unsupported 'job-name' value, deleting from request.");
        ippDeleteAttribute(con->request, name);
      }
    }
  }

 /*
  * Is the destination valid?
  */

  if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
  {
   /*
    * Bad URI...
    */

    send_ipp_status(con, IPP_NOT_FOUND,
                    _("The printer or class does not exist."));
    return;
  }

 /*
  * Check policy...
  */

#ifdef HAVE_SSL
  auth_info = ippFindAttribute(con->request, "auth-info", IPP_TAG_TEXT);
#endif /* HAVE_SSL */

  if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
  {
    send_http_error(con, status, printer);
    return;
  }
  else if (printer->num_auth_info_required == 1 &&
           !strcmp(printer->auth_info_required[0], "negotiate") &&
           !con->username[0])
  {
    send_http_error(con, HTTP_UNAUTHORIZED, printer);
    return;
  }
#ifdef HAVE_SSL
  else if (auth_info && !con->http->tls &&
           !httpAddrLocalhost(con->http->hostaddr))
  {
   /*
    * Require encryption of auth-info over non-local connections...
    */

    send_http_error(con, HTTP_UPGRADE_REQUIRED, printer);
    return;
  }
#endif /* HAVE_SSL */

 /*
  * Everything was ok, so return OK status...
  */

  con->response->request.status.status_code = IPP_OK;
}