]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
e1d6a774 | 2 | * "$Id: cups-polld.c 5305 2006-03-18 03:05:12Z mike $" |
ef416fc2 | 3 | * |
4 | * Polling daemon for the Common UNIX Printing System (CUPS). | |
5 | * | |
6 | * Copyright 1997-2005 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 | * poll_server() - Poll the server for the given set of printers or classes. | |
28 | */ | |
29 | ||
30 | /* | |
31 | * Include necessary headers... | |
32 | */ | |
33 | ||
34 | #include <cups/http-private.h> | |
35 | #include <cups/cups.h> | |
36 | #include <stdlib.h> | |
37 | #include <errno.h> | |
38 | #include <cups/language.h> | |
39 | #include <cups/string.h> | |
40 | ||
41 | ||
42 | /* | |
43 | * Local functions... | |
44 | */ | |
45 | ||
e1d6a774 | 46 | static int poll_server(http_t *http, cups_lang_t *language, ipp_op_t op, |
47 | int sock, int port, int interval, | |
48 | const char *prefix); | |
ef416fc2 | 49 | |
50 | ||
51 | /* | |
52 | * 'main()' - Open sockets and poll until we are killed... | |
53 | */ | |
54 | ||
55 | int /* O - Exit status */ | |
56 | main(int argc, /* I - Number of command-line arguments */ | |
57 | char *argv[]) /* I - Command-line arguments */ | |
58 | { | |
59 | http_t *http; /* HTTP connection */ | |
60 | cups_lang_t *language; /* Language info */ | |
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 | language = cupsLangDefault(); | |
139 | ||
140 | for (;;) | |
141 | { | |
142 | /* | |
143 | * Get the printers, then the classes... | |
144 | */ | |
145 | ||
146 | remain = interval; | |
147 | ||
148 | if ((seconds = poll_server(http, language, CUPS_GET_PRINTERS, sock, port, | |
149 | interval, prefix)) > 0) | |
150 | remain -= seconds; | |
151 | ||
152 | /* | |
153 | * Sleep for any remaining time... | |
154 | */ | |
155 | ||
156 | if (remain > 0) | |
157 | sleep(remain); | |
158 | } | |
159 | } | |
160 | ||
161 | ||
162 | /* | |
163 | * 'poll_server()' - Poll the server for the given set of printers or classes. | |
164 | */ | |
165 | ||
e1d6a774 | 166 | static int /* O - Number of seconds or -1 on error */ |
ef416fc2 | 167 | poll_server(http_t *http, /* I - HTTP connection */ |
168 | cups_lang_t *language, /* I - Language */ | |
169 | ipp_op_t op, /* I - Operation code */ | |
170 | int sock, /* I - Broadcast sock */ | |
171 | int port, /* I - Broadcast port */ | |
172 | int interval, /* I - Polling interval */ | |
173 | const char *prefix) /* I - Prefix for log messages */ | |
174 | { | |
175 | int seconds; /* Number of seconds */ | |
176 | int count, /* Current number of printers/classes */ | |
177 | max_count; /* Maximum printers/classes per second */ | |
178 | ipp_t *request, /* Request data */ | |
179 | *response; /* Response data */ | |
180 | ipp_attribute_t *attr; /* Current attribute */ | |
181 | const char *uri, /* printer-uri */ | |
182 | *info, /* printer-info */ | |
183 | *location, /* printer-location */ | |
184 | *make_model; /* printer-make-and-model */ | |
185 | cups_ptype_t type; /* printer-type */ | |
186 | ipp_pstate_t state; /* printer-state */ | |
187 | int accepting; /* printer-is-accepting-jobs */ | |
188 | struct sockaddr_in addr; /* Broadcast address */ | |
189 | char packet[1540]; /* Data packet */ | |
190 | static const char * const attrs[] = /* Requested attributes */ | |
191 | { | |
192 | "printer-info", | |
193 | "printer-is-accepting-jobs", | |
194 | "printer-location", | |
195 | "printer-make-and-model", | |
196 | "printer-name", | |
197 | "printer-state", | |
198 | "printer-type", | |
199 | "printer-uri-supported" | |
200 | }; | |
201 | ||
202 | ||
203 | /* | |
204 | * Broadcast to 127.0.0.1 (localhost) | |
205 | */ | |
206 | ||
207 | memset(&addr, 0, sizeof(addr)); | |
208 | addr.sin_addr.s_addr = htonl(0x7f000001); | |
209 | addr.sin_family = AF_INET; | |
210 | addr.sin_port = htons(port); | |
211 | ||
212 | /* | |
213 | * Build a CUPS_GET_PRINTERS or CUPS_GET_CLASSES request, which requires | |
214 | * only the attributes-charset and attributes-natural-language attributes. | |
215 | */ | |
216 | ||
217 | request = ippNew(); | |
218 | ||
219 | request->request.op.operation_id = op; | |
220 | request->request.op.request_id = 1; | |
221 | ||
222 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, | |
223 | "attributes-charset", NULL, cupsLangEncoding(language)); | |
224 | ||
225 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, | |
226 | "attributes-natural-language", NULL, language->language); | |
227 | ||
228 | ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, | |
229 | "requested-attributes", sizeof(attrs) / sizeof(attrs[0]), | |
230 | NULL, attrs); | |
231 | ||
232 | ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, | |
233 | "printer-type", 0); | |
234 | ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, | |
235 | "printer-type-mask", | |
236 | CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT | | |
237 | CUPS_PRINTER_NOT_SHARED); | |
238 | ||
239 | /* | |
240 | * Do the request and get back a response... | |
241 | */ | |
242 | ||
243 | if ((response = cupsDoRequest(http, request, "/")) != NULL) | |
244 | { | |
245 | if (response->request.status.status_code > IPP_OK_CONFLICT) | |
246 | { | |
247 | fprintf(stderr, "ERROR: %s get-%s failed: %s\n", prefix, | |
248 | op == CUPS_GET_PRINTERS ? "printers" : "classes", | |
249 | ippErrorString(response->request.status.status_code)); | |
250 | ippDelete(response); | |
251 | return (-1); | |
252 | } | |
253 | ||
254 | /* | |
255 | * Figure out how many printers/classes we have... | |
256 | */ | |
257 | ||
258 | for (attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME), | |
259 | max_count = 0; | |
260 | attr != NULL; | |
261 | attr = ippFindNextAttribute(response, "printer-name", IPP_TAG_NAME), | |
262 | max_count ++); | |
263 | ||
264 | fprintf(stderr, "DEBUG: %s found %d %s.\n", prefix, max_count, | |
265 | op == CUPS_GET_PRINTERS ? "printers" : "classes"); | |
266 | ||
267 | count = 0; | |
268 | seconds = time(NULL); | |
269 | max_count = max_count / interval + 1; | |
270 | ||
271 | /* | |
272 | * Loop through the printers or classes returned in the list... | |
273 | */ | |
274 | ||
275 | for (attr = response->attrs; attr != NULL; attr = attr->next) | |
276 | { | |
277 | /* | |
278 | * Skip leading attributes until we hit a printer... | |
279 | */ | |
280 | ||
281 | while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER) | |
282 | attr = attr->next; | |
283 | ||
284 | if (attr == NULL) | |
285 | break; | |
286 | ||
287 | /* | |
288 | * Pull the needed attributes from this printer... | |
289 | */ | |
290 | ||
291 | uri = NULL; | |
292 | info = ""; | |
293 | location = ""; | |
294 | make_model = ""; | |
295 | type = CUPS_PRINTER_REMOTE; | |
296 | accepting = 1; | |
297 | state = IPP_PRINTER_IDLE; | |
298 | ||
299 | while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) | |
300 | { | |
301 | if (strcmp(attr->name, "printer-uri-supported") == 0 && | |
302 | attr->value_tag == IPP_TAG_URI) | |
303 | uri = attr->values[0].string.text; | |
304 | ||
305 | if (strcmp(attr->name, "printer-info") == 0 && | |
306 | attr->value_tag == IPP_TAG_TEXT) | |
307 | info = attr->values[0].string.text; | |
308 | ||
309 | if (strcmp(attr->name, "printer-is-accepting-jobs") == 0 && | |
310 | attr->value_tag == IPP_TAG_BOOLEAN) | |
311 | accepting = attr->values[0].boolean; | |
312 | ||
313 | if (strcmp(attr->name, "printer-location") == 0 && | |
314 | attr->value_tag == IPP_TAG_TEXT) | |
315 | location = attr->values[0].string.text; | |
316 | ||
317 | if (strcmp(attr->name, "printer-make-and-model") == 0 && | |
318 | attr->value_tag == IPP_TAG_TEXT) | |
319 | make_model = attr->values[0].string.text; | |
320 | ||
321 | if (strcmp(attr->name, "printer-state") == 0 && | |
322 | attr->value_tag == IPP_TAG_ENUM) | |
323 | state = (ipp_pstate_t)attr->values[0].integer; | |
324 | ||
325 | if (strcmp(attr->name, "printer-type") == 0 && | |
326 | attr->value_tag == IPP_TAG_ENUM) | |
327 | type = (cups_ptype_t)attr->values[0].integer; | |
328 | ||
329 | attr = attr->next; | |
330 | } | |
331 | ||
332 | /* | |
333 | * See if we have everything needed... | |
334 | */ | |
335 | ||
336 | if (uri == NULL) | |
337 | { | |
338 | if (attr == NULL) | |
339 | break; | |
340 | else | |
341 | continue; | |
342 | } | |
343 | ||
344 | /* | |
345 | * Send the printer information... | |
346 | */ | |
347 | ||
348 | type |= CUPS_PRINTER_REMOTE; | |
349 | ||
350 | if (!accepting) | |
351 | type |= CUPS_PRINTER_REJECTING; | |
352 | ||
353 | snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\"\n", | |
354 | type, state, uri, location, info, make_model); | |
355 | ||
356 | fprintf(stderr, "DEBUG2: %s Sending %s", prefix, packet); | |
357 | ||
358 | if (sendto(sock, packet, strlen(packet), 0, | |
359 | (struct sockaddr *)&addr, sizeof(addr)) <= 0) | |
360 | { | |
361 | ippDelete(response); | |
362 | perror("cups-polld"); | |
363 | return (-1); | |
364 | } | |
365 | ||
366 | /* | |
367 | * Throttle the local broadcasts as needed so that we don't | |
368 | * overwhelm the local server... | |
369 | */ | |
370 | ||
371 | count ++; | |
372 | if (count >= max_count) | |
373 | { | |
374 | /* | |
375 | * Sleep for a second... | |
376 | */ | |
377 | ||
378 | count = 0; | |
379 | sleep(1); | |
380 | } | |
381 | ||
382 | if (attr == NULL) | |
383 | break; | |
384 | } | |
385 | ||
386 | ippDelete(response); | |
387 | } | |
388 | else | |
389 | { | |
390 | fprintf(stderr, "ERROR: %s get-%s failed: %s\n", prefix, | |
391 | op == CUPS_GET_PRINTERS ? "printers" : "classes", | |
392 | ippErrorString(cupsLastError())); | |
393 | return (-1); | |
394 | } | |
395 | ||
396 | /* | |
397 | * Return the number of seconds we used... | |
398 | */ | |
399 | ||
400 | return (time(NULL) - seconds); | |
401 | } | |
402 | ||
403 | ||
404 | /* | |
e1d6a774 | 405 | * End of "$Id: cups-polld.c 5305 2006-03-18 03:05:12Z mike $". |
ef416fc2 | 406 | */ |