get_subscriptions(cupsd_client_t  *con,	/* I - Client connection */
                  ipp_attribute_t *uri)	/* I - Printer/job URI */
{
  http_status_t		status;		/* Policy status */
  int			count;		/* Number of subscriptions */
  int			limit;		/* Limit */
  cupsd_subscription_t	*sub;		/* Subscription */
  cups_array_t		*ra;		/* Requested attributes array */
  ipp_attribute_t	*attr;		/* Attribute */
  cups_ptype_t		dtype;		/* Destination type (printer/class) */
  char			scheme[HTTP_MAX_URI],
					/* Scheme portion of URI */
			username[HTTP_MAX_URI],
					/* Username portion of URI */
			host[HTTP_MAX_URI],
					/* Host portion of URI */
			resource[HTTP_MAX_URI];
					/* Resource portion of URI */
  int			port;		/* Port portion of URI */
  cupsd_job_t		*job;		/* Job pointer */
  cupsd_printer_t	*printer;	/* Printer */
  cupsd_policy_t	*policy;	/* Policy */
  cups_array_t		*exclude;	/* Private attributes array */


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

 /*
  * Is the destination valid?
  */

  httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
                  sizeof(scheme), username, sizeof(username), host,
		  sizeof(host), &port, resource, sizeof(resource));

  if (!strcmp(resource, "/") ||
      (!strncmp(resource, "/jobs", 5) && strlen(resource) <= 6) ||
      (!strncmp(resource, "/printers", 9) && strlen(resource) <= 10) ||
      (!strncmp(resource, "/classes", 8) && strlen(resource) <= 9))
  {
    printer = NULL;
    job     = NULL;
  }
  else if (!strncmp(resource, "/jobs/", 6) && resource[6])
  {
    printer = NULL;
    job     = cupsdFindJob(atoi(resource + 6));

    if (!job)
    {
      send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."),
                      atoi(resource + 6));
      return;
    }
  }
  else 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;
  }
  else if ((attr = ippFindAttribute(con->request, "notify-job-id",
                                    IPP_TAG_INTEGER)) != NULL)
  {
    job = cupsdFindJob(attr->values[0].integer);

    if (!job)
    {
      send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."),
                      attr->values[0].integer);
      return;
    }
  }
  else
    job = NULL;

 /*
  * Check policy...
  */

  if (printer)
    policy = printer->op_policy_ptr;
  else
    policy = DefaultPolicyPtr;

  if ((status = cupsdCheckPolicy(policy, con, NULL)) != HTTP_OK)
  {
    send_http_error(con, status, printer);
    return;
  }

 /*
  * Expire subscriptions as needed...
  */

  cupsdExpireSubscriptions(NULL, NULL);

 /*
  * Copy the subscription attributes to the response using the
  * requested-attributes attribute that may be provided by the client.
  */

  ra = create_requested_array(con->request);

  if ((attr = ippFindAttribute(con->request, "limit",
                               IPP_TAG_INTEGER)) != NULL)
    limit = attr->values[0].integer;
  else
    limit = 0;

 /*
  * See if we only want to see subscriptions for a specific user...
  */

  if ((attr = ippFindAttribute(con->request, "my-subscriptions",
                               IPP_TAG_BOOLEAN)) != NULL &&
      attr->values[0].boolean)
    strlcpy(username, get_username(con), sizeof(username));
  else
    username[0] = '\0';

  for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions), count = 0;
       sub;
       sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
    if ((!printer || sub->dest == printer) && (!job || sub->job == job) &&
        (!username[0] || !_cups_strcasecmp(username, sub->owner)))
    {
      ippAddSeparator(con->response);

      exclude = cupsdGetPrivateAttrs(sub->dest ? sub->dest->op_policy_ptr :
						 policy, con, sub->dest,
						 sub->owner);

      copy_subscription_attrs(con, sub, ra, exclude);

      count ++;
      if (limit && count >= limit)
        break;
    }

  cupsArrayDelete(ra);

  if (count)
    con->response->request.status.status_code = IPP_OK;
  else
    send_ipp_status(con, IPP_NOT_FOUND, _("No subscriptions found."));
}