xref: /aosp_15_r20/external/libcups/scheduler/quotas.c (revision 5e7646d21f1134fb0638875d812ef646c12ab91e)
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