1/* 2 * "$Id: quotas.c 11093 2013-07-03 20:48:42Z msweet $" 3 * 4 * Quota routines for the CUPS scheduler. 5 * 6 * Copyright 2007-2011 by Apple Inc. 7 * Copyright 1997-2007 by Easy Software Products. 8 * 9 * These coded instructions, statements, and computer programs are the 10 * property of Apple Inc. and are protected by Federal copyright 11 * law. Distribution and use rights are outlined in the file "LICENSE.txt" 12 * which should have been included with this file. If this file is 13 * file is missing or damaged, see the license at "http://www.cups.org/". 14 * 15 * Contents: 16 * 17 * cupsdFindQuota() - Find a quota record. 18 * cupsdFreeQuotas() - Free quotas for a printer. 19 * cupsdUpdateQuota() - Update quota data for the specified printer and user. 20 * add_quota() - Add a quota record for this printer and user. 21 * compare_quotas() - Compare two quota records... 22 */ 23 24/* 25 * Include necessary headers... 26 */ 27 28#include "cupsd.h" 29 30 31/* 32 * Local functions... 33 */ 34 35static cupsd_quota_t *add_quota(cupsd_printer_t *p, const char *username); 36static int compare_quotas(const cupsd_quota_t *q1, 37 const cupsd_quota_t *q2); 38 39 40/* 41 * 'cupsdFindQuota()' - Find a quota record. 42 */ 43 44cupsd_quota_t * /* O - Quota data */ 45cupsdFindQuota( 46 cupsd_printer_t *p, /* I - Printer */ 47 const char *username) /* I - User */ 48{ 49 cupsd_quota_t *q, /* Quota data pointer */ 50 match; /* Search data */ 51 char *ptr; /* Pointer into username */ 52 53 54 if (!p || !username) 55 return (NULL); 56 57 strlcpy(match.username, username, sizeof(match.username)); 58 if ((ptr = strchr(match.username, '@')) != NULL) 59 *ptr = '\0'; /* Strip @domain/@KDC */ 60 61 if ((q = (cupsd_quota_t *)cupsArrayFind(p->quotas, &match)) != NULL) 62 return (q); 63 else 64 return (add_quota(p, username)); 65} 66 67 68/* 69 * 'cupsdFreeQuotas()' - Free quotas for a printer. 70 */ 71 72void 73cupsdFreeQuotas(cupsd_printer_t *p) /* I - Printer */ 74{ 75 cupsd_quota_t *q; /* Current quota record */ 76 77 78 if (!p) 79 return; 80 81 for (q = (cupsd_quota_t *)cupsArrayFirst(p->quotas); 82 q; 83 q = (cupsd_quota_t *)cupsArrayNext(p->quotas)) 84 free(q); 85 86 cupsArrayDelete(p->quotas); 87 88 p->quotas = NULL; 89} 90 91 92/* 93 * 'cupsdUpdateQuota()' - Update quota data for the specified printer and user. 94 */ 95 96cupsd_quota_t * /* O - Quota data */ 97cupsdUpdateQuota( 98 cupsd_printer_t *p, /* I - Printer */ 99 const char *username, /* I - User */ 100 int pages, /* I - Number of pages */ 101 int k) /* I - Number of kilobytes */ 102{ 103 cupsd_quota_t *q; /* Quota data */ 104 cupsd_job_t *job; /* Current job */ 105 time_t curtime; /* Current time */ 106 ipp_attribute_t *attr; /* Job attribute */ 107 108 109 if (!p || !username) 110 return (NULL); 111 112 if (!p->k_limit && !p->page_limit) 113 return (NULL); 114 115 if ((q = cupsdFindQuota(p, username)) == NULL) 116 return (NULL); 117 118 cupsdLogMessage(CUPSD_LOG_DEBUG, 119 "cupsdUpdateQuota: p=%s username=%s pages=%d k=%d", 120 p->name, username, pages, k); 121 122 curtime = time(NULL); 123 124 if (curtime < q->next_update) 125 { 126 q->page_count += pages; 127 q->k_count += k; 128 129 return (q); 130 } 131 132 if (p->quota_period) 133 curtime -= p->quota_period; 134 else 135 curtime = 0; 136 137 q->next_update = 0; 138 q->page_count = 0; 139 q->k_count = 0; 140 141 for (job = (cupsd_job_t *)cupsArrayFirst(Jobs); 142 job; 143 job = (cupsd_job_t *)cupsArrayNext(Jobs)) 144 { 145 /* 146 * We only care about the current printer/class and user... 147 */ 148 149 if (_cups_strcasecmp(job->dest, p->name) != 0 || 150 _cups_strcasecmp(job->username, q->username) != 0) 151 continue; 152 153 /* 154 * Make sure attributes are loaded; we always call cupsdLoadJob() to ensure 155 * the access_time member is updated so the job isn't unloaded right away... 156 */ 157 158 if (!cupsdLoadJob(job)) 159 continue; 160 161 if ((attr = ippFindAttribute(job->attrs, "time-at-completion", 162 IPP_TAG_INTEGER)) == NULL) 163 if ((attr = ippFindAttribute(job->attrs, "time-at-processing", 164 IPP_TAG_INTEGER)) == NULL) 165 attr = ippFindAttribute(job->attrs, "time-at-creation", 166 IPP_TAG_INTEGER); 167 168 if (attr->values[0].integer < curtime) 169 { 170 /* 171 * This job is too old to count towards the quota, ignore it... 172 */ 173 174 if (JobAutoPurge && !job->printer && job->state_value > IPP_JOB_STOPPED) 175 cupsdDeleteJob(job, CUPSD_JOB_PURGE); 176 177 continue; 178 } 179 180 if (q->next_update == 0) 181 q->next_update = attr->values[0].integer + p->quota_period; 182 183 if ((attr = ippFindAttribute(job->attrs, "job-media-sheets-completed", 184 IPP_TAG_INTEGER)) != NULL) 185 q->page_count += attr->values[0].integer; 186 187 if ((attr = ippFindAttribute(job->attrs, "job-k-octets", 188 IPP_TAG_INTEGER)) != NULL) 189 q->k_count += attr->values[0].integer; 190 } 191 192 return (q); 193} 194 195 196/* 197 * 'add_quota()' - Add a quota record for this printer and user. 198 */ 199 200static cupsd_quota_t * /* O - Quota data */ 201add_quota(cupsd_printer_t *p, /* I - Printer */ 202 const char *username) /* I - User */ 203{ 204 cupsd_quota_t *q; /* New quota data */ 205 char *ptr; /* Pointer into username */ 206 207 208 if (!p || !username) 209 return (NULL); 210 211 if (!p->quotas) 212 p->quotas = cupsArrayNew((cups_array_func_t)compare_quotas, NULL); 213 214 if (!p->quotas) 215 return (NULL); 216 217 if ((q = calloc(1, sizeof(cupsd_quota_t))) == NULL) 218 return (NULL); 219 220 strlcpy(q->username, username, sizeof(q->username)); 221 if ((ptr = strchr(q->username, '@')) != NULL) 222 *ptr = '\0'; /* Strip @domain/@KDC */ 223 224 cupsArrayAdd(p->quotas, q); 225 226 return (q); 227} 228 229 230/* 231 * 'compare_quotas()' - Compare two quota records... 232 */ 233 234static int /* O - Result of comparison */ 235compare_quotas(const cupsd_quota_t *q1, /* I - First quota record */ 236 const cupsd_quota_t *q2) /* I - Second quota record */ 237{ 238 return (_cups_strcasecmp(q1->username, q2->username)); 239} 240 241 242/* 243 * End of "$Id: quotas.c 11093 2013-07-03 20:48:42Z msweet $". 244 */ 245