|
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 |
}
|