5051756c520689d980d8dda28255e86a7ebb12a2
[platform/upstream/cups.git] / scheduler / quotas.c
1 /*
2  * "$Id: quotas.c 9793 2011-05-20 03:49:49Z mike $"
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
35 static cupsd_quota_t    *add_quota(cupsd_printer_t *p, const char *username);
36 static 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
44 cupsd_quota_t *                         /* O - Quota data */
45 cupsdFindQuota(
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
72 void
73 cupsdFreeQuotas(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
96 cupsd_quota_t *                         /* O - Quota data */
97 cupsdUpdateQuota(
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
200 static cupsd_quota_t *                  /* O - Quota data */
201 add_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
234 static int                              /* O - Result of comparison */
235 compare_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 9793 2011-05-20 03:49:49Z mike $".
244  */