]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
503b54c9 | 2 | * Quota routines for the CUPS scheduler. |
ef416fc2 | 3 | * |
503b54c9 MS |
4 | * Copyright 2007-2011 by Apple Inc. |
5 | * Copyright 1997-2007 by Easy Software Products. | |
ef416fc2 | 6 | * |
e3101897 | 7 | * Licensed under Apache License v2.0. See the file "LICENSE" for more information. |
ef416fc2 | 8 | */ |
9 | ||
10 | /* | |
11 | * Include necessary headers... | |
12 | */ | |
13 | ||
14 | #include "cupsd.h" | |
15 | ||
16 | ||
17 | /* | |
18 | * Local functions... | |
19 | */ | |
20 | ||
e1d6a774 | 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); | |
3d8365b8 | 24 | |
25 | ||
26 | /* | |
27 | * 'cupsdFindQuota()' - Find a quota record. | |
28 | */ | |
29 | ||
30 | cupsd_quota_t * /* O - Quota data */ | |
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 */ | |
db1f069b | 37 | char *ptr; /* Pointer into username */ |
3d8365b8 | 38 | |
39 | ||
40 | if (!p || !username) | |
41 | return (NULL); | |
42 | ||
43 | strlcpy(match.username, username, sizeof(match.username)); | |
db1f069b MS |
44 | if ((ptr = strchr(match.username, '@')) != NULL) |
45 | *ptr = '\0'; /* Strip @domain/@KDC */ | |
3d8365b8 | 46 | |
47 | if ((q = (cupsd_quota_t *)cupsArrayFind(p->quotas, &match)) != NULL) | |
48 | return (q); | |
49 | else | |
50 | return (add_quota(p, username)); | |
51 | } | |
ef416fc2 | 52 | |
53 | ||
54 | /* | |
55 | * 'cupsdFreeQuotas()' - Free quotas for a printer. | |
56 | */ | |
57 | ||
58 | void | |
fa73b229 | 59 | cupsdFreeQuotas(cupsd_printer_t *p) /* I - Printer */ |
ef416fc2 | 60 | { |
fa73b229 | 61 | cupsd_quota_t *q; /* Current quota record */ |
62 | ||
63 | ||
ef416fc2 | 64 | if (!p) |
65 | return; | |
66 | ||
fa73b229 | 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); | |
ef416fc2 | 73 | |
fa73b229 | 74 | p->quotas = NULL; |
ef416fc2 | 75 | } |
76 | ||
77 | ||
78 | /* | |
79 | * 'cupsdUpdateQuota()' - Update quota data for the specified printer and user. | |
80 | */ | |
81 | ||
82 | cupsd_quota_t * /* O - Quota data */ | |
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 | ||
3d8365b8 | 101 | if ((q = cupsdFindQuota(p, username)) == NULL) |
ef416fc2 | 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 | { | |
dfd5680b MS |
131 | /* |
132 | * We only care about the current printer/class and user... | |
133 | */ | |
134 | ||
88f9aafc MS |
135 | if (_cups_strcasecmp(job->dest, p->name) != 0 || |
136 | _cups_strcasecmp(job->username, q->username) != 0) | |
ef416fc2 | 137 | continue; |
138 | ||
dfd5680b MS |
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 | ||
ef416fc2 | 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 | ||
ef416fc2 | 154 | if (attr->values[0].integer < curtime) |
155 | { | |
dfd5680b MS |
156 | /* |
157 | * This job is too old to count towards the quota, ignore it... | |
158 | */ | |
159 | ||
b9faaae1 MS |
160 | if (JobAutoPurge && !job->printer && job->state_value > IPP_JOB_STOPPED) |
161 | cupsdDeleteJob(job, CUPSD_JOB_PURGE); | |
ef416fc2 | 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 | ||
e1d6a774 | 182 | /* |
183 | * 'add_quota()' - Add a quota record for this printer and user. | |
184 | */ | |
185 | ||
07725fee | 186 | static cupsd_quota_t * /* O - Quota data */ |
e1d6a774 | 187 | add_quota(cupsd_printer_t *p, /* I - Printer */ |
188 | const char *username) /* I - User */ | |
189 | { | |
190 | cupsd_quota_t *q; /* New quota data */ | |
db1f069b | 191 | char *ptr; /* Pointer into username */ |
e1d6a774 | 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)); | |
db1f069b MS |
207 | if ((ptr = strchr(q->username, '@')) != NULL) |
208 | *ptr = '\0'; /* Strip @domain/@KDC */ | |
e1d6a774 | 209 | |
210 | cupsArrayAdd(p->quotas, q); | |
211 | ||
212 | return (q); | |
213 | } | |
214 | ||
215 | ||
ef416fc2 | 216 | /* |
fa73b229 | 217 | * 'compare_quotas()' - Compare two quota records... |
ef416fc2 | 218 | */ |
219 | ||
220 | static int /* O - Result of comparison */ | |
fa73b229 | 221 | compare_quotas(const cupsd_quota_t *q1, /* I - First quota record */ |
222 | const cupsd_quota_t *q2) /* I - Second quota record */ | |
ef416fc2 | 223 | { |
88f9aafc | 224 | return (_cups_strcasecmp(q1->username, q2->username)); |
ef416fc2 | 225 | } |