]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/cups-polld.c
Load cups into easysw/current.
[thirdparty/cups.git] / scheduler / cups-polld.c
1 /*
2 * "$Id: cups-polld.c 5753 2006-07-18 19:53:24Z mike $"
3 *
4 * Polling daemon for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
26 * main() - Open sockets and poll until we are killed...
27 * dequote() - Remote quotes from a string.
28 * poll_server() - Poll the server for the given set of printers or classes.
29 */
30
31 /*
32 * Include necessary headers...
33 */
34
35 #include <cups/http-private.h>
36 #include <cups/cups.h>
37 #include <stdlib.h>
38 #include <errno.h>
39 #include <cups/language.h>
40 #include <cups/string.h>
41
42
43 /*
44 * Local functions...
45 */
46
47 static char *dequote(char *d, const char *s, int dlen);
48 static int poll_server(http_t *http, int sock, int port, int interval,
49 const char *prefix);
50
51
52 /*
53 * 'main()' - Open sockets and poll until we are killed...
54 */
55
56 int /* O - Exit status */
57 main(int argc, /* I - Number of command-line args */
58 char *argv[]) /* I - Command-line arguments */
59 {
60 http_t *http; /* HTTP connection */
61 int interval; /* Polling interval */
62 int sock; /* Browser sock */
63 int port; /* Browser port */
64 int val; /* Socket option value */
65 int seconds, /* Seconds left from poll */
66 remain; /* Total remaining time to sleep */
67 char prefix[1024]; /* Prefix for log messages */
68
69
70 /*
71 * Don't buffer log messages...
72 */
73
74 setbuf(stderr, NULL);
75
76 /*
77 * The command-line must contain the following:
78 *
79 * cups-polld server server-port interval port
80 */
81
82 if (argc != 5)
83 {
84 fputs("Usage: cups-polld server server-port interval port\n", stderr);
85 return (1);
86 }
87
88 interval = atoi(argv[3]);
89 port = atoi(argv[4]);
90
91 if (interval < 2)
92 interval = 2;
93
94 snprintf(prefix, sizeof(prefix), "[cups-polld %s:%d]", argv[1], atoi(argv[2]));
95
96 /*
97 * Open a broadcast socket...
98 */
99
100 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
101 {
102 fprintf(stderr, "ERROR: %s Unable to open broadcast socket: %s\n", prefix,
103 strerror(errno));
104 return (1);
105 }
106
107 /*
108 * Set the "broadcast" flag...
109 */
110
111 val = 1;
112 if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
113 {
114 fprintf(stderr, "ERROR: %s Unable to put socket in broadcast mode: %s\n",
115 prefix, strerror(errno));
116
117 close(sock);
118 return (1);
119 }
120
121 /*
122 * Open a connection to the server...
123 */
124
125 while ((http = httpConnectEncrypt(argv[1], atoi(argv[2]),
126 cupsEncryption())) == NULL)
127 {
128 fprintf(stderr, "ERROR: %s Unable to connect to %s on port %s: %s\n",
129 prefix, argv[1], argv[2],
130 h_errno ? hstrerror(h_errno) : strerror(errno));
131 sleep(interval);
132 }
133
134 /*
135 * Loop forever, asking for available printers and classes...
136 */
137
138 for (;;)
139 {
140 /*
141 * Get the printers and classes...
142 */
143
144 remain = interval;
145
146 if ((seconds = poll_server(http, sock, port, interval, prefix)) > 0)
147 remain -= seconds;
148
149 /*
150 * Sleep for any remaining time...
151 */
152
153 if (remain > 0)
154 sleep(remain);
155 }
156 }
157
158
159 /*
160 * 'dequote()' - Remote quotes from a string.
161 */
162
163 static char * /* O - Dequoted string */
164 dequote(char *d, /* I - Destination string */
165 const char *s, /* I - Source string */
166 int dlen) /* I - Destination length */
167 {
168 char *dptr; /* Pointer into destination */
169
170
171 if (s)
172 {
173 for (dptr = d, dlen --; *s && dlen > 0; s ++)
174 if (*s != '\"')
175 {
176 *dptr++ = *s;
177 dlen --;
178 }
179
180 *dptr = '\0';
181 }
182 else
183 *d = '\0';
184
185 return (d);
186 }
187
188
189 /*
190 * 'poll_server()' - Poll the server for the given set of printers or classes.
191 */
192
193 static int /* O - Number of seconds or -1 on error */
194 poll_server(http_t *http, /* I - HTTP connection */
195 int sock, /* I - Broadcast sock */
196 int port, /* I - Broadcast port */
197 int interval, /* I - Polling interval */
198 const char *prefix) /* I - Prefix for log messages */
199 {
200 int seconds; /* Number of seconds */
201 int count, /* Current number of printers/classes */
202 max_count; /* Maximum printers/classes per second */
203 ipp_t *request, /* Request data */
204 *response; /* Response data */
205 ipp_attribute_t *attr; /* Current attribute */
206 const char *uri; /* printer-uri */
207 char info[1024], /* printer-info */
208 job_sheets[1024],/* job-sheets-default */
209 location[1024], /* printer-location */
210 make_model[1024];
211 /* printer-make-and-model */
212 cups_ptype_t type; /* printer-type */
213 ipp_pstate_t state; /* printer-state */
214 int accepting; /* printer-is-accepting-jobs */
215 struct sockaddr_in addr; /* Broadcast address */
216 char packet[1540]; /* Data packet */
217 static const char * const attrs[] = /* Requested attributes */
218 {
219 "job-sheets-default",
220 "printer-info",
221 "printer-is-accepting-jobs",
222 "printer-location",
223 "printer-make-and-model",
224 "printer-name",
225 "printer-state",
226 "printer-type",
227 "printer-uri-supported"
228 };
229
230
231 /*
232 * Broadcast to 127.0.0.1 (localhost)
233 */
234
235 memset(&addr, 0, sizeof(addr));
236 addr.sin_addr.s_addr = htonl(0x7f000001);
237 addr.sin_family = AF_INET;
238 addr.sin_port = htons(port);
239
240 /*
241 * Build a CUPS_GET_PRINTERS request and pass along a list of the
242 * attributes we are interested in along with the types of printers
243 * (and classes) we want.
244 */
245
246 request = ippNewRequest(CUPS_GET_PRINTERS);
247
248 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
249 "requested-attributes", sizeof(attrs) / sizeof(attrs[0]),
250 NULL, attrs);
251
252 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
253 "printer-type", 0);
254 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
255 "printer-type-mask",
256 CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
257 CUPS_PRINTER_NOT_SHARED);
258
259 /*
260 * Do the request and get back a response...
261 */
262
263 response = cupsDoRequest(http, request, "/");
264
265 if (cupsLastError() > IPP_OK_CONFLICT)
266 {
267 fprintf(stderr, "ERROR: %s CUPS-Get-Printers failed: %s\n", prefix,
268 cupsLastErrorString());
269 ippDelete(response);
270 return (-1);
271 }
272
273 if (response)
274 {
275 /*
276 * Figure out how many printers/classes we have...
277 */
278
279 for (attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME),
280 max_count = 0;
281 attr != NULL;
282 attr = ippFindNextAttribute(response, "printer-name", IPP_TAG_NAME),
283 max_count ++);
284
285 fprintf(stderr, "DEBUG: %s Found %d printers.\n", prefix, max_count);
286
287 count = 0;
288 seconds = time(NULL);
289 max_count = max_count / interval + 1;
290
291 /*
292 * Loop through the printers or classes returned in the list...
293 */
294
295 for (attr = response->attrs; attr; attr = attr->next)
296 {
297 /*
298 * Skip leading attributes until we hit a printer...
299 */
300
301 while (attr && attr->group_tag != IPP_TAG_PRINTER)
302 attr = attr->next;
303
304 if (!attr)
305 break;
306
307 /*
308 * Pull the needed attributes from this printer...
309 */
310
311 uri = NULL;
312 info[0] = '\0';
313 job_sheets[0] = '\0';
314 location[0] = '\0';
315 make_model[0] = '\0';
316 type = CUPS_PRINTER_REMOTE;
317 accepting = 1;
318 state = IPP_PRINTER_IDLE;
319
320 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
321 {
322 if (!strcmp(attr->name, "job-sheets-default") &&
323 (attr->value_tag == IPP_TAG_NAME ||
324 attr->value_tag == IPP_TAG_KEYWORD))
325 {
326 if (attr->num_values == 1)
327 snprintf(job_sheets, sizeof(job_sheets), " job-sheets=%s",
328 attr->values[0].string.text);
329 else
330 snprintf(job_sheets, sizeof(job_sheets), " job-sheets=%s,%s",
331 attr->values[0].string.text,
332 attr->values[1].string.text);
333 }
334 else if (!strcmp(attr->name, "printer-uri-supported") &&
335 attr->value_tag == IPP_TAG_URI)
336 uri = attr->values[0].string.text;
337 else if (!strcmp(attr->name, "printer-info") &&
338 attr->value_tag == IPP_TAG_TEXT)
339 dequote(info, attr->values[0].string.text, sizeof(info));
340 else if (!strcmp(attr->name, "printer-is-accepting-jobs") &&
341 attr->value_tag == IPP_TAG_BOOLEAN)
342 accepting = attr->values[0].boolean;
343 else if (!strcmp(attr->name, "printer-location") &&
344 attr->value_tag == IPP_TAG_TEXT)
345 dequote(location, attr->values[0].string.text, sizeof(location));
346 else if (!strcmp(attr->name, "printer-make-and-model") &&
347 attr->value_tag == IPP_TAG_TEXT)
348 dequote(make_model, attr->values[0].string.text, sizeof(location));
349 else if (!strcmp(attr->name, "printer-state") &&
350 attr->value_tag == IPP_TAG_ENUM)
351 state = (ipp_pstate_t)attr->values[0].integer;
352 else if (!strcmp(attr->name, "printer-type") &&
353 attr->value_tag == IPP_TAG_ENUM)
354 type = (cups_ptype_t)attr->values[0].integer;
355
356 attr = attr->next;
357 }
358
359 /*
360 * See if we have everything needed...
361 */
362
363 if (uri == NULL)
364 {
365 if (attr == NULL)
366 break;
367 else
368 continue;
369 }
370
371 /*
372 * Send the printer information...
373 */
374
375 type |= CUPS_PRINTER_REMOTE;
376
377 if (!accepting)
378 type |= CUPS_PRINTER_REJECTING;
379
380 snprintf(packet, sizeof(packet),
381 "%x %x %s \"%s\" \"%s\" \"%s\" lease-duration=%d%s\n",
382 type, state, uri, location, info, make_model, interval * 2,
383 job_sheets);
384
385 fprintf(stderr, "DEBUG2: %s Sending %s", prefix, packet);
386
387 if (sendto(sock, packet, strlen(packet), 0,
388 (struct sockaddr *)&addr, sizeof(addr)) <= 0)
389 {
390 ippDelete(response);
391 perror("cups-polld");
392 return (-1);
393 }
394
395 /*
396 * Throttle the local broadcasts as needed so that we don't
397 * overwhelm the local server...
398 */
399
400 count ++;
401 if (count >= max_count)
402 {
403 /*
404 * Sleep for a second...
405 */
406
407 count = 0;
408
409 sleep(1);
410 }
411
412 if (!attr)
413 break;
414 }
415
416 ippDelete(response);
417 }
418
419 /*
420 * Return the number of seconds we used...
421 */
422
423 return (time(NULL) - seconds);
424 }
425
426
427 /*
428 * End of "$Id: cups-polld.c 5753 2006-07-18 19:53:24Z mike $".
429 */