Blame scheduler/quotas.c

Packit 2fc92b
/*
Packit 2fc92b
 * Quota routines for the CUPS scheduler.
Packit 2fc92b
 *
Packit 2fc92b
 * Copyright 2007-2011 by Apple Inc.
Packit 2fc92b
 * Copyright 1997-2007 by Easy Software Products.
Packit 2fc92b
 *
Packit 2fc92b
 * These coded instructions, statements, and computer programs are the
Packit 2fc92b
 * property of Apple Inc. and are protected by Federal copyright
Packit 2fc92b
 * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
Packit 2fc92b
 * which should have been included with this file.  If this file is
Packit 2fc92b
 * missing or damaged, see the license at "http://www.cups.org/".
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * Include necessary headers...
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
#include "cupsd.h"
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * Local functions...
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static cupsd_quota_t	*add_quota(cupsd_printer_t *p, const char *username);
Packit 2fc92b
static int		compare_quotas(const cupsd_quota_t *q1,
Packit 2fc92b
			               const cupsd_quota_t *q2);
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'cupsdFindQuota()' - Find a quota record.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
cupsd_quota_t *				/* O - Quota data */
Packit 2fc92b
cupsdFindQuota(
Packit 2fc92b
    cupsd_printer_t *p,			/* I - Printer */
Packit 2fc92b
    const char      *username)		/* I - User */
