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