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