Packit 2fc92b
{
Packit 2fc92b
  cupsd_quota_t	*q,			/* Quota data pointer */
Packit 2fc92b
		match;			/* Search data */
Packit 2fc92b
  char		*ptr;			/* Pointer into username */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  if (!p || !username)
Packit 2fc92b
    return (NULL);
Packit 2fc92b
Packit 2fc92b
  strlcpy(match.username, username, sizeof(match.username));
Packit 2fc92b
  if ((ptr = strchr(match.username, '@')) != NULL)
Packit 2fc92b
    *ptr = '\0';			/* Strip @domain/@KDC */
Packit 2fc92b
Packit 2fc92b
  if ((q = (cupsd_quota_t *)cupsArrayFind(p->quotas, &match)) != NULL)
Packit 2fc92b
    return (q);
Packit 2fc92b
  else
Packit 2fc92b
    return (add_quota(p, username));
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'cupsdFreeQuotas()' - Free quotas for a printer.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
void
Packit 2fc92b
cupsdFreeQuotas(cupsd_printer_t *p)	/* I - Printer */
Packit 2fc92b
{
Packit 2fc92b
  cupsd_quota_t *q;			/* Current quota record */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  if (!p)
Packit 2fc92b
    return;
Packit 2fc92b
Packit 2fc92b
  for (q = (cupsd_quota_t *)cupsArrayFirst(p->quotas);
Packit 2fc92b
       q;
Packit 2fc92b
       q = (cupsd_quota_t *)cupsArrayNext(p->quotas))
Packit 2fc92b
    free(q);
Packit 2fc92b
Packit 2fc92b
  cupsArrayDelete(p->quotas);
Packit 2fc92b
Packit 2fc92b
  p->quotas = NULL;
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'cupsdUpdateQuota()' - Update quota data for the specified printer and user.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
cupsd_quota_t *				/* O - Quota data */
Packit 2fc92b
cupsdUpdateQuota(
Packit 2fc92b
    cupsd_printer_t *p,			/* I - Printer */
Packit 2fc92b
    const char      *username,		/* I - User */
Packit 2fc92b
    int             pages,		/* I - Number of pages */
Packit 2fc92b
    int             k)			/* I - Number of kilobytes */
Packit 2fc92b
{
Packit 2fc92b
  cupsd_quota_t		*q;		/* Quota data */
Packit 2fc92b
  cupsd_job_t		*job;		/* Current job */
Packit 2fc92b
  time_t		curtime;	/* Current time */
Packit 2fc92b
  ipp_attribute_t	*attr;		/* Job attribute */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  if (!p || !username)
Packit 2fc92b
    return (NULL);
Packit 2fc92b
Packit 2fc92b
  if (!p->k_limit && !p->page_limit)
Packit 2fc92b
    return (NULL);
Packit 2fc92b
Packit 2fc92b
  if ((q = cupsdFindQuota(p, username)) == NULL)
Packit 2fc92b
    return (NULL);
Packit 2fc92b
Packit 2fc92b
  cupsdLogMessage(CUPSD_LOG_DEBUG,
Packit 2fc92b
                  "cupsdUpdateQuota: p=%s username=%s pages=%d k=%d",
Packit 2fc92b
                  p->name, username, pages, k);
Packit 2fc92b
Packit 2fc92b
  curtime = time(NULL);
Packit 2fc92b
Packit 2fc92b
  if (curtime < q->next_update)
Packit 2fc92b
  {
Packit 2fc92b
    q->page_count += pages;
Packit 2fc92b
    q->k_count    += k;
Packit 2fc92b
Packit 2fc92b
    return (q);
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
  if (p->quota_period)
Packit 2fc92b
    curtime -= p->quota_period;
Packit 2fc92b
  else
Packit 2fc92b
    curtime = 0;
Packit 2fc92b
Packit 2fc92b
  q->next_update = 0;
Packit 2fc92b
  q->page_count  = 0;
Packit 2fc92b
  q->k_count     = 0;
Packit 2fc92b
Packit 2fc92b
  for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
Packit 2fc92b
       job;
Packit 2fc92b
       job = (cupsd_job_t *)cupsArrayNext(Jobs))
Packit 2fc92b
  {
Packit 2fc92b
   /*
Packit 2fc92b
    * We only care about the current printer/class and user...
Packit 2fc92b
    */
Packit 2fc92b
Packit 2fc92b
    if (_cups_strcasecmp(job->dest, p->name) != 0 ||
Packit 2fc92b
        _cups_strcasecmp(job->username, q->username) != 0)
Packit 2fc92b
      continue;
Packit 2fc92b
Packit 2fc92b
   /*
Packit 2fc92b
    * Make sure attributes are loaded; we always call cupsdLoadJob() to ensure
Packit 2fc92b
    * the access_time member is updated so the job isn't unloaded right away...
Packit 2fc92b
    */
Packit 2fc92b
Packit 2fc92b
    if (!cupsdLoadJob(job))
Packit 2fc92b
      continue;
Packit 2fc92b
Packit 2fc92b
    if ((attr = ippFindAttribute(job->attrs, "time-at-completion",
Packit 2fc92b
                                 IPP_TAG_INTEGER)) == NULL)
Packit 2fc92b
      if ((attr = ippFindAttribute(job->attrs, "time-at-processing",
Packit 2fc92b
                                   IPP_TAG_INTEGER)) == NULL)
Packit 2fc92b
        attr = ippFindAttribute(job->attrs, "time-at-creation",
Packit 2fc92b
                                IPP_TAG_INTEGER);
Packit 2fc92b
Packit 2fc92b
    if (attr->values[0].integer < curtime)
Packit 2fc92b
    {
Packit 2fc92b
     /*
Packit 2fc92b
      * This job is too old to count towards the quota, ignore it...
Packit 2fc92b
      */
Packit 2fc92b
Packit 2fc92b
      if (JobAutoPurge && !job->printer && job->state_value > IPP_JOB_STOPPED)
Packit 2fc92b
        cupsdDeleteJob(job, CUPSD_JOB_PURGE);
Packit 2fc92b
Packit 2fc92b
      continue;
Packit 2fc92b
    }
Packit 2fc92b
Packit 2fc92b
    if (q->next_update == 0)
Packit 2fc92b
      q->next_update = attr->values[0].integer + p->quota_period;
Packit 2fc92b
Packit 2fc92b
    if ((attr = ippFindAttribute(job->attrs, "job-media-sheets-completed",
Packit 2fc92b
                                 IPP_TAG_INTEGER)) != NULL)
Packit 2fc92b
      q->page_count += attr->values[0].integer;
Packit 2fc92b
Packit 2fc92b
    if ((attr = ippFindAttribute(job->attrs, "job-k-octets",
Packit 2fc92b
                                 IPP_TAG_INTEGER)) != NULL)
Packit 2fc92b
      q->k_count += attr->values[0].integer;
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
  return (q);
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'add_quota()' - Add a quota record for this printer and user.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static cupsd_quota_t *			/* O - Quota data */
Packit 2fc92b
add_quota(cupsd_printer_t *p,		/* I - Printer */
Packit 2fc92b
          const char      *username)	/* I - User */
Packit 2fc92b
{
Packit 2fc92b
  cupsd_quota_t	*q;			/* New quota data */
Packit 2fc92b
  char		*ptr;			/* Pointer into username */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  if (!p || !username)
Packit 2fc92b
    return (NULL);
Packit 2fc92b
Packit 2fc92b
  if (!p->quotas)
Packit 2fc92b
    p->quotas = cupsArrayNew((cups_array_func_t)compare_quotas, NULL);
Packit 2fc92b
Packit 2fc92b
  if (!p->quotas)
Packit 2fc92b
    return (NULL);
Packit 2fc92b
Packit 2fc92b
  if ((q = calloc(1, sizeof(cupsd_quota_t))) == NULL)
Packit 2fc92b
    return (NULL);
Packit 2fc92b
Packit 2fc92b
  strlcpy(q->username, username, sizeof(q->username));
Packit 2fc92b
  if ((ptr = strchr(q->username, '@')) != NULL)
Packit 2fc92b
    *ptr = '\0';			/* Strip @domain/@KDC */
Packit 2fc92b
Packit 2fc92b
  cupsArrayAdd(p->quotas, q);
Packit 2fc92b
Packit 2fc92b
  return (q);
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'compare_quotas()' - Compare two quota records...
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static int				/* O - Result of comparison */
Packit 2fc92b
compare_quotas(const cupsd_quota_t *q1,	/* I - First quota record */
Packit 2fc92b
               const cupsd_quota_t *q2)	/* I - Second quota record */
Packit 2fc92b
{
Packit 2fc92b
  return (_cups_strcasecmp(q1->username, q2->username));
Packit 2fc92b
}