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