]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
7e86f2f6 | 2 | * Administration CGI for CUPS. |
ef416fc2 | 3 | * |
11055349 | 4 | * Copyright © 2007-2021 by Apple Inc. |
553f29c9 | 5 | * Copyright © 1997-2007 by Easy Software Products. |
ef416fc2 | 6 | * |
553f29c9 MS |
7 | * Licensed under Apache License v2.0. See the file "LICENSE" for more |
8 | * information. | |
ef416fc2 | 9 | */ |
10 | ||
11 | /* | |
12 | * Include necessary headers... | |
13 | */ | |
14 | ||
15 | #include "cgi-private.h" | |
fb2d5470 MS |
16 | #include <cups/http-private.h> |
17 | #include <cups/ppd-private.h> | |
757d2cad | 18 | #include <cups/adminutil.h> |
aaf19ab0 | 19 | #include <cups/ppd.h> |
ef416fc2 | 20 | #include <errno.h> |
fa73b229 | 21 | #include <unistd.h> |
22 | #include <fcntl.h> | |
23 | #include <sys/wait.h> | |
749b1e90 | 24 | #include <limits.h> |
ef416fc2 | 25 | |
26 | ||
f8b3a85b MS |
27 | /* |
28 | * Local globals... | |
29 | */ | |
30 | ||
31 | static int current_device = 0; /* Current device shown */ | |
32 | ||
33 | ||
ef416fc2 | 34 | /* |
35 | * Local functions... | |
36 | */ | |
37 | ||
fb2d5470 | 38 | static void choose_device_cb(const char *device_class, const char *device_id, const char *device_info, const char *device_make_and_model, const char *device_uri, const char *device_location, const char *title); |
fa73b229 | 39 | static void do_am_class(http_t *http, int modify); |
40 | static void do_am_printer(http_t *http, int modify); | |
fa73b229 | 41 | static void do_config_server(http_t *http); |
42 | static void do_delete_class(http_t *http); | |
43 | static void do_delete_printer(http_t *http); | |
323c5de1 | 44 | static void do_list_printers(http_t *http); |
fa73b229 | 45 | static void do_menu(http_t *http); |
fa73b229 | 46 | static void do_set_allowed_users(http_t *http); |
58dc1933 MS |
47 | static void do_set_default(http_t *http); |
48 | static void do_set_options(http_t *http, int is_class); | |
fa73b229 | 49 | static void do_set_sharing(http_t *http); |
749b1e90 MS |
50 | static char *get_option_value(ppd_file_t *ppd, const char *name, |
51 | char *buffer, size_t bufsize); | |
52 | static double get_points(double number, const char *uval); | |
ef416fc2 | 53 | |
54 | ||
55 | /* | |
56 | * 'main()' - Main entry for CGI. | |
57 | */ | |
58 | ||
59 | int /* O - Exit status */ | |
7e86f2f6 | 60 | main(void) |
ef416fc2 | 61 | { |
ef416fc2 | 62 | http_t *http; /* Connection to the server */ |
63 | const char *op; /* Operation name */ | |
64 | ||
65 | ||
ef416fc2 | 66 | /* |
67 | * Connect to the HTTP server... | |
68 | */ | |
69 | ||
bd7854cb | 70 | fputs("DEBUG: admin.cgi started...\n", stderr); |
71 | ||
ef416fc2 | 72 | http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption()); |
73 | ||
a4d04587 | 74 | if (!http) |
75 | { | |
76 | perror("ERROR: Unable to connect to cupsd"); | |
f301802f | 77 | fprintf(stderr, "DEBUG: cupsServer()=\"%s\"\n", |
78 | cupsServer() ? cupsServer() : "(null)"); | |
a4d04587 | 79 | fprintf(stderr, "DEBUG: ippPort()=%d\n", ippPort()); |
80 | fprintf(stderr, "DEBUG: cupsEncryption()=%d\n", cupsEncryption()); | |
81 | exit(1); | |
82 | } | |
83 | ||
bd7854cb | 84 | fprintf(stderr, "DEBUG: http=%p\n", http); |
85 | ||
ef416fc2 | 86 | /* |
87 | * Set the web interface section... | |
88 | */ | |
89 | ||
90 | cgiSetVariable("SECTION", "admin"); | |
ef55b745 | 91 | cgiSetVariable("REFRESH_PAGE", ""); |
ef416fc2 | 92 | |
93 | /* | |
94 | * See if we have form data... | |
95 | */ | |
96 | ||
0af14961 | 97 | if (!cgiInitialize() || !cgiGetVariable("OP")) |
ef416fc2 | 98 | { |
99 | /* | |
100 | * Nope, send the administration menu... | |
101 | */ | |
102 | ||
bd7854cb | 103 | fputs("DEBUG: No form data, showing main menu...\n", stderr); |
104 | ||
fa73b229 | 105 | do_menu(http); |
ef416fc2 | 106 | } |
2e4ff8af | 107 | else if ((op = cgiGetVariable("OP")) != NULL && cgiIsPOST()) |
ef416fc2 | 108 | { |
109 | /* | |
110 | * Do the operation... | |
111 | */ | |
112 | ||
bd7854cb | 113 | fprintf(stderr, "DEBUG: op=\"%s\"...\n", op); |
114 | ||
0268488e MS |
115 | if (!*op) |
116 | { | |
117 | const char *printer = getenv("PRINTER_NAME"), | |
118 | /* Printer or class name */ | |
119 | *server_port = getenv("SERVER_PORT"); | |
120 | /* Port number string */ | |
121 | int port = atoi(server_port ? server_port : "0"); | |
122 | /* Port number */ | |
123 | char uri[1024]; /* URL */ | |
124 | ||
125 | if (printer) | |
126 | httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), | |
127 | getenv("HTTPS") ? "https" : "http", NULL, | |
128 | getenv("SERVER_NAME"), port, "/%s/%s", | |
129 | cgiGetVariable("IS_CLASS") ? "classes" : "printers", | |
130 | printer); | |
131 | else | |
132 | httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), | |
133 | getenv("HTTPS") ? "https" : "http", NULL, | |
134 | getenv("SERVER_NAME"), port, "/admin"); | |
135 | ||
136 | printf("Location: %s\n\n", uri); | |
137 | } | |
138 | else if (!strcmp(op, "set-allowed-users")) | |
fa73b229 | 139 | do_set_allowed_users(http); |
ef416fc2 | 140 | else if (!strcmp(op, "set-as-default")) |
58dc1933 | 141 | do_set_default(http); |
ef416fc2 | 142 | else if (!strcmp(op, "set-sharing")) |
fa73b229 | 143 | do_set_sharing(http); |
355e94dc MS |
144 | else if (!strcmp(op, "find-new-printers") || |
145 | !strcmp(op, "list-available-printers")) | |
323c5de1 | 146 | do_list_printers(http); |
ef416fc2 | 147 | else if (!strcmp(op, "add-class")) |
fa73b229 | 148 | do_am_class(http, 0); |
ef416fc2 | 149 | else if (!strcmp(op, "add-printer")) |
fa73b229 | 150 | do_am_printer(http, 0); |
ef416fc2 | 151 | else if (!strcmp(op, "modify-class")) |
fa73b229 | 152 | do_am_class(http, 1); |
ef416fc2 | 153 | else if (!strcmp(op, "modify-printer")) |
fa73b229 | 154 | do_am_printer(http, 1); |
ef416fc2 | 155 | else if (!strcmp(op, "delete-class")) |
fa73b229 | 156 | do_delete_class(http); |
ef416fc2 | 157 | else if (!strcmp(op, "delete-printer")) |
fa73b229 | 158 | do_delete_printer(http); |
323c5de1 | 159 | else if (!strcmp(op, "set-class-options")) |
160 | do_set_options(http, 1); | |
ef416fc2 | 161 | else if (!strcmp(op, "set-printer-options")) |
323c5de1 | 162 | do_set_options(http, 0); |
ef416fc2 | 163 | else if (!strcmp(op, "config-server")) |
fa73b229 | 164 | do_config_server(http); |
ef416fc2 | 165 | else |
166 | { | |
167 | /* | |
749b1e90 | 168 | * Bad operation code - display an error... |
ef416fc2 | 169 | */ |
170 | ||
fa73b229 | 171 | cgiStartHTML(cgiText(_("Administration"))); |
172 | cgiCopyTemplateLang("error-op.tmpl"); | |
ef416fc2 | 173 | cgiEndHTML(); |
174 | } | |
ef416fc2 | 175 | } |
2e4ff8af MS |
176 | else if (op && !strcmp(op, "redirect")) |
177 | { | |
ef55b745 | 178 | const char *url; /* Redirection URL... */ |
2e4ff8af MS |
179 | char prefix[1024]; /* URL prefix */ |
180 | ||
181 | ||
182 | if (getenv("HTTPS")) | |
183 | snprintf(prefix, sizeof(prefix), "https://%s:%s", | |
184 | getenv("SERVER_NAME"), getenv("SERVER_PORT")); | |
185 | else | |
186 | snprintf(prefix, sizeof(prefix), "http://%s:%s", | |
187 | getenv("SERVER_NAME"), getenv("SERVER_PORT")); | |
188 | ||
0af14961 MS |
189 | fprintf(stderr, "DEBUG: redirecting with prefix %s!\n", prefix); |
190 | ||
2e4ff8af | 191 | if ((url = cgiGetVariable("URL")) != NULL) |
ef55b745 MS |
192 | { |
193 | char encoded[1024], /* Encoded URL string */ | |
194 | *ptr; /* Pointer into encoded string */ | |
195 | ||
196 | ||
197 | ptr = encoded; | |
198 | if (*url != '/') | |
199 | *ptr++ = '/'; | |
200 | ||
201 | for (; *url && ptr < (encoded + sizeof(encoded) - 4); url ++) | |
202 | { | |
203 | if (strchr("%@&+ <>#=", *url) || *url < ' ' || *url & 128) | |
204 | { | |
205 | /* | |
206 | * Percent-encode this character; safe because we have at least 4 | |
207 | * bytes left in the array... | |
208 | */ | |
209 | ||
064e50fb | 210 | snprintf(ptr, sizeof(encoded) - (size_t)(ptr - encoded), "%%%02X", *url & 255); |
ef55b745 MS |
211 | ptr += 3; |
212 | } | |
213 | else | |
214 | *ptr++ = *url; | |
215 | } | |
216 | ||
217 | *ptr = '\0'; | |
218 | ||
219 | if (*url) | |
220 | { | |
221 | /* | |
222 | * URL was too long, just redirect to the admin page... | |
223 | */ | |
224 | ||
225 | printf("Location: %s/admin\n\n", prefix); | |
226 | } | |
227 | else | |
228 | { | |
229 | /* | |
230 | * URL is OK, redirect there... | |
231 | */ | |
232 | ||
233 | printf("Location: %s%s\n\n", prefix, encoded); | |
234 | } | |
235 | } | |
2e4ff8af MS |
236 | else |
237 | printf("Location: %s/admin\n\n", prefix); | |
238 | } | |
ef416fc2 | 239 | else |
240 | { | |
241 | /* | |
749b1e90 | 242 | * Form data but no operation code - display an error... |
ef416fc2 | 243 | */ |
244 | ||
fa73b229 | 245 | cgiStartHTML(cgiText(_("Administration"))); |
246 | cgiCopyTemplateLang("error-op.tmpl"); | |
ef416fc2 | 247 | cgiEndHTML(); |
248 | } | |
249 | ||
250 | /* | |
fa73b229 | 251 | * Close the HTTP server connection... |
ef416fc2 | 252 | */ |
253 | ||
fa73b229 | 254 | httpClose(http); |
ef416fc2 | 255 | |
256 | /* | |
257 | * Return with no errors... | |
258 | */ | |
259 | ||
260 | return (0); | |
261 | } | |
262 | ||
263 | ||
58dc1933 MS |
264 | /* |
265 | * 'choose_device_cb()' - Add a device to the device selection page. | |
266 | */ | |
267 | ||
268 | static void | |
269 | choose_device_cb( | |
270 | const char *device_class, /* I - Class */ | |
271 | const char *device_id, /* I - 1284 device ID */ | |
272 | const char *device_info, /* I - Description */ | |
273 | const char *device_make_and_model, /* I - Make and model */ | |
274 | const char *device_uri, /* I - Device URI */ | |
275 | const char *device_location, /* I - Location */ | |
f8b3a85b | 276 | const char *title) /* I - Page title */ |
58dc1933 | 277 | { |
f8b3a85b MS |
278 | /* |
279 | * For modern browsers, start a multi-part page so we can show that something | |
280 | * is happening. Non-modern browsers just get everything at the end... | |
281 | */ | |
282 | ||
283 | if (current_device == 0 && cgiSupportsMultipart()) | |
284 | { | |
285 | cgiStartMultipart(); | |
286 | cgiStartHTML(title); | |
287 | cgiCopyTemplateLang("choose-device.tmpl"); | |
288 | cgiEndHTML(); | |
289 | fflush(stdout); | |
290 | } | |
291 | ||
292 | ||
58dc1933 MS |
293 | /* |
294 | * Add the device to the array... | |
295 | */ | |
296 | ||
f8b3a85b MS |
297 | cgiSetArray("device_class", current_device, device_class); |
298 | cgiSetArray("device_id", current_device, device_id); | |
299 | cgiSetArray("device_info", current_device, device_info); | |
300 | cgiSetArray("device_make_and_model", current_device, device_make_and_model); | |
301 | cgiSetArray("device_uri", current_device, device_uri); | |
302 | cgiSetArray("device_location", current_device, device_location); | |
58dc1933 | 303 | |
f8b3a85b | 304 | current_device ++; |
58dc1933 MS |
305 | } |
306 | ||
307 | ||
ef416fc2 | 308 | /* |
309 | * 'do_am_class()' - Add or modify a class. | |
310 | */ | |
311 | ||
312 | static void | |
fa73b229 | 313 | do_am_class(http_t *http, /* I - HTTP connection */ |
314 | int modify) /* I - Modify the printer? */ | |
ef416fc2 | 315 | { |
316 | int i, j; /* Looping vars */ | |
317 | int element; /* Element number */ | |
318 | int num_printers; /* Number of printers */ | |
319 | ipp_t *request, /* IPP request */ | |
320 | *response; /* IPP response */ | |
321 | ipp_attribute_t *attr; /* member-uris attribute */ | |
ef416fc2 | 322 | char uri[HTTP_MAX_URI]; /* Device or printer URI */ |
323 | const char *name, /* Pointer to class name */ | |
ef55b745 | 324 | *op, /* Operation name */ |
ef416fc2 | 325 | *ptr; /* Pointer to CGI variable */ |
326 | const char *title; /* Title of page */ | |
327 | static const char * const pattrs[] = /* Requested printer attributes */ | |
328 | { | |
329 | "member-names", | |
330 | "printer-info", | |
331 | "printer-location" | |
332 | }; | |
333 | ||
334 | ||
fa73b229 | 335 | title = cgiText(modify ? _("Modify Class") : _("Add Class")); |
ef55b745 | 336 | op = cgiGetVariable("OP"); |
ef416fc2 | 337 | name = cgiGetVariable("PRINTER_NAME"); |
338 | ||
339 | if (cgiGetVariable("PRINTER_LOCATION") == NULL) | |
340 | { | |
341 | /* | |
342 | * Build a CUPS_GET_PRINTERS request, which requires the | |
343 | * following attributes: | |
344 | * | |
345 | * attributes-charset | |
346 | * attributes-natural-language | |
ef416fc2 | 347 | */ |
348 | ||
fa73b229 | 349 | request = ippNewRequest(CUPS_GET_PRINTERS); |
ef416fc2 | 350 | |
acb056cb MS |
351 | ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type", |
352 | CUPS_PRINTER_LOCAL); | |
353 | ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type-mask", | |
a2326b5b | 354 | CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE); |
acb056cb | 355 | |
ef416fc2 | 356 | /* |
357 | * Do the request and get back a response... | |
358 | */ | |
359 | ||
ef55b745 MS |
360 | cgiClearVariables(); |
361 | if (op) | |
362 | cgiSetVariable("OP", op); | |
363 | if (name) | |
364 | cgiSetVariable("PRINTER_NAME", name); | |
365 | ||
ef416fc2 | 366 | if ((response = cupsDoRequest(http, request, "/")) != NULL) |
367 | { | |
368 | /* | |
369 | * Create MEMBER_URIS and MEMBER_NAMES arrays... | |
370 | */ | |
371 | ||
372 | for (element = 0, attr = response->attrs; | |
373 | attr != NULL; | |
374 | attr = attr->next) | |
375 | if (attr->name && !strcmp(attr->name, "printer-uri-supported")) | |
376 | { | |
377 | if ((ptr = strrchr(attr->values[0].string.text, '/')) != NULL && | |
88f9aafc | 378 | (!name || _cups_strcasecmp(name, ptr + 1))) |
ef416fc2 | 379 | { |
380 | /* | |
381 | * Don't show the current class... | |
382 | */ | |
383 | ||
384 | cgiSetArray("MEMBER_URIS", element, attr->values[0].string.text); | |
385 | element ++; | |
386 | } | |
387 | } | |
388 | ||
389 | for (element = 0, attr = response->attrs; | |
390 | attr != NULL; | |
391 | attr = attr->next) | |
392 | if (attr->name && !strcmp(attr->name, "printer-name")) | |
393 | { | |
88f9aafc | 394 | if (!name || _cups_strcasecmp(name, attr->values[0].string.text)) |
ef416fc2 | 395 | { |
396 | /* | |
397 | * Don't show the current class... | |
398 | */ | |
399 | ||
400 | cgiSetArray("MEMBER_NAMES", element, attr->values[0].string.text); | |
401 | element ++; | |
402 | } | |
403 | } | |
404 | ||
405 | num_printers = cgiGetSize("MEMBER_URIS"); | |
406 | ||
407 | ippDelete(response); | |
408 | } | |
409 | else | |
410 | num_printers = 0; | |
411 | ||
412 | if (modify) | |
413 | { | |
414 | /* | |
415 | * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the | |
416 | * following attributes: | |
417 | * | |
418 | * attributes-charset | |
419 | * attributes-natural-language | |
420 | * printer-uri | |
421 | */ | |
422 | ||
fa73b229 | 423 | request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); |
ef416fc2 | 424 | |
a4d04587 | 425 | httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, |
426 | "localhost", 0, "/classes/%s", name); | |
ef416fc2 | 427 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", |
428 | NULL, uri); | |
429 | ||
430 | ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, | |
431 | "requested-attributes", | |
432 | (int)(sizeof(pattrs) / sizeof(pattrs[0])), | |
433 | NULL, pattrs); | |
434 | ||
435 | /* | |
436 | * Do the request and get back a response... | |
437 | */ | |
438 | ||
439 | if ((response = cupsDoRequest(http, request, "/")) != NULL) | |
440 | { | |
480ef0fe | 441 | if ((attr = ippFindAttribute(response, "member-names", |
442 | IPP_TAG_NAME)) != NULL) | |
ef416fc2 | 443 | { |
444 | /* | |
445 | * Mark any current members in the class... | |
446 | */ | |
447 | ||
448 | for (j = 0; j < num_printers; j ++) | |
449 | cgiSetArray("MEMBER_SELECTED", j, ""); | |
450 | ||
451 | for (i = 0; i < attr->num_values; i ++) | |
452 | { | |
453 | for (j = 0; j < num_printers; j ++) | |
454 | { | |
88f9aafc | 455 | if (!_cups_strcasecmp(attr->values[i].string.text, |
ef416fc2 | 456 | cgiGetArray("MEMBER_NAMES", j))) |
457 | { | |
458 | cgiSetArray("MEMBER_SELECTED", j, "SELECTED"); | |
459 | break; | |
460 | } | |
461 | } | |
462 | } | |
463 | } | |
464 | ||
465 | if ((attr = ippFindAttribute(response, "printer-info", | |
466 | IPP_TAG_TEXT)) != NULL) | |
467 | cgiSetVariable("PRINTER_INFO", attr->values[0].string.text); | |
468 | ||
469 | if ((attr = ippFindAttribute(response, "printer-location", | |
470 | IPP_TAG_TEXT)) != NULL) | |
471 | cgiSetVariable("PRINTER_LOCATION", attr->values[0].string.text); | |
472 | ||
473 | ippDelete(response); | |
474 | } | |
475 | ||
476 | /* | |
477 | * Update the location and description of an existing printer... | |
478 | */ | |
479 | ||
480 | cgiStartHTML(title); | |
481 | cgiCopyTemplateLang("modify-class.tmpl"); | |
482 | } | |
483 | else | |
484 | { | |
485 | /* | |
486 | * Get the name, location, and description for a new printer... | |
487 | */ | |
488 | ||
489 | cgiStartHTML(title); | |
490 | cgiCopyTemplateLang("add-class.tmpl"); | |
491 | } | |
492 | ||
493 | cgiEndHTML(); | |
494 | ||
495 | return; | |
496 | } | |
497 | ||
7a0cbd5e MS |
498 | if (!name) |
499 | { | |
500 | cgiStartHTML(title); | |
4d301e69 | 501 | cgiSetVariable("ERROR", cgiText(_("Missing form variable"))); |
7a0cbd5e MS |
502 | cgiCopyTemplateLang("error.tmpl"); |
503 | cgiEndHTML(); | |
504 | return; | |
505 | } | |
506 | ||
ef416fc2 | 507 | for (ptr = name; *ptr; ptr ++) |
508 | if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#') | |
509 | break; | |
510 | ||
511 | if (*ptr || ptr == name || strlen(name) > 127) | |
512 | { | |
fa73b229 | 513 | cgiSetVariable("ERROR", |
514 | cgiText(_("The class name may only contain up to " | |
515 | "127 printable characters and may not " | |
516 | "contain spaces, slashes (/), or the " | |
517 | "pound sign (#)."))); | |
ef416fc2 | 518 | cgiStartHTML(title); |
519 | cgiCopyTemplateLang("error.tmpl"); | |
520 | cgiEndHTML(); | |
521 | return; | |
522 | } | |
523 | ||
524 | /* | |
525 | * Build a CUPS_ADD_CLASS request, which requires the following | |
526 | * attributes: | |
527 | * | |
528 | * attributes-charset | |
529 | * attributes-natural-language | |
530 | * printer-uri | |
531 | * printer-location | |
532 | * printer-info | |
533 | * printer-is-accepting-jobs | |
534 | * printer-state | |
535 | * member-uris | |
536 | */ | |
537 | ||
fa73b229 | 538 | request = ippNewRequest(CUPS_ADD_CLASS); |
ef416fc2 | 539 | |
a4d04587 | 540 | httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, |
7a0cbd5e | 541 | "localhost", 0, "/classes/%s", name); |
ef416fc2 | 542 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", |
543 | NULL, uri); | |
544 | ||
545 | ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location", | |
546 | NULL, cgiGetVariable("PRINTER_LOCATION")); | |
547 | ||
548 | ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info", | |
549 | NULL, cgiGetVariable("PRINTER_INFO")); | |
550 | ||
551 | ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1); | |
552 | ||
553 | ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", | |
554 | IPP_PRINTER_IDLE); | |
555 | ||
556 | if ((num_printers = cgiGetSize("MEMBER_URIS")) > 0) | |
557 | { | |
558 | attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI, "member-uris", | |
559 | num_printers, NULL, NULL); | |
560 | for (i = 0; i < num_printers; i ++) | |
86c184ff | 561 | ippSetString(request, &attr, i, cgiGetArray("MEMBER_URIS", i)); |
ef416fc2 | 562 | } |
563 | ||
564 | /* | |
565 | * Do the request and get back a response... | |
566 | */ | |
567 | ||
fa73b229 | 568 | ippDelete(cupsDoRequest(http, request, "/admin/")); |
ef416fc2 | 569 | |
355e94dc MS |
570 | if (cupsLastError() == IPP_NOT_AUTHORIZED) |
571 | { | |
572 | puts("Status: 401\n"); | |
573 | exit(0); | |
574 | } | |
575 | else if (cupsLastError() > IPP_OK_CONFLICT) | |
ef416fc2 | 576 | { |
577 | cgiStartHTML(title); | |
f3c17241 MS |
578 | cgiShowIPPError(modify ? _("Unable to modify class") : |
579 | _("Unable to add class")); | |
ef416fc2 | 580 | } |
581 | else | |
582 | { | |
583 | /* | |
584 | * Redirect successful updates back to the class page... | |
585 | */ | |
586 | ||
587 | char refresh[1024]; /* Refresh URL */ | |
588 | ||
589 | cgiFormEncode(uri, name, sizeof(uri)); | |
f301802f | 590 | snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=/classes/%s", |
ef416fc2 | 591 | uri); |
592 | cgiSetVariable("refresh_page", refresh); | |
593 | ||
594 | cgiStartHTML(title); | |
595 | ||
596 | if (modify) | |
597 | cgiCopyTemplateLang("class-modified.tmpl"); | |
598 | else | |
599 | cgiCopyTemplateLang("class-added.tmpl"); | |
600 | } | |
601 | ||
602 | cgiEndHTML(); | |
603 | } | |
604 | ||
605 | ||
606 | /* | |
607 | * 'do_am_printer()' - Add or modify a printer. | |
608 | */ | |
609 | ||
610 | static void | |
fa73b229 | 611 | do_am_printer(http_t *http, /* I - HTTP connection */ |
612 | int modify) /* I - Modify the printer? */ | |
ef416fc2 | 613 | { |
614 | int i; /* Looping var */ | |
89d46774 | 615 | ipp_attribute_t *attr; /* Current attribute */ |
ef416fc2 | 616 | ipp_t *request, /* IPP request */ |
617 | *response, /* IPP response */ | |
618 | *oldinfo; /* Old printer information */ | |
ef416fc2 | 619 | const cgi_file_t *file; /* Uploaded file, if any */ |
620 | const char *var; /* CGI variable */ | |
621 | char uri[HTTP_MAX_URI], /* Device or printer URI */ | |
fb2d5470 MS |
622 | *uriptr, /* Pointer into URI */ |
623 | evefile[1024] = ""; /* IPP Everywhere PPD file */ | |
ef416fc2 | 624 | int maxrate; /* Maximum baud rate */ |
625 | char baudrate[255]; /* Baud rate string */ | |
626 | const char *name, /* Pointer to class name */ | |
627 | *ptr; /* Pointer to CGI variable */ | |
628 | const char *title; /* Title of page */ | |
629 | static int baudrates[] = /* Baud rates */ | |
630 | { | |
631 | 1200, | |
632 | 2400, | |
633 | 4800, | |
634 | 9600, | |
635 | 19200, | |
636 | 38400, | |
637 | 57600, | |
638 | 115200, | |
639 | 230400, | |
640 | 460800 | |
641 | }; | |
642 | ||
643 | ||
f301802f | 644 | ptr = cgiGetVariable("DEVICE_URI"); |
fa73b229 | 645 | fprintf(stderr, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n", |
f301802f | 646 | ptr ? ptr : "(null)"); |
fa73b229 | 647 | |
648 | title = cgiText(modify ? _("Modify Printer") : _("Add Printer")); | |
ef416fc2 | 649 | |
650 | if (modify) | |
651 | { | |
652 | /* | |
653 | * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the | |
654 | * following attributes: | |
655 | * | |
656 | * attributes-charset | |
657 | * attributes-natural-language | |
658 | * printer-uri | |
659 | */ | |
660 | ||
fa73b229 | 661 | request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); |
ef416fc2 | 662 | |
a4d04587 | 663 | httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, |
664 | "localhost", 0, "/printers/%s", | |
665 | cgiGetVariable("PRINTER_NAME")); | |
ef416fc2 | 666 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", |
667 | NULL, uri); | |
668 | ||
669 | /* | |
670 | * Do the request and get back a response... | |
671 | */ | |
672 | ||
673 | oldinfo = cupsDoRequest(http, request, "/"); | |
674 | } | |
675 | else | |
676 | oldinfo = NULL; | |
677 | ||
2e4ff8af | 678 | file = cgiGetFile(); |
ef416fc2 | 679 | |
2e4ff8af MS |
680 | if (file) |
681 | { | |
682 | fprintf(stderr, "DEBUG: file->tempfile=%s\n", file->tempfile); | |
683 | fprintf(stderr, "DEBUG: file->name=%s\n", file->name); | |
684 | fprintf(stderr, "DEBUG: file->filename=%s\n", file->filename); | |
685 | fprintf(stderr, "DEBUG: file->mimetype=%s\n", file->mimetype); | |
686 | } | |
ef416fc2 | 687 | |
2e4ff8af MS |
688 | if ((name = cgiGetVariable("PRINTER_NAME")) != NULL) |
689 | { | |
690 | for (ptr = name; *ptr; ptr ++) | |
f1547f12 | 691 | if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '\\' || *ptr == '?' || *ptr == '\'' || *ptr == '\"' || *ptr == '#') |
2e4ff8af | 692 | break; |
ef416fc2 | 693 | |
2e4ff8af MS |
694 | if (*ptr || ptr == name || strlen(name) > 127) |
695 | { | |
696 | cgiSetVariable("ERROR", | |
f1547f12 | 697 | cgiText(_("The printer name may only contain up to 127 printable characters and may not contain spaces, slashes (/ \\), quotes (' \"), question mark (?), or the pound sign (#)."))); |
2e4ff8af MS |
698 | cgiStartHTML(title); |
699 | cgiCopyTemplateLang("error.tmpl"); | |
700 | cgiEndHTML(); | |
701 | return; | |
ef416fc2 | 702 | } |
2e4ff8af MS |
703 | } |
704 | ||
705 | if ((var = cgiGetVariable("DEVICE_URI")) != NULL) | |
706 | { | |
707 | if ((uriptr = strrchr(var, '|')) != NULL) | |
ef416fc2 | 708 | { |
709 | /* | |
2e4ff8af | 710 | * Extract make and make/model from device URI string... |
ef416fc2 | 711 | */ |
712 | ||
2e4ff8af MS |
713 | char make[1024], /* Make string */ |
714 | *makeptr; /* Pointer into make */ | |
ef416fc2 | 715 | |
ef416fc2 | 716 | |
2e4ff8af | 717 | *uriptr++ = '\0'; |
ef416fc2 | 718 | |
2e4ff8af | 719 | strlcpy(make, uriptr, sizeof(make)); |
ef416fc2 | 720 | |
2e4ff8af MS |
721 | if ((makeptr = strchr(make, ' ')) != NULL) |
722 | *makeptr = '\0'; | |
723 | else if ((makeptr = strchr(make, '-')) != NULL) | |
724 | *makeptr = '\0'; | |
88f9aafc MS |
725 | else if (!_cups_strncasecmp(make, "laserjet", 8) || |
726 | !_cups_strncasecmp(make, "deskjet", 7) || | |
727 | !_cups_strncasecmp(make, "designjet", 9)) | |
5a9febac | 728 | strlcpy(make, "HP", sizeof(make)); |
88f9aafc | 729 | else if (!_cups_strncasecmp(make, "phaser", 6)) |
5a9febac | 730 | strlcpy(make, "Xerox", sizeof(make)); |
88f9aafc | 731 | else if (!_cups_strncasecmp(make, "stylus", 6)) |
5a9febac | 732 | strlcpy(make, "Epson", sizeof(make)); |
2e4ff8af | 733 | else |
5a9febac | 734 | strlcpy(make, "Generic", sizeof(make)); |
ef416fc2 | 735 | |
2e4ff8af MS |
736 | if (!cgiGetVariable("CURRENT_MAKE")) |
737 | cgiSetVariable("CURRENT_MAKE", make); | |
ef416fc2 | 738 | |
2e4ff8af MS |
739 | if (!cgiGetVariable("CURRENT_MAKE_AND_MODEL")) |
740 | cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr); | |
741 | ||
742 | if (!modify) | |
743 | { | |
744 | char template[128], /* Template name */ | |
745 | *tptr; /* Pointer into template name */ | |
746 | ||
747 | cgiSetVariable("PRINTER_INFO", uriptr); | |
748 | ||
749 | for (tptr = template; | |
750 | tptr < (template + sizeof(template) - 1) && *uriptr; | |
751 | uriptr ++) | |
752 | if (isalnum(*uriptr & 255) || *uriptr == '_' || *uriptr == '-' || | |
753 | *uriptr == '.') | |
754 | *tptr++ = *uriptr; | |
41681883 MS |
755 | else if ((*uriptr == ' ' || *uriptr == '/') && tptr > template && |
756 | tptr[-1] != '_') | |
2e4ff8af MS |
757 | *tptr++ = '_'; |
758 | else if (*uriptr == '?' || *uriptr == '(') | |
759 | break; | |
760 | ||
761 | *tptr = '\0'; | |
762 | ||
763 | cgiSetVariable("TEMPLATE_NAME", template); | |
764 | } | |
064e50fb MS |
765 | |
766 | /* | |
767 | * Set DEVICE_URI to the actual device uri, without make and model from | |
768 | * html form. | |
769 | */ | |
770 | ||
771 | cgiSetVariable("DEVICE_URI", var); | |
2e4ff8af | 772 | } |
ef416fc2 | 773 | } |
774 | ||
2e4ff8af | 775 | if (!var) |
ef416fc2 | 776 | { |
777 | /* | |
58dc1933 | 778 | * Look for devices so the user can pick something... |
ef416fc2 | 779 | */ |
780 | ||
58dc1933 MS |
781 | if ((attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL) |
782 | { | |
783 | strlcpy(uri, attr->values[0].string.text, sizeof(uri)); | |
784 | if ((uriptr = strchr(uri, ':')) != NULL && strncmp(uriptr, "://", 3) == 0) | |
785 | *uriptr = '\0'; | |
a4d04587 | 786 | |
58dc1933 MS |
787 | cgiSetVariable("CURRENT_DEVICE_URI", attr->values[0].string.text); |
788 | cgiSetVariable("CURRENT_DEVICE_SCHEME", uri); | |
789 | } | |
ef416fc2 | 790 | |
ef55b745 MS |
791 | /* |
792 | * Scan for devices for up to 30 seconds... | |
ef416fc2 | 793 | */ |
794 | ||
58dc1933 | 795 | fputs("DEBUG: Getting list of devices...\n", stderr); |
a4d04587 | 796 | |
ef55b745 | 797 | current_device = 0; |
f14324a7 | 798 | if (cupsGetDevices(http, 5, CUPS_INCLUDE_ALL, CUPS_EXCLUDE_NONE, |
ed6e7faf | 799 | (cups_device_cb_t)choose_device_cb, |
f8b3a85b | 800 | (void *)title) == IPP_OK) |
d2354e63 | 801 | { |
58dc1933 | 802 | fputs("DEBUG: Got device list!\n", stderr); |
d2354e63 | 803 | |
ef55b745 MS |
804 | if (cgiSupportsMultipart()) |
805 | cgiStartMultipart(); | |
d2354e63 | 806 | |
ef55b745 MS |
807 | cgiSetVariable("CUPS_GET_DEVICES_DONE", "1"); |
808 | cgiStartHTML(title); | |
809 | cgiCopyTemplateLang("choose-device.tmpl"); | |
810 | cgiEndHTML(); | |
811 | ||
812 | if (cgiSupportsMultipart()) | |
813 | cgiEndMultipart(); | |
d2354e63 | 814 | } |
a4d04587 | 815 | else |
e4572d57 | 816 | { |
a4d04587 | 817 | fprintf(stderr, |
818 | "ERROR: CUPS-Get-Devices request failed with status %x: %s\n", | |
819 | cupsLastError(), cupsLastErrorString()); | |
e4572d57 MS |
820 | if (cupsLastError() == IPP_NOT_AUTHORIZED) |
821 | { | |
822 | puts("Status: 401\n"); | |
823 | exit(0); | |
824 | } | |
825 | else | |
826 | { | |
827 | cgiStartHTML(title); | |
f3c17241 MS |
828 | cgiShowIPPError(modify ? _("Unable to modify printer") : |
829 | _("Unable to add printer")); | |
e4572d57 MS |
830 | cgiEndHTML(); |
831 | return; | |
832 | } | |
833 | } | |
ef416fc2 | 834 | } |
0268488e MS |
835 | else if (!strchr(var, '/') || |
836 | (!strncmp(var, "lpd://", 6) && !strchr(var + 6, '/'))) | |
ef416fc2 | 837 | { |
838 | if ((attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL) | |
839 | { | |
840 | /* | |
841 | * Set the current device URI for the form to the old one... | |
842 | */ | |
843 | ||
844 | if (strncmp(attr->values[0].string.text, var, strlen(var)) == 0) | |
1f6f3dbc | 845 | cgiSetVariable("CURRENT_DEVICE_URI", attr->values[0].string.text); |
ef416fc2 | 846 | } |
847 | ||
848 | /* | |
849 | * User needs to set the full URI... | |
850 | */ | |
851 | ||
852 | cgiStartHTML(title); | |
853 | cgiCopyTemplateLang("choose-uri.tmpl"); | |
854 | cgiEndHTML(); | |
855 | } | |
856 | else if (!strncmp(var, "serial:", 7) && !cgiGetVariable("BAUDRATE")) | |
857 | { | |
858 | /* | |
859 | * Need baud rate, parity, etc. | |
860 | */ | |
861 | ||
862 | if ((var = strchr(var, '?')) != NULL && | |
863 | strncmp(var, "?baud=", 6) == 0) | |
864 | maxrate = atoi(var + 6); | |
865 | else | |
866 | maxrate = 19200; | |
867 | ||
868 | for (i = 0; i < 10; i ++) | |
869 | if (baudrates[i] > maxrate) | |
870 | break; | |
871 | else | |
872 | { | |
064e50fb | 873 | snprintf(baudrate, sizeof(baudrate), "%d", baudrates[i]); |
ef416fc2 | 874 | cgiSetArray("BAUDRATES", i, baudrate); |
875 | } | |
876 | ||
877 | cgiStartHTML(title); | |
878 | cgiCopyTemplateLang("choose-serial.tmpl"); | |
879 | cgiEndHTML(); | |
880 | } | |
2e4ff8af MS |
881 | else if (!name || !cgiGetVariable("PRINTER_LOCATION")) |
882 | { | |
883 | cgiStartHTML(title); | |
884 | ||
885 | if (modify) | |
886 | { | |
887 | /* | |
888 | * Update the location and description of an existing printer... | |
889 | */ | |
890 | ||
891 | if (oldinfo) | |
1f6f3dbc MS |
892 | { |
893 | if ((attr = ippFindAttribute(oldinfo, "printer-info", | |
894 | IPP_TAG_TEXT)) != NULL) | |
895 | cgiSetVariable("PRINTER_INFO", attr->values[0].string.text); | |
896 | ||
897 | if ((attr = ippFindAttribute(oldinfo, "printer-location", | |
898 | IPP_TAG_TEXT)) != NULL) | |
899 | cgiSetVariable("PRINTER_LOCATION", attr->values[0].string.text); | |
ef55b745 MS |
900 | |
901 | if ((attr = ippFindAttribute(oldinfo, "printer-is-shared", | |
902 | IPP_TAG_BOOLEAN)) != NULL) | |
903 | cgiSetVariable("PRINTER_IS_SHARED", | |
904 | attr->values[0].boolean ? "1" : "0"); | |
1f6f3dbc | 905 | } |
2e4ff8af MS |
906 | |
907 | cgiCopyTemplateLang("modify-printer.tmpl"); | |
908 | } | |
909 | else | |
910 | { | |
911 | /* | |
912 | * Get the name, location, and description for a new printer... | |
913 | */ | |
914 | ||
c5571a1d MS |
915 | #ifdef __APPLE__ |
916 | if (!strncmp(var, "usb:", 4)) | |
917 | cgiSetVariable("printer_is_shared", "1"); | |
918 | else | |
919 | #endif /* __APPLE__ */ | |
920 | cgiSetVariable("printer_is_shared", "0"); | |
921 | ||
2e4ff8af MS |
922 | cgiCopyTemplateLang("add-printer.tmpl"); |
923 | } | |
924 | ||
925 | cgiEndHTML(); | |
926 | ||
927 | if (oldinfo) | |
928 | ippDelete(oldinfo); | |
929 | ||
930 | return; | |
931 | } | |
bf3816c7 MS |
932 | else if (!file && |
933 | (!cgiGetVariable("PPD_NAME") || cgiGetVariable("SELECT_MAKE"))) | |
ef416fc2 | 934 | { |
553f29c9 MS |
935 | int ipp_everywhere = !strncmp(var, "ipp://", 6) || !strncmp(var, "ipps://", 7) || (!strncmp(var, "dnssd://", 8) && (strstr(var, "_ipp._tcp") || strstr(var, "_ipps._tcp"))); |
936 | ||
bf3816c7 | 937 | if (modify && !cgiGetVariable("SELECT_MAKE")) |
ef416fc2 | 938 | { |
939 | /* | |
940 | * Get the PPD file... | |
941 | */ | |
942 | ||
943 | int fd; /* PPD file */ | |
944 | char filename[1024]; /* PPD filename */ | |
945 | ppd_file_t *ppd; /* PPD information */ | |
946 | char buffer[1024]; /* Buffer */ | |
7e86f2f6 | 947 | ssize_t bytes; /* Number of bytes */ |
ef416fc2 | 948 | http_status_t get_status; /* Status of GET */ |
949 | ||
950 | ||
a4d04587 | 951 | /* TODO: Use cupsGetFile() API... */ |
ef416fc2 | 952 | snprintf(uri, sizeof(uri), "/printers/%s.ppd", name); |
953 | ||
954 | if (httpGet(http, uri)) | |
955 | httpGet(http, uri); | |
956 | ||
957 | while ((get_status = httpUpdate(http)) == HTTP_CONTINUE); | |
958 | ||
959 | if (get_status != HTTP_OK) | |
960 | { | |
178cb736 MS |
961 | httpFlush(http); |
962 | ||
ef416fc2 | 963 | fprintf(stderr, "ERROR: Unable to get PPD file %s: %d - %s\n", |
964 | uri, get_status, httpStatus(get_status)); | |
965 | } | |
966 | else if ((fd = cupsTempFd(filename, sizeof(filename))) >= 0) | |
967 | { | |
a4d04587 | 968 | while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0) |
7e86f2f6 | 969 | write(fd, buffer, (size_t)bytes); |
ef416fc2 | 970 | |
971 | close(fd); | |
972 | ||
973 | if ((ppd = ppdOpenFile(filename)) != NULL) | |
974 | { | |
975 | if (ppd->manufacturer) | |
976 | cgiSetVariable("CURRENT_MAKE", ppd->manufacturer); | |
977 | ||
978 | if (ppd->nickname) | |
979 | cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd->nickname); | |
980 | ||
981 | ppdClose(ppd); | |
982 | unlink(filename); | |
983 | } | |
984 | else | |
985 | { | |
7e86f2f6 MS |
986 | int linenum; /* Line number */ |
987 | ||
ef416fc2 | 988 | fprintf(stderr, "ERROR: Unable to open PPD file %s: %s\n", |
7e86f2f6 | 989 | filename, ppdErrorString(ppdLastError(&linenum))); |
ef416fc2 | 990 | } |
991 | } | |
992 | else | |
993 | { | |
994 | httpFlush(http); | |
995 | ||
996 | fprintf(stderr, | |
997 | "ERROR: Unable to create temporary file for PPD file: %s\n", | |
998 | strerror(errno)); | |
999 | } | |
1000 | } | |
ef416fc2 | 1001 | |
1002 | /* | |
1003 | * Build a CUPS_GET_PPDS request, which requires the following | |
1004 | * attributes: | |
1005 | * | |
1006 | * attributes-charset | |
1007 | * attributes-natural-language | |
1008 | * printer-uri | |
1009 | */ | |
1010 | ||
fa73b229 | 1011 | request = ippNewRequest(CUPS_GET_PPDS); |
ef416fc2 | 1012 | |
1013 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", | |
1014 | NULL, "ipp://localhost/printers/"); | |
1015 | ||
c7017ecc MS |
1016 | if ((var = cgiGetVariable("PPD_MAKE")) == NULL) |
1017 | var = cgiGetVariable("CURRENT_MAKE"); | |
bf3816c7 | 1018 | if (var && !cgiGetVariable("SELECT_MAKE")) |
58dc1933 | 1019 | { |
e4572d57 MS |
1020 | const char *make_model; /* Make and model */ |
1021 | ||
1022 | ||
ef416fc2 | 1023 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT, |
1024 | "ppd-make", NULL, var); | |
58dc1933 | 1025 | |
bf3816c7 | 1026 | if ((make_model = cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL) |
58dc1933 | 1027 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT, |
e4572d57 | 1028 | "ppd-make-and-model", NULL, make_model); |
58dc1933 | 1029 | } |
ef416fc2 | 1030 | else |
1031 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, | |
1032 | "requested-attributes", NULL, "ppd-make"); | |
1033 | ||
1034 | /* | |
1035 | * Do the request and get back a response... | |
1036 | */ | |
1037 | ||
1038 | if ((response = cupsDoRequest(http, request, "/")) != NULL) | |
1039 | { | |
1040 | /* | |
1041 | * Got the list of PPDs, see if the user has selected a make... | |
1042 | */ | |
1043 | ||
ef55b745 | 1044 | if (cgiSetIPPVars(response, NULL, NULL, NULL, 0) == 0 && !modify) |
ef416fc2 | 1045 | { |
1046 | /* | |
89d46774 | 1047 | * No PPD files with this make, try again with all makes... |
ef416fc2 | 1048 | */ |
1049 | ||
89d46774 | 1050 | ippDelete(response); |
1051 | ||
1052 | request = ippNewRequest(CUPS_GET_PPDS); | |
1053 | ||
1054 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", | |
1055 | NULL, "ipp://localhost/printers/"); | |
1056 | ||
1057 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, | |
1058 | "requested-attributes", NULL, "ppd-make"); | |
ef416fc2 | 1059 | |
89d46774 | 1060 | if ((response = cupsDoRequest(http, request, "/")) != NULL) |
1061 | cgiSetIPPVars(response, NULL, NULL, NULL, 0); | |
1062 | ||
1063 | cgiStartHTML(title); | |
1064 | cgiCopyTemplateLang("choose-make.tmpl"); | |
1065 | cgiEndHTML(); | |
1066 | } | |
2e4ff8af | 1067 | else if (!var || cgiGetVariable("SELECT_MAKE")) |
89d46774 | 1068 | { |
ef416fc2 | 1069 | cgiStartHTML(title); |
1070 | cgiCopyTemplateLang("choose-make.tmpl"); | |
1071 | cgiEndHTML(); | |
1072 | } | |
1073 | else | |
1074 | { | |
1075 | /* | |
1076 | * Let the user choose a model... | |
1077 | */ | |
1078 | ||
ef416fc2 | 1079 | cgiStartHTML(title); |
ef55b745 MS |
1080 | if (!cgiGetVariable("PPD_MAKE")) |
1081 | cgiSetVariable("PPD_MAKE", cgiGetVariable("CURRENT_MAKE")); | |
553f29c9 MS |
1082 | if (ipp_everywhere) |
1083 | cgiSetVariable("SHOW_IPP_EVERYWHERE", "1"); | |
ef416fc2 | 1084 | cgiCopyTemplateLang("choose-model.tmpl"); |
1085 | cgiEndHTML(); | |
1086 | } | |
1087 | ||
ef416fc2 | 1088 | ippDelete(response); |
1089 | } | |
1090 | else | |
1091 | { | |
ef416fc2 | 1092 | cgiStartHTML(title); |
f3c17241 | 1093 | cgiShowIPPError(_("Unable to get list of printer drivers")); |
ef416fc2 | 1094 | cgiCopyTemplateLang("error.tmpl"); |
1095 | cgiEndHTML(); | |
1096 | } | |
1097 | } | |
1098 | else | |
1099 | { | |
1100 | /* | |
1101 | * Build a CUPS_ADD_PRINTER request, which requires the following | |
1102 | * attributes: | |
1103 | * | |
1104 | * attributes-charset | |
1105 | * attributes-natural-language | |
1106 | * printer-uri | |
1107 | * printer-location | |
1108 | * printer-info | |
1109 | * ppd-name | |
1110 | * device-uri | |
1111 | * printer-is-accepting-jobs | |
c5571a1d | 1112 | * printer-is-shared |
ef416fc2 | 1113 | * printer-state |
1114 | */ | |
1115 | ||
fa73b229 | 1116 | request = ippNewRequest(CUPS_ADD_PRINTER); |
ef416fc2 | 1117 | |
a4d04587 | 1118 | httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, |
1119 | "localhost", 0, "/printers/%s", | |
1120 | cgiGetVariable("PRINTER_NAME")); | |
ef416fc2 | 1121 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", |
1122 | NULL, uri); | |
1123 | ||
ef416fc2 | 1124 | if (!file) |
0af14961 MS |
1125 | { |
1126 | var = cgiGetVariable("PPD_NAME"); | |
11055349 | 1127 | if (strcmp(var, "__no_change__")) |
b0f26938 | 1128 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name", |
0af14961 MS |
1129 | NULL, var); |
1130 | } | |
ef416fc2 | 1131 | |
b0f26938 MS |
1132 | ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location", |
1133 | NULL, cgiGetVariable("PRINTER_LOCATION")); | |
1134 | ||
1135 | ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info", | |
1136 | NULL, cgiGetVariable("PRINTER_INFO")); | |
1137 | ||
ef416fc2 | 1138 | strlcpy(uri, cgiGetVariable("DEVICE_URI"), sizeof(uri)); |
1139 | ||
1140 | /* | |
1141 | * Strip make and model from URI... | |
1142 | */ | |
1143 | ||
1144 | if ((uriptr = strrchr(uri, '|')) != NULL) | |
1145 | *uriptr = '\0'; | |
1146 | ||
fa73b229 | 1147 | if (!strncmp(uri, "serial:", 7)) |
ef416fc2 | 1148 | { |
1149 | /* | |
1150 | * Update serial port URI to include baud rate, etc. | |
1151 | */ | |
1152 | ||
1153 | if ((uriptr = strchr(uri, '?')) == NULL) | |
1154 | uriptr = uri + strlen(uri); | |
1155 | ||
7e86f2f6 | 1156 | snprintf(uriptr, sizeof(uri) - (size_t)(uriptr - uri), |
ef416fc2 | 1157 | "?baud=%s+bits=%s+parity=%s+flow=%s", |
1158 | cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"), | |
1159 | cgiGetVariable("PARITY"), cgiGetVariable("FLOW")); | |
1160 | } | |
1161 | ||
1162 | ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", | |
1163 | NULL, uri); | |
1164 | ||
1165 | ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1); | |
1166 | ||
c5571a1d MS |
1167 | var = cgiGetVariable("printer_is_shared"); |
1168 | ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-shared", | |
1169 | var && (!strcmp(var, "1") || !strcmp(var, "on"))); | |
1170 | ||
ef416fc2 | 1171 | ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", |
1172 | IPP_PRINTER_IDLE); | |
1173 | ||
1174 | /* | |
1175 | * Do the request and get back a response... | |
1176 | */ | |
1177 | ||
1178 | if (file) | |
fa73b229 | 1179 | ippDelete(cupsDoFileRequest(http, request, "/admin/", file->tempfile)); |
fb2d5470 MS |
1180 | else if (evefile[0]) |
1181 | { | |
1182 | ippDelete(cupsDoFileRequest(http, request, "/admin/", evefile)); | |
1183 | unlink(evefile); | |
1184 | } | |
ef416fc2 | 1185 | else |
fa73b229 | 1186 | ippDelete(cupsDoRequest(http, request, "/admin/")); |
ef416fc2 | 1187 | |
355e94dc MS |
1188 | if (cupsLastError() == IPP_NOT_AUTHORIZED) |
1189 | { | |
1190 | puts("Status: 401\n"); | |
1191 | exit(0); | |
1192 | } | |
1193 | else if (cupsLastError() > IPP_OK_CONFLICT) | |
ef416fc2 | 1194 | { |
1195 | cgiStartHTML(title); | |
f3c17241 MS |
1196 | cgiShowIPPError(modify ? _("Unable to modify printer") : |
1197 | _("Unable to add printer")); | |
ef416fc2 | 1198 | } |
2e4ff8af | 1199 | else if (modify) |
ef416fc2 | 1200 | { |
1201 | /* | |
2e4ff8af | 1202 | * Redirect successful updates back to the printer page... |
ef416fc2 | 1203 | */ |
1204 | ||
1205 | char refresh[1024]; /* Refresh URL */ | |
1206 | ||
1207 | ||
1208 | cgiFormEncode(uri, name, sizeof(uri)); | |
1209 | ||
2e4ff8af MS |
1210 | snprintf(refresh, sizeof(refresh), |
1211 | "5;/admin/?OP=redirect&URL=/printers/%s", uri); | |
ef416fc2 | 1212 | |
1213 | cgiSetVariable("refresh_page", refresh); | |
1214 | ||
1215 | cgiStartHTML(title); | |
1216 | ||
2e4ff8af MS |
1217 | cgiCopyTemplateLang("printer-modified.tmpl"); |
1218 | } | |
1219 | else | |
1220 | { | |
1221 | /* | |
1222 | * Set the printer options... | |
1223 | */ | |
1224 | ||
1225 | cgiSetVariable("OP", "set-printer-options"); | |
1226 | do_set_options(http, 0); | |
1227 | return; | |
ef416fc2 | 1228 | } |
1229 | ||
1230 | cgiEndHTML(); | |
1231 | } | |
1232 | ||
1233 | if (oldinfo) | |
1234 | ippDelete(oldinfo); | |
1235 | } | |
1236 | ||
1237 | ||
1238 | /* | |
323c5de1 | 1239 | * 'do_config_server()' - Configure server settings. |
ef416fc2 | 1240 | */ |
1241 | ||
1242 | static void | |
323c5de1 | 1243 | do_config_server(http_t *http) /* I - HTTP connection */ |
ef416fc2 | 1244 | { |
2e4ff8af | 1245 | if (cgiGetVariable("CHANGESETTINGS")) |
ef416fc2 | 1246 | { |
323c5de1 | 1247 | /* |
1248 | * Save basic setting changes... | |
1249 | */ | |
ef416fc2 | 1250 | |
323c5de1 | 1251 | int num_settings; /* Number of server settings */ |
1252 | cups_option_t *settings; /* Server settings */ | |
0af14961 MS |
1253 | int advanced, /* Advanced settings shown? */ |
1254 | changed; /* Have settings changed? */ | |
323c5de1 | 1255 | const char *debug_logging, /* DEBUG_LOGGING value */ |
82cc1f9a MS |
1256 | *preserve_jobs = NULL, |
1257 | /* PRESERVE_JOBS value */ | |
323c5de1 | 1258 | *remote_admin, /* REMOTE_ADMIN value */ |
1259 | *remote_any, /* REMOTE_ANY value */ | |
323c5de1 | 1260 | *share_printers,/* SHARE_PRINTERS value */ |
0af14961 | 1261 | *user_cancel_any, |
ac884b6a | 1262 | /* USER_CANCEL_ANY value */ |
bf3816c7 MS |
1263 | *browse_web_if = NULL, |
1264 | /* BrowseWebIF value */ | |
1265 | *preserve_job_history = NULL, | |
0af14961 | 1266 | /* PreserveJobHistory value */ |
bf3816c7 | 1267 | *preserve_job_files = NULL, |
0af14961 | 1268 | /* PreserveJobFiles value */ |
bf3816c7 MS |
1269 | *max_clients = NULL, |
1270 | /* MaxClients value */ | |
1271 | *max_jobs = NULL, | |
1272 | /* MaxJobs value */ | |
1273 | *max_log_size = NULL; | |
1274 | /* MaxLogSize value */ | |
58dc1933 MS |
1275 | const char *current_browse_web_if, |
1276 | /* BrowseWebIF value */ | |
1277 | *current_preserve_job_history, | |
1278 | /* PreserveJobHistory value */ | |
1279 | *current_preserve_job_files, | |
1280 | /* PreserveJobFiles value */ | |
1281 | *current_max_clients, | |
1282 | /* MaxClients value */ | |
1283 | *current_max_jobs, | |
1284 | /* MaxJobs value */ | |
a2326b5b | 1285 | *current_max_log_size; |
58dc1933 | 1286 | /* MaxLogSize value */ |
323c5de1 | 1287 | #ifdef HAVE_GSSAPI |
ac884b6a | 1288 | char default_auth_type[255]; |
323c5de1 | 1289 | /* DefaultAuthType value */ |
ef55b745 | 1290 | const char *val; /* Setting value */ |
323c5de1 | 1291 | #endif /* HAVE_GSSAPI */ |
bd7854cb | 1292 | |
ef416fc2 | 1293 | |
323c5de1 | 1294 | /* |
1295 | * Get the checkbox values from the form... | |
1296 | */ | |
bd7854cb | 1297 | |
0af14961 MS |
1298 | debug_logging = cgiGetVariable("DEBUG_LOGGING") ? "1" : "0"; |
1299 | remote_admin = cgiGetVariable("REMOTE_ADMIN") ? "1" : "0"; | |
1300 | remote_any = cgiGetVariable("REMOTE_ANY") ? "1" : "0"; | |
0af14961 MS |
1301 | share_printers = cgiGetVariable("SHARE_PRINTERS") ? "1" : "0"; |
1302 | user_cancel_any = cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0"; | |
1303 | ||
1304 | advanced = cgiGetVariable("ADVANCEDSETTINGS") != NULL; | |
1305 | if (advanced) | |
1306 | { | |
1307 | /* | |
1308 | * Get advanced settings... | |
1309 | */ | |
1310 | ||
1311 | browse_web_if = cgiGetVariable("BROWSE_WEB_IF") ? "Yes" : "No"; | |
1f6f3dbc | 1312 | max_clients = cgiGetVariable("MAX_CLIENTS"); |
0af14961 | 1313 | max_log_size = cgiGetVariable("MAX_LOG_SIZE"); |
82cc1f9a MS |
1314 | preserve_jobs = cgiGetVariable("PRESERVE_JOBS"); |
1315 | ||
1316 | if (preserve_jobs) | |
1317 | { | |
1318 | max_jobs = cgiGetVariable("MAX_JOBS"); | |
1319 | preserve_job_history = cgiGetVariable("PRESERVE_JOB_HISTORY"); | |
1320 | preserve_job_files = cgiGetVariable("PRESERVE_JOB_FILES"); | |
1321 | ||
1322 | if (!max_jobs || atoi(max_jobs) < 0) | |
1323 | max_jobs = "500"; | |
1324 | ||
1325 | if (!preserve_job_history) | |
1326 | preserve_job_history = "On"; | |
1327 | ||
1328 | if (!preserve_job_files) | |
1329 | preserve_job_files = "1d"; | |
1330 | } | |
1331 | else | |
1332 | { | |
1333 | max_jobs = "0"; | |
1334 | preserve_job_history = "No"; | |
1335 | preserve_job_files = "No"; | |
1336 | } | |
0af14961 | 1337 | |
1f6f3dbc MS |
1338 | if (!max_clients || atoi(max_clients) <= 0) |
1339 | max_clients = "100"; | |
1340 | ||
82cc1f9a | 1341 | if (!max_log_size || atoi(max_log_size) <= 0.0) |
0af14961 | 1342 | max_log_size = "1m"; |
0af14961 | 1343 | } |
bd7854cb | 1344 | |
323c5de1 | 1345 | /* |
1346 | * Get the current server settings... | |
1347 | */ | |
ef416fc2 | 1348 | |
323c5de1 | 1349 | if (!cupsAdminGetServerSettings(http, &num_settings, &settings)) |
1350 | { | |
1351 | cgiStartHTML(cgiText(_("Change Settings"))); | |
1352 | cgiSetVariable("MESSAGE", | |
f3c17241 | 1353 | cgiText(_("Unable to change server settings"))); |
323c5de1 | 1354 | cgiSetVariable("ERROR", cupsLastErrorString()); |
1355 | cgiCopyTemplateLang("error.tmpl"); | |
1356 | cgiEndHTML(); | |
1357 | return; | |
1358 | } | |
ef416fc2 | 1359 | |
0a682745 MS |
1360 | #ifdef HAVE_GSSAPI |
1361 | /* | |
1362 | * Get authentication settings... | |
1363 | */ | |
1364 | ||
1365 | if (cgiGetVariable("KERBEROS")) | |
ac884b6a | 1366 | strlcpy(default_auth_type, "Negotiate", sizeof(default_auth_type)); |
0a682745 MS |
1367 | else |
1368 | { | |
0af14961 | 1369 | val = cupsGetOption("DefaultAuthType", num_settings, settings); |
ac884b6a | 1370 | |
88f9aafc | 1371 | if (!val || !_cups_strcasecmp(val, "Negotiate")) |
ac884b6a MS |
1372 | strlcpy(default_auth_type, "Basic", sizeof(default_auth_type)); |
1373 | else | |
1374 | strlcpy(default_auth_type, val, sizeof(default_auth_type)); | |
0a682745 MS |
1375 | } |
1376 | ||
1377 | fprintf(stderr, "DEBUG: DefaultAuthType %s\n", default_auth_type); | |
1378 | #endif /* HAVE_GSSAPI */ | |
1379 | ||
58dc1933 MS |
1380 | if ((current_browse_web_if = cupsGetOption("BrowseWebIF", num_settings, |
1381 | settings)) == NULL) | |
1382 | current_browse_web_if = "No"; | |
1383 | ||
1384 | if ((current_preserve_job_history = cupsGetOption("PreserveJobHistory", | |
1385 | num_settings, | |
1386 | settings)) == NULL) | |
1387 | current_preserve_job_history = "Yes"; | |
1388 | ||
1389 | if ((current_preserve_job_files = cupsGetOption("PreserveJobFiles", | |
1390 | num_settings, | |
1391 | settings)) == NULL) | |
82cc1f9a | 1392 | current_preserve_job_files = "1d"; |
58dc1933 MS |
1393 | |
1394 | if ((current_max_clients = cupsGetOption("MaxClients", num_settings, | |
1395 | settings)) == NULL) | |
1396 | current_max_clients = "100"; | |
1397 | ||
1398 | if ((current_max_jobs = cupsGetOption("MaxJobs", num_settings, | |
1399 | settings)) == NULL) | |
1400 | current_max_jobs = "500"; | |
1401 | ||
1402 | if ((current_max_log_size = cupsGetOption("MaxLogSize", num_settings, | |
1403 | settings)) == NULL) | |
1404 | current_max_log_size = "1m"; | |
1405 | ||
323c5de1 | 1406 | /* |
1407 | * See if the settings have changed... | |
1408 | */ | |
1409 | ||
0af14961 MS |
1410 | changed = strcmp(debug_logging, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, |
1411 | num_settings, settings)) || | |
1412 | strcmp(remote_admin, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, | |
1413 | num_settings, settings)) || | |
1414 | strcmp(remote_any, cupsGetOption(CUPS_SERVER_REMOTE_ANY, | |
1415 | num_settings, settings)) || | |
0af14961 MS |
1416 | strcmp(share_printers, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, |
1417 | num_settings, settings)) || | |
323c5de1 | 1418 | #ifdef HAVE_GSSAPI |
0af14961 MS |
1419 | !cupsGetOption("DefaultAuthType", num_settings, settings) || |
1420 | strcmp(default_auth_type, cupsGetOption("DefaultAuthType", | |
1421 | num_settings, settings)) || | |
323c5de1 | 1422 | #endif /* HAVE_GSSAPI */ |
0af14961 MS |
1423 | strcmp(user_cancel_any, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, |
1424 | num_settings, settings)); | |
1425 | ||
1426 | if (advanced && !changed) | |
a2326b5b | 1427 | changed = _cups_strcasecmp(browse_web_if, current_browse_web_if) || |
88f9aafc MS |
1428 | _cups_strcasecmp(preserve_job_history, current_preserve_job_history) || |
1429 | _cups_strcasecmp(preserve_job_files, current_preserve_job_files) || | |
1430 | _cups_strcasecmp(max_clients, current_max_clients) || | |
1431 | _cups_strcasecmp(max_jobs, current_max_jobs) || | |
1432 | _cups_strcasecmp(max_log_size, current_max_log_size); | |
0af14961 MS |
1433 | |
1434 | if (changed) | |
323c5de1 | 1435 | { |
1436 | /* | |
1437 | * Settings *have* changed, so save the changes... | |
1438 | */ | |
ef416fc2 | 1439 | |
323c5de1 | 1440 | cupsFreeOptions(num_settings, settings); |
ef416fc2 | 1441 | |
323c5de1 | 1442 | num_settings = 0; |
1443 | num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING, | |
1444 | debug_logging, num_settings, &settings); | |
1445 | num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN, | |
1446 | remote_admin, num_settings, &settings); | |
1447 | num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY, | |
1448 | remote_any, num_settings, &settings); | |
323c5de1 | 1449 | num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS, |
1450 | share_printers, num_settings, &settings); | |
1451 | num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY, | |
1452 | user_cancel_any, num_settings, &settings); | |
1453 | #ifdef HAVE_GSSAPI | |
1454 | num_settings = cupsAddOption("DefaultAuthType", default_auth_type, | |
1455 | num_settings, &settings); | |
1456 | #endif /* HAVE_GSSAPI */ | |
ef416fc2 | 1457 | |
0af14961 MS |
1458 | if (advanced) |
1459 | { | |
1460 | /* | |
1461 | * Add advanced settings... | |
1462 | */ | |
1463 | ||
88f9aafc | 1464 | if (_cups_strcasecmp(browse_web_if, current_browse_web_if)) |
0af14961 MS |
1465 | num_settings = cupsAddOption("BrowseWebIF", browse_web_if, |
1466 | num_settings, &settings); | |
88f9aafc | 1467 | if (_cups_strcasecmp(preserve_job_history, current_preserve_job_history)) |
0af14961 MS |
1468 | num_settings = cupsAddOption("PreserveJobHistory", |
1469 | preserve_job_history, num_settings, | |
1470 | &settings); | |
88f9aafc | 1471 | if (_cups_strcasecmp(preserve_job_files, current_preserve_job_files)) |
0af14961 MS |
1472 | num_settings = cupsAddOption("PreserveJobFiles", preserve_job_files, |
1473 | num_settings, &settings); | |
88f9aafc | 1474 | if (_cups_strcasecmp(max_clients, current_max_clients)) |
1f6f3dbc MS |
1475 | num_settings = cupsAddOption("MaxClients", max_clients, num_settings, |
1476 | &settings); | |
88f9aafc | 1477 | if (_cups_strcasecmp(max_jobs, current_max_jobs)) |
0af14961 MS |
1478 | num_settings = cupsAddOption("MaxJobs", max_jobs, num_settings, |
1479 | &settings); | |
88f9aafc | 1480 | if (_cups_strcasecmp(max_log_size, current_max_log_size)) |
0af14961 MS |
1481 | num_settings = cupsAddOption("MaxLogSize", max_log_size, num_settings, |
1482 | &settings); | |
1483 | } | |
1484 | ||
323c5de1 | 1485 | if (!cupsAdminSetServerSettings(http, num_settings, settings)) |
ef416fc2 | 1486 | { |
355e94dc MS |
1487 | if (cupsLastError() == IPP_NOT_AUTHORIZED) |
1488 | { | |
1489 | puts("Status: 401\n"); | |
1490 | exit(0); | |
1491 | } | |
1492 | ||
323c5de1 | 1493 | cgiStartHTML(cgiText(_("Change Settings"))); |
1494 | cgiSetVariable("MESSAGE", | |
f3c17241 | 1495 | cgiText(_("Unable to change server settings"))); |
323c5de1 | 1496 | cgiSetVariable("ERROR", cupsLastErrorString()); |
1497 | cgiCopyTemplateLang("error.tmpl"); | |
ef416fc2 | 1498 | } |
ef416fc2 | 1499 | else |
323c5de1 | 1500 | { |
58dc1933 | 1501 | if (advanced) |
a2326b5b MS |
1502 | cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&" |
1503 | "URL=/admin/?ADVANCEDSETTINGS=YES"); | |
58dc1933 MS |
1504 | else |
1505 | cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect"); | |
323c5de1 | 1506 | cgiStartHTML(cgiText(_("Change Settings"))); |
1507 | cgiCopyTemplateLang("restart.tmpl"); | |
1508 | } | |
1509 | } | |
1510 | else | |
1511 | { | |
1512 | /* | |
1513 | * No changes... | |
1514 | */ | |
ef416fc2 | 1515 | |
323c5de1 | 1516 | cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect"); |
1517 | cgiStartHTML(cgiText(_("Change Settings"))); | |
1518 | cgiCopyTemplateLang("norestart.tmpl"); | |
1519 | } | |
ef416fc2 | 1520 | |
323c5de1 | 1521 | cupsFreeOptions(num_settings, settings); |
ef416fc2 | 1522 | |
323c5de1 | 1523 | cgiEndHTML(); |
1524 | } | |
2e4ff8af | 1525 | else if (cgiGetVariable("SAVECHANGES") && cgiGetVariable("CUPSDCONF")) |
ef416fc2 | 1526 | { |
1527 | /* | |
323c5de1 | 1528 | * Save hand-edited config file... |
ef416fc2 | 1529 | */ |
1530 | ||
323c5de1 | 1531 | http_status_t status; /* PUT status */ |
1532 | char tempfile[1024]; /* Temporary new cupsd.conf */ | |
1533 | int tempfd; /* Temporary file descriptor */ | |
1534 | cups_file_t *temp; /* Temporary file */ | |
1535 | const char *start, /* Start of line */ | |
1536 | *end; /* End of line */ | |
bd7854cb | 1537 | |
fa73b229 | 1538 | |
323c5de1 | 1539 | /* |
1540 | * Create a temporary file for the new cupsd.conf file... | |
1541 | */ | |
ef416fc2 | 1542 | |
323c5de1 | 1543 | if ((tempfd = cupsTempFd(tempfile, sizeof(tempfile))) < 0) |
ef416fc2 | 1544 | { |
323c5de1 | 1545 | cgiStartHTML(cgiText(_("Edit Configuration File"))); |
f3c17241 | 1546 | cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file"))); |
323c5de1 | 1547 | cgiSetVariable("ERROR", strerror(errno)); |
1548 | cgiCopyTemplateLang("error.tmpl"); | |
1549 | cgiEndHTML(); | |
ef55b745 | 1550 | |
323c5de1 | 1551 | perror(tempfile); |
1552 | return; | |
ef416fc2 | 1553 | } |
1554 | ||
323c5de1 | 1555 | if ((temp = cupsFileOpenFd(tempfd, "w")) == NULL) |
ef416fc2 | 1556 | { |
323c5de1 | 1557 | cgiStartHTML(cgiText(_("Edit Configuration File"))); |
f3c17241 | 1558 | cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file"))); |
323c5de1 | 1559 | cgiSetVariable("ERROR", strerror(errno)); |
1560 | cgiCopyTemplateLang("error.tmpl"); | |
1561 | cgiEndHTML(); | |
ef55b745 | 1562 | |
323c5de1 | 1563 | perror(tempfile); |
1564 | close(tempfd); | |
1565 | unlink(tempfile); | |
1566 | return; | |
1567 | } | |
ef416fc2 | 1568 | |
323c5de1 | 1569 | /* |
1570 | * Copy the cupsd.conf text from the form variable... | |
1571 | */ | |
ef416fc2 | 1572 | |
323c5de1 | 1573 | start = cgiGetVariable("CUPSDCONF"); |
1574 | while (start) | |
1575 | { | |
1576 | if ((end = strstr(start, "\r\n")) == NULL) | |
1577 | if ((end = strstr(start, "\n")) == NULL) | |
1578 | end = start + strlen(start); | |
ef416fc2 | 1579 | |
7e86f2f6 | 1580 | cupsFileWrite(temp, start, (size_t)(end - start)); |
323c5de1 | 1581 | cupsFilePutChar(temp, '\n'); |
ef416fc2 | 1582 | |
323c5de1 | 1583 | if (*end == '\r') |
1584 | start = end + 2; | |
1585 | else if (*end == '\n') | |
1586 | start = end + 1; | |
1587 | else | |
1588 | start = NULL; | |
1589 | } | |
ef416fc2 | 1590 | |
323c5de1 | 1591 | cupsFileClose(temp); |
ef416fc2 | 1592 | |
323c5de1 | 1593 | /* |
1594 | * Upload the configuration file to the server... | |
1595 | */ | |
ef416fc2 | 1596 | |
323c5de1 | 1597 | status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile); |
ef416fc2 | 1598 | |
355e94dc MS |
1599 | if (status == HTTP_UNAUTHORIZED) |
1600 | { | |
1601 | puts("Status: 401\n"); | |
1602 | unlink(tempfile); | |
1603 | exit(0); | |
1604 | } | |
1605 | else if (status != HTTP_CREATED) | |
323c5de1 | 1606 | { |
1607 | cgiSetVariable("MESSAGE", | |
f3c17241 | 1608 | cgiText(_("Unable to upload cupsd.conf file"))); |
323c5de1 | 1609 | cgiSetVariable("ERROR", httpStatus(status)); |
1610 | ||
1611 | cgiStartHTML(cgiText(_("Edit Configuration File"))); | |
1612 | cgiCopyTemplateLang("error.tmpl"); | |
1613 | } | |
1614 | else | |
1615 | { | |
3bc376ee | 1616 | cgiSetVariable("refresh_page", "5;URL=/admin/"); |
323c5de1 | 1617 | |
1618 | cgiStartHTML(cgiText(_("Edit Configuration File"))); | |
1619 | cgiCopyTemplateLang("restart.tmpl"); | |
ef416fc2 | 1620 | } |
1621 | ||
323c5de1 | 1622 | cgiEndHTML(); |
1623 | ||
1624 | unlink(tempfile); | |
1625 | } | |
1626 | else | |
1627 | { | |
1628 | struct stat info; /* cupsd.conf information */ | |
1629 | cups_file_t *cupsd; /* cupsd.conf file */ | |
355e94dc MS |
1630 | char *buffer, /* Buffer for entire file */ |
1631 | *bufptr, /* Pointer into buffer */ | |
1632 | *bufend; /* End of buffer */ | |
1633 | int ch; /* Character from file */ | |
323c5de1 | 1634 | char filename[1024]; /* Filename */ |
1635 | const char *server_root; /* Location of config files */ | |
1636 | ||
1637 | ||
ef416fc2 | 1638 | /* |
323c5de1 | 1639 | * Locate the cupsd.conf file... |
ef416fc2 | 1640 | */ |
1641 | ||
323c5de1 | 1642 | if ((server_root = getenv("CUPS_SERVERROOT")) == NULL) |
1643 | server_root = CUPS_SERVERROOT; | |
ef416fc2 | 1644 | |
323c5de1 | 1645 | snprintf(filename, sizeof(filename), "%s/cupsd.conf", server_root); |
ef416fc2 | 1646 | |
1647 | /* | |
323c5de1 | 1648 | * Figure out the size... |
ef416fc2 | 1649 | */ |
1650 | ||
323c5de1 | 1651 | if (stat(filename, &info)) |
ef416fc2 | 1652 | { |
323c5de1 | 1653 | cgiStartHTML(cgiText(_("Edit Configuration File"))); |
1654 | cgiSetVariable("MESSAGE", | |
f3c17241 | 1655 | cgiText(_("Unable to access cupsd.conf file"))); |
323c5de1 | 1656 | cgiSetVariable("ERROR", strerror(errno)); |
1657 | cgiCopyTemplateLang("error.tmpl"); | |
1658 | cgiEndHTML(); | |
ef416fc2 | 1659 | |
323c5de1 | 1660 | perror(filename); |
1661 | return; | |
1662 | } | |
ef416fc2 | 1663 | |
323c5de1 | 1664 | if (info.st_size > (1024 * 1024)) |
1665 | { | |
1666 | cgiStartHTML(cgiText(_("Edit Configuration File"))); | |
1667 | cgiSetVariable("MESSAGE", | |
f3c17241 | 1668 | cgiText(_("Unable to access cupsd.conf file"))); |
323c5de1 | 1669 | cgiSetVariable("ERROR", |
1670 | cgiText(_("Unable to edit cupsd.conf files larger than " | |
4d301e69 | 1671 | "1MB"))); |
323c5de1 | 1672 | cgiCopyTemplateLang("error.tmpl"); |
1673 | cgiEndHTML(); | |
ef416fc2 | 1674 | |
323c5de1 | 1675 | fprintf(stderr, "ERROR: \"%s\" too large (%ld) to edit!\n", filename, |
1676 | (long)info.st_size); | |
1677 | return; | |
1678 | } | |
ef416fc2 | 1679 | |
323c5de1 | 1680 | /* |
1681 | * Open the cupsd.conf file... | |
1682 | */ | |
ef416fc2 | 1683 | |
323c5de1 | 1684 | if ((cupsd = cupsFileOpen(filename, "r")) == NULL) |
1685 | { | |
1686 | /* | |
1687 | * Unable to open - log an error... | |
1688 | */ | |
ef416fc2 | 1689 | |
323c5de1 | 1690 | cgiStartHTML(cgiText(_("Edit Configuration File"))); |
1691 | cgiSetVariable("MESSAGE", | |
f3c17241 | 1692 | cgiText(_("Unable to access cupsd.conf file"))); |
323c5de1 | 1693 | cgiSetVariable("ERROR", strerror(errno)); |
1694 | cgiCopyTemplateLang("error.tmpl"); | |
1695 | cgiEndHTML(); | |
ef416fc2 | 1696 | |
323c5de1 | 1697 | perror(filename); |
1698 | return; | |
1699 | } | |
ef416fc2 | 1700 | |
323c5de1 | 1701 | /* |
1702 | * Allocate memory and load the file into a string buffer... | |
1703 | */ | |
ef416fc2 | 1704 | |
7e86f2f6 | 1705 | if ((buffer = calloc(1, (size_t)info.st_size + 1)) != NULL) |
91c84a35 | 1706 | { |
7e86f2f6 | 1707 | cupsFileRead(cupsd, buffer, (size_t)info.st_size); |
91c84a35 MS |
1708 | cgiSetVariable("CUPSDCONF", buffer); |
1709 | free(buffer); | |
1710 | } | |
ef416fc2 | 1711 | |
323c5de1 | 1712 | cupsFileClose(cupsd); |
ef416fc2 | 1713 | |
355e94dc MS |
1714 | /* |
1715 | * Then get the default cupsd.conf file and put that into a string as | |
1716 | * well... | |
1717 | */ | |
1718 | ||
1719 | strlcat(filename, ".default", sizeof(filename)); | |
1720 | ||
1721 | if (!stat(filename, &info) && info.st_size < (1024 * 1024) && | |
1722 | (cupsd = cupsFileOpen(filename, "r")) != NULL) | |
1723 | { | |
7e86f2f6 | 1724 | if ((buffer = calloc(1, 2 * (size_t)info.st_size + 1)) != NULL) |
355e94dc | 1725 | { |
91c84a35 MS |
1726 | bufend = buffer + 2 * info.st_size - 1; |
1727 | ||
1728 | for (bufptr = buffer; | |
1729 | bufptr < bufend && (ch = cupsFileGetChar(cupsd)) != EOF;) | |
355e94dc | 1730 | { |
91c84a35 MS |
1731 | if (ch == '\\' || ch == '\"') |
1732 | { | |
1733 | *bufptr++ = '\\'; | |
7e86f2f6 | 1734 | *bufptr++ = (char)ch; |
91c84a35 MS |
1735 | } |
1736 | else if (ch == '\n') | |
1737 | { | |
1738 | *bufptr++ = '\\'; | |
1739 | *bufptr++ = 'n'; | |
1740 | } | |
1741 | else if (ch == '\t') | |
1742 | { | |
1743 | *bufptr++ = '\\'; | |
1744 | *bufptr++ = 't'; | |
1745 | } | |
1746 | else if (ch >= ' ') | |
7e86f2f6 | 1747 | *bufptr++ = (char)ch; |
355e94dc | 1748 | } |
355e94dc | 1749 | |
91c84a35 | 1750 | *bufptr = '\0'; |
355e94dc | 1751 | |
91c84a35 MS |
1752 | cgiSetVariable("CUPSDCONF_DEFAULT", buffer); |
1753 | free(buffer); | |
1754 | } | |
355e94dc | 1755 | |
91c84a35 | 1756 | cupsFileClose(cupsd); |
355e94dc MS |
1757 | } |
1758 | ||
323c5de1 | 1759 | /* |
1760 | * Show the current config file... | |
1761 | */ | |
ef416fc2 | 1762 | |
323c5de1 | 1763 | cgiStartHTML(cgiText(_("Edit Configuration File"))); |
ef416fc2 | 1764 | |
323c5de1 | 1765 | cgiCopyTemplateLang("edit-config.tmpl"); |
ef416fc2 | 1766 | |
323c5de1 | 1767 | cgiEndHTML(); |
1768 | } | |
1769 | } | |
ef416fc2 | 1770 | |
ef416fc2 | 1771 | |
323c5de1 | 1772 | /* |
749b1e90 | 1773 | * 'do_delete_class()' - Delete a class. |
323c5de1 | 1774 | */ |
ef416fc2 | 1775 | |
323c5de1 | 1776 | static void |
1777 | do_delete_class(http_t *http) /* I - HTTP connection */ | |
1778 | { | |
1779 | ipp_t *request; /* IPP request */ | |
1780 | char uri[HTTP_MAX_URI]; /* Job URI */ | |
1781 | const char *pclass; /* Printer class name */ | |
ef416fc2 | 1782 | |
ef416fc2 | 1783 | |
323c5de1 | 1784 | /* |
1785 | * Get form variables... | |
1786 | */ | |
ef416fc2 | 1787 | |
323c5de1 | 1788 | if (cgiGetVariable("CONFIRM") == NULL) |
1789 | { | |
1790 | cgiStartHTML(cgiText(_("Delete Class"))); | |
1791 | cgiCopyTemplateLang("class-confirm.tmpl"); | |
1792 | cgiEndHTML(); | |
1793 | return; | |
1794 | } | |
ef416fc2 | 1795 | |
323c5de1 | 1796 | if ((pclass = cgiGetVariable("PRINTER_NAME")) != NULL) |
1797 | httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, | |
1798 | "localhost", 0, "/classes/%s", pclass); | |
1799 | else | |
1800 | { | |
1801 | cgiStartHTML(cgiText(_("Delete Class"))); | |
4d301e69 | 1802 | cgiSetVariable("ERROR", cgiText(_("Missing form variable"))); |
323c5de1 | 1803 | cgiCopyTemplateLang("error.tmpl"); |
1804 | cgiEndHTML(); | |
1805 | return; | |
1806 | } | |
ef416fc2 | 1807 | |
323c5de1 | 1808 | /* |
1809 | * Build a CUPS_DELETE_CLASS request, which requires the following | |
1810 | * attributes: | |
1811 | * | |
1812 | * attributes-charset | |
1813 | * attributes-natural-language | |
1814 | * printer-uri | |
1815 | */ | |
1816 | ||
1817 | request = ippNewRequest(CUPS_DELETE_CLASS); | |
1818 | ||
1819 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", | |
1820 | NULL, uri); | |
1821 | ||
1822 | /* | |
1823 | * Do the request and get back a response... | |
1824 | */ | |
1825 | ||
1826 | ippDelete(cupsDoRequest(http, request, "/admin/")); | |
ef416fc2 | 1827 | |
323c5de1 | 1828 | /* |
1829 | * Show the results... | |
1830 | */ | |
1831 | ||
355e94dc MS |
1832 | if (cupsLastError() == IPP_NOT_AUTHORIZED) |
1833 | { | |
1834 | puts("Status: 401\n"); | |
1835 | exit(0); | |
1836 | } | |
1837 | else if (cupsLastError() <= IPP_OK_CONFLICT) | |
323c5de1 | 1838 | { |
ef416fc2 | 1839 | /* |
323c5de1 | 1840 | * Redirect successful updates back to the classes page... |
ef416fc2 | 1841 | */ |
1842 | ||
323c5de1 | 1843 | cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes"); |
1844 | } | |
ef416fc2 | 1845 | |
323c5de1 | 1846 | cgiStartHTML(cgiText(_("Delete Class"))); |
ef416fc2 | 1847 | |
323c5de1 | 1848 | if (cupsLastError() > IPP_OK_CONFLICT) |
f3c17241 | 1849 | cgiShowIPPError(_("Unable to delete class")); |
323c5de1 | 1850 | else |
1851 | cgiCopyTemplateLang("class-deleted.tmpl"); | |
ef416fc2 | 1852 | |
323c5de1 | 1853 | cgiEndHTML(); |
1854 | } | |
ef416fc2 | 1855 | |
ef416fc2 | 1856 | |
323c5de1 | 1857 | /* |
749b1e90 | 1858 | * 'do_delete_printer()' - Delete a printer. |
323c5de1 | 1859 | */ |
ef416fc2 | 1860 | |
323c5de1 | 1861 | static void |
1862 | do_delete_printer(http_t *http) /* I - HTTP connection */ | |
1863 | { | |
1864 | ipp_t *request; /* IPP request */ | |
1865 | char uri[HTTP_MAX_URI]; /* Job URI */ | |
1866 | const char *printer; /* Printer printer name */ | |
ef416fc2 | 1867 | |
323c5de1 | 1868 | |
1869 | /* | |
1870 | * Get form variables... | |
1871 | */ | |
1872 | ||
1873 | if (cgiGetVariable("CONFIRM") == NULL) | |
1874 | { | |
1875 | cgiStartHTML(cgiText(_("Delete Printer"))); | |
1876 | cgiCopyTemplateLang("printer-confirm.tmpl"); | |
ef416fc2 | 1877 | cgiEndHTML(); |
323c5de1 | 1878 | return; |
ef416fc2 | 1879 | } |
323c5de1 | 1880 | |
1881 | if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL) | |
1882 | httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, | |
1883 | "localhost", 0, "/printers/%s", printer); | |
ef416fc2 | 1884 | else |
323c5de1 | 1885 | { |
1886 | cgiStartHTML(cgiText(_("Delete Printer"))); | |
4d301e69 | 1887 | cgiSetVariable("ERROR", cgiText(_("Missing form variable"))); |
323c5de1 | 1888 | cgiCopyTemplateLang("error.tmpl"); |
1889 | cgiEndHTML(); | |
1890 | return; | |
1891 | } | |
1892 | ||
1893 | /* | |
1894 | * Build a CUPS_DELETE_PRINTER request, which requires the following | |
1895 | * attributes: | |
1896 | * | |
1897 | * attributes-charset | |
1898 | * attributes-natural-language | |
1899 | * printer-uri | |
1900 | */ | |
1901 | ||
1902 | request = ippNewRequest(CUPS_DELETE_PRINTER); | |
1903 | ||
1904 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", | |
1905 | NULL, uri); | |
1906 | ||
1907 | /* | |
1908 | * Do the request and get back a response... | |
1909 | */ | |
1910 | ||
1911 | ippDelete(cupsDoRequest(http, request, "/admin/")); | |
1912 | ||
1913 | /* | |
1914 | * Show the results... | |
1915 | */ | |
1916 | ||
355e94dc MS |
1917 | if (cupsLastError() == IPP_NOT_AUTHORIZED) |
1918 | { | |
1919 | puts("Status: 401\n"); | |
1920 | exit(0); | |
1921 | } | |
1922 | else if (cupsLastError() <= IPP_OK_CONFLICT) | |
ef416fc2 | 1923 | { |
1924 | /* | |
323c5de1 | 1925 | * Redirect successful updates back to the printers page... |
ef416fc2 | 1926 | */ |
1927 | ||
323c5de1 | 1928 | cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers"); |
1929 | } | |
bd7854cb | 1930 | |
323c5de1 | 1931 | cgiStartHTML(cgiText(_("Delete Printer"))); |
ef416fc2 | 1932 | |
323c5de1 | 1933 | if (cupsLastError() > IPP_OK_CONFLICT) |
f3c17241 | 1934 | cgiShowIPPError(_("Unable to delete printer")); |
323c5de1 | 1935 | else |
1936 | cgiCopyTemplateLang("printer-deleted.tmpl"); | |
ef416fc2 | 1937 | |
323c5de1 | 1938 | cgiEndHTML(); |
1939 | } | |
ef416fc2 | 1940 | |
ef416fc2 | 1941 | |
ef416fc2 | 1942 | /* |
749b1e90 | 1943 | * 'do_list_printers()' - List available printers. |
ef416fc2 | 1944 | */ |
1945 | ||
1946 | static void | |
323c5de1 | 1947 | do_list_printers(http_t *http) /* I - HTTP connection */ |
ef416fc2 | 1948 | { |
323c5de1 | 1949 | ipp_t *request, /* IPP request */ |
1950 | *response; /* IPP response */ | |
1951 | ipp_attribute_t *attr; /* IPP attribute */ | |
ef416fc2 | 1952 | |
757d2cad | 1953 | |
323c5de1 | 1954 | cgiStartHTML(cgiText(_("List Available Printers"))); |
1955 | fflush(stdout); | |
1956 | ||
1957 | /* | |
1958 | * Get the list of printers and their devices... | |
1959 | */ | |
1960 | ||
1961 | request = ippNewRequest(CUPS_GET_PRINTERS); | |
1962 | ||
1963 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, | |
1964 | "requested-attributes", NULL, "device-uri"); | |
1965 | ||
1966 | ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type", | |
1967 | CUPS_PRINTER_LOCAL); | |
1968 | ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type-mask", | |
1969 | CUPS_PRINTER_LOCAL); | |
757d2cad | 1970 | |
323c5de1 | 1971 | if ((response = cupsDoRequest(http, request, "/")) != NULL) |
1972 | { | |
d09495fa | 1973 | /* |
323c5de1 | 1974 | * Got the printer list, now load the devices... |
d09495fa | 1975 | */ |
1976 | ||
323c5de1 | 1977 | int i; /* Looping var */ |
1978 | cups_array_t *printer_devices; /* Printer devices for local printers */ | |
1979 | char *printer_device; /* Current printer device */ | |
7594b224 | 1980 | |
d09495fa | 1981 | |
1982 | /* | |
323c5de1 | 1983 | * Allocate an array and copy the device strings... |
d09495fa | 1984 | */ |
1985 | ||
323c5de1 | 1986 | printer_devices = cupsArrayNew((cups_array_func_t)strcmp, NULL); |
1987 | ||
1988 | for (attr = ippFindAttribute(response, "device-uri", IPP_TAG_URI); | |
1989 | attr; | |
1990 | attr = ippFindNextAttribute(response, "device-uri", IPP_TAG_URI)) | |
ef416fc2 | 1991 | { |
86c184ff | 1992 | cupsArrayAdd(printer_devices, strdup(attr->values[0].string.text)); |
d09495fa | 1993 | } |
1994 | ||
1995 | /* | |
323c5de1 | 1996 | * Free the printer list and get the device list... |
d09495fa | 1997 | */ |
1998 | ||
323c5de1 | 1999 | ippDelete(response); |
d09495fa | 2000 | |
323c5de1 | 2001 | request = ippNewRequest(CUPS_GET_DEVICES); |
d09495fa | 2002 | |
323c5de1 | 2003 | if ((response = cupsDoRequest(http, request, "/")) != NULL) |
ef416fc2 | 2004 | { |
d09495fa | 2005 | /* |
323c5de1 | 2006 | * Got the device list, let's parse it... |
d09495fa | 2007 | */ |
2008 | ||
323c5de1 | 2009 | const char *device_uri, /* device-uri attribute value */ |
2010 | *device_make_and_model, /* device-make-and-model value */ | |
2011 | *device_info; /* device-info value */ | |
ef416fc2 | 2012 | |
ef416fc2 | 2013 | |
323c5de1 | 2014 | for (i = 0, attr = response->attrs; attr; attr = attr->next) |
2015 | { | |
2016 | /* | |
2017 | * Skip leading attributes until we hit a device... | |
2018 | */ | |
ef416fc2 | 2019 | |
323c5de1 | 2020 | while (attr && attr->group_tag != IPP_TAG_PRINTER) |
2021 | attr = attr->next; | |
ef416fc2 | 2022 | |
323c5de1 | 2023 | if (!attr) |
2024 | break; | |
ef416fc2 | 2025 | |
323c5de1 | 2026 | /* |
2027 | * Pull the needed attributes from this device... | |
2028 | */ | |
ef416fc2 | 2029 | |
323c5de1 | 2030 | device_info = NULL; |
2031 | device_make_and_model = NULL; | |
2032 | device_uri = NULL; | |
ef416fc2 | 2033 | |
323c5de1 | 2034 | while (attr && attr->group_tag == IPP_TAG_PRINTER) |
2035 | { | |
2036 | if (!strcmp(attr->name, "device-info") && | |
2037 | attr->value_tag == IPP_TAG_TEXT) | |
2038 | device_info = attr->values[0].string.text; | |
ef416fc2 | 2039 | |
323c5de1 | 2040 | if (!strcmp(attr->name, "device-make-and-model") && |
2041 | attr->value_tag == IPP_TAG_TEXT) | |
2042 | device_make_and_model = attr->values[0].string.text; | |
ef416fc2 | 2043 | |
323c5de1 | 2044 | if (!strcmp(attr->name, "device-uri") && |
2045 | attr->value_tag == IPP_TAG_URI) | |
2046 | device_uri = attr->values[0].string.text; | |
ef416fc2 | 2047 | |
323c5de1 | 2048 | attr = attr->next; |
2049 | } | |
ef416fc2 | 2050 | |
323c5de1 | 2051 | /* |
2052 | * See if we have everything needed... | |
2053 | */ | |
ef416fc2 | 2054 | |
323c5de1 | 2055 | if (device_info && device_make_and_model && device_uri && |
88f9aafc | 2056 | _cups_strcasecmp(device_make_and_model, "unknown") && |
323c5de1 | 2057 | strchr(device_uri, ':')) |
2058 | { | |
2059 | /* | |
2060 | * Yes, now see if there is already a printer for this | |
2061 | * device... | |
2062 | */ | |
ef416fc2 | 2063 | |
323c5de1 | 2064 | if (!cupsArrayFind(printer_devices, (void *)device_uri)) |
2065 | { | |
2066 | /* | |
2067 | * Not found, so it must be a new printer... | |
2068 | */ | |
ef416fc2 | 2069 | |
2e4ff8af MS |
2070 | char option[1024], /* Form variables for this device */ |
2071 | *option_ptr; /* Pointer into string */ | |
323c5de1 | 2072 | const char *ptr; /* Pointer into device string */ |
ef416fc2 | 2073 | |
fa73b229 | 2074 | |
323c5de1 | 2075 | /* |
2076 | * Format the printer name variable for this device... | |
2077 | * | |
2078 | * We use the device-info string first, then device-uri, | |
2079 | * and finally device-make-and-model to come up with a | |
2080 | * suitable name. | |
2081 | */ | |
ef416fc2 | 2082 | |
88f9aafc | 2083 | if (_cups_strncasecmp(device_info, "unknown", 7)) |
323c5de1 | 2084 | ptr = device_info; |
2085 | else if ((ptr = strstr(device_uri, "://")) != NULL) | |
2086 | ptr += 3; | |
2087 | else | |
2088 | ptr = device_make_and_model; | |
ef416fc2 | 2089 | |
2e4ff8af MS |
2090 | for (option_ptr = option; |
2091 | option_ptr < (option + sizeof(option) - 1) && *ptr; | |
323c5de1 | 2092 | ptr ++) |
2093 | if (isalnum(*ptr & 255) || *ptr == '_' || *ptr == '-' || | |
2094 | *ptr == '.') | |
2e4ff8af | 2095 | *option_ptr++ = *ptr; |
e60ec91f MS |
2096 | else if ((*ptr == ' ' || *ptr == '/') && option_ptr > option && |
2097 | option_ptr[-1] != '_') | |
2e4ff8af | 2098 | *option_ptr++ = '_'; |
323c5de1 | 2099 | else if (*ptr == '?' || *ptr == '(') |
2100 | break; | |
ef416fc2 | 2101 | |
2e4ff8af | 2102 | *option_ptr = '\0'; |
ef416fc2 | 2103 | |
2e4ff8af | 2104 | cgiSetArray("TEMPLATE_NAME", i, option); |
ef416fc2 | 2105 | |
323c5de1 | 2106 | /* |
2107 | * Finally, set the form variables for this printer... | |
2108 | */ | |
ef416fc2 | 2109 | |
323c5de1 | 2110 | cgiSetArray("device_info", i, device_info); |
2111 | cgiSetArray("device_make_and_model", i, device_make_and_model); | |
323c5de1 | 2112 | cgiSetArray("device_uri", i, device_uri); |
2113 | i ++; | |
2114 | } | |
2115 | } | |
ef416fc2 | 2116 | |
323c5de1 | 2117 | if (!attr) |
2118 | break; | |
2119 | } | |
2120 | ||
2121 | ippDelete(response); | |
ef416fc2 | 2122 | |
ef416fc2 | 2123 | /* |
323c5de1 | 2124 | * Free the device list... |
ef416fc2 | 2125 | */ |
2126 | ||
323c5de1 | 2127 | for (printer_device = (char *)cupsArrayFirst(printer_devices); |
2128 | printer_device; | |
2129 | printer_device = (char *)cupsArrayNext(printer_devices)) | |
86c184ff | 2130 | free(printer_device); |
ef416fc2 | 2131 | |
323c5de1 | 2132 | cupsArrayDelete(printer_devices); |
ef416fc2 | 2133 | } |
323c5de1 | 2134 | } |
ef416fc2 | 2135 | |
323c5de1 | 2136 | /* |
2137 | * Finally, show the printer list... | |
2138 | */ | |
ef416fc2 | 2139 | |
323c5de1 | 2140 | cgiCopyTemplateLang("list-available-printers.tmpl"); |
ef416fc2 | 2141 | |
323c5de1 | 2142 | cgiEndHTML(); |
ef416fc2 | 2143 | } |
2144 | ||
2145 | ||
2146 | /* | |
749b1e90 | 2147 | * 'do_menu()' - Show the main menu. |
ef416fc2 | 2148 | */ |
2149 | ||
2150 | static void | |
323c5de1 | 2151 | do_menu(http_t *http) /* I - HTTP connection */ |
ef416fc2 | 2152 | { |
323c5de1 | 2153 | int num_settings; /* Number of server settings */ |
2154 | cups_option_t *settings; /* Server settings */ | |
2155 | const char *val; /* Setting value */ | |
ef416fc2 | 2156 | |
2157 | ||
89d46774 | 2158 | /* |
323c5de1 | 2159 | * Get the current server settings... |
89d46774 | 2160 | */ |
fa73b229 | 2161 | |
323c5de1 | 2162 | if (!cupsAdminGetServerSettings(http, &num_settings, &settings)) |
ef416fc2 | 2163 | { |
323c5de1 | 2164 | cgiSetVariable("SETTINGS_MESSAGE", |
2165 | cgiText(_("Unable to open cupsd.conf file:"))); | |
2166 | cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString()); | |
ef416fc2 | 2167 | } |
2168 | ||
323c5de1 | 2169 | if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, num_settings, |
2170 | settings)) != NULL && atoi(val)) | |
2171 | cgiSetVariable("DEBUG_LOGGING", "CHECKED"); | |
ef416fc2 | 2172 | |
323c5de1 | 2173 | if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, num_settings, |
2174 | settings)) != NULL && atoi(val)) | |
2175 | cgiSetVariable("REMOTE_ADMIN", "CHECKED"); | |
ef416fc2 | 2176 | |
323c5de1 | 2177 | if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, num_settings, |
2178 | settings)) != NULL && atoi(val)) | |
2179 | cgiSetVariable("REMOTE_ANY", "CHECKED"); | |
ef416fc2 | 2180 | |
323c5de1 | 2181 | if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, num_settings, |
2182 | settings)) != NULL && atoi(val)) | |
2183 | cgiSetVariable("SHARE_PRINTERS", "CHECKED"); | |
ef416fc2 | 2184 | |
323c5de1 | 2185 | if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, num_settings, |
2186 | settings)) != NULL && atoi(val)) | |
2187 | cgiSetVariable("USER_CANCEL_ANY", "CHECKED"); | |
2188 | ||
2189 | #ifdef HAVE_GSSAPI | |
2190 | cgiSetVariable("HAVE_GSSAPI", "1"); | |
2191 | ||
2192 | if ((val = cupsGetOption("DefaultAuthType", num_settings, | |
88f9aafc | 2193 | settings)) != NULL && !_cups_strcasecmp(val, "Negotiate")) |
323c5de1 | 2194 | cgiSetVariable("KERBEROS", "CHECKED"); |
ef55b745 | 2195 | else |
323c5de1 | 2196 | #endif /* HAVE_GSSAPI */ |
ef55b745 | 2197 | cgiSetVariable("KERBEROS", ""); |
323c5de1 | 2198 | |
0af14961 MS |
2199 | if ((val = cupsGetOption("BrowseWebIF", num_settings, |
2200 | settings)) == NULL) | |
2201 | val = "No"; | |
2202 | ||
88f9aafc MS |
2203 | if (!_cups_strcasecmp(val, "yes") || !_cups_strcasecmp(val, "on") || |
2204 | !_cups_strcasecmp(val, "true")) | |
0af14961 MS |
2205 | cgiSetVariable("BROWSE_WEB_IF", "CHECKED"); |
2206 | ||
2207 | if ((val = cupsGetOption("PreserveJobHistory", num_settings, | |
2208 | settings)) == NULL) | |
2209 | val = "Yes"; | |
2210 | ||
82cc1f9a MS |
2211 | if (val && |
2212 | (!_cups_strcasecmp(val, "0") || !_cups_strcasecmp(val, "no") || | |
2213 | !_cups_strcasecmp(val, "off") || !_cups_strcasecmp(val, "false") || | |
2214 | !_cups_strcasecmp(val, "disabled"))) | |
0af14961 | 2215 | { |
82cc1f9a MS |
2216 | cgiSetVariable("PRESERVE_JOB_HISTORY", "0"); |
2217 | cgiSetVariable("PRESERVE_JOB_FILES", "0"); | |
2218 | } | |
2219 | else | |
2220 | { | |
2221 | cgiSetVariable("PRESERVE_JOBS", "CHECKED"); | |
2222 | cgiSetVariable("PRESERVE_JOB_HISTORY", val); | |
0af14961 MS |
2223 | |
2224 | if ((val = cupsGetOption("PreserveJobFiles", num_settings, | |
2225 | settings)) == NULL) | |
82cc1f9a MS |
2226 | val = "1d"; |
2227 | ||
2228 | cgiSetVariable("PRESERVE_JOB_FILES", val); | |
0af14961 | 2229 | |
0af14961 MS |
2230 | } |
2231 | ||
1f6f3dbc MS |
2232 | if ((val = cupsGetOption("MaxClients", num_settings, settings)) == NULL) |
2233 | val = "100"; | |
2234 | ||
2235 | cgiSetVariable("MAX_CLIENTS", val); | |
2236 | ||
0af14961 MS |
2237 | if ((val = cupsGetOption("MaxJobs", num_settings, settings)) == NULL) |
2238 | val = "500"; | |
2239 | ||
2240 | cgiSetVariable("MAX_JOBS", val); | |
2241 | ||
2242 | if ((val = cupsGetOption("MaxLogSize", num_settings, settings)) == NULL) | |
2243 | val = "1m"; | |
2244 | ||
2245 | cgiSetVariable("MAX_LOG_SIZE", val); | |
2246 | ||
323c5de1 | 2247 | cupsFreeOptions(num_settings, settings); |
ef416fc2 | 2248 | |
323c5de1 | 2249 | /* |
2250 | * Finally, show the main menu template... | |
2251 | */ | |
2252 | ||
2253 | cgiStartHTML(cgiText(_("Administration"))); | |
2254 | ||
2255 | cgiCopyTemplateLang("admin.tmpl"); | |
ef416fc2 | 2256 | |
2257 | cgiEndHTML(); | |
2258 | } | |
2259 | ||
2260 | ||
fa73b229 | 2261 | /* |
323c5de1 | 2262 | * 'do_set_allowed_users()' - Set the allowed/denied users for a queue. |
fa73b229 | 2263 | */ |
2264 | ||
2265 | static void | |
323c5de1 | 2266 | do_set_allowed_users(http_t *http) /* I - HTTP connection */ |
fa73b229 | 2267 | { |
323c5de1 | 2268 | int i; /* Looping var */ |
fa73b229 | 2269 | ipp_t *request, /* IPP request */ |
2270 | *response; /* IPP response */ | |
323c5de1 | 2271 | char uri[HTTP_MAX_URI]; /* Printer URI */ |
2272 | const char *printer, /* Printer name (purge-jobs) */ | |
2273 | *is_class, /* Is a class? */ | |
2274 | *users, /* List of users or groups */ | |
2275 | *type; /* Allow/deny type */ | |
2276 | int num_users; /* Number of users */ | |
2277 | char *ptr, /* Pointer into users string */ | |
2278 | *end, /* Pointer to end of users string */ | |
2279 | quote; /* Quote character */ | |
2280 | ipp_attribute_t *attr; /* Attribute */ | |
2281 | static const char * const attrs[] = /* Requested attributes */ | |
2282 | { | |
2283 | "requesting-user-name-allowed", | |
2284 | "requesting-user-name-denied" | |
2285 | }; | |
fa73b229 | 2286 | |
fa73b229 | 2287 | |
323c5de1 | 2288 | is_class = cgiGetVariable("IS_CLASS"); |
2289 | printer = cgiGetVariable("PRINTER_NAME"); | |
fa73b229 | 2290 | |
323c5de1 | 2291 | if (!printer) |
2292 | { | |
4d301e69 | 2293 | cgiSetVariable("ERROR", cgiText(_("Missing form variable"))); |
323c5de1 | 2294 | cgiStartHTML(cgiText(_("Set Allowed Users"))); |
2295 | cgiCopyTemplateLang("error.tmpl"); | |
2296 | cgiEndHTML(); | |
2297 | return; | |
2298 | } | |
ef416fc2 | 2299 | |
323c5de1 | 2300 | users = cgiGetVariable("users"); |
2301 | type = cgiGetVariable("type"); | |
ef416fc2 | 2302 | |
323c5de1 | 2303 | if (!users || !type || |
2304 | (strcmp(type, "requesting-user-name-allowed") && | |
2305 | strcmp(type, "requesting-user-name-denied"))) | |
2306 | { | |
2307 | /* | |
2308 | * Build a Get-Printer-Attributes request, which requires the following | |
2309 | * attributes: | |
2310 | * | |
2311 | * attributes-charset | |
2312 | * attributes-natural-language | |
2313 | * printer-uri | |
2314 | * requested-attributes | |
2315 | */ | |
fa73b229 | 2316 | |
323c5de1 | 2317 | request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); |
fa73b229 | 2318 | |
323c5de1 | 2319 | httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, |
2320 | "localhost", 0, is_class ? "/classes/%s" : "/printers/%s", | |
2321 | printer); | |
2322 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", | |
2323 | NULL, uri); | |
fa73b229 | 2324 | |
323c5de1 | 2325 | ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, |
2326 | "requested-attributes", | |
2327 | (int)(sizeof(attrs) / sizeof(attrs[0])), NULL, attrs); | |
fa73b229 | 2328 | |
323c5de1 | 2329 | /* |
2330 | * Do the request and get back a response... | |
2331 | */ | |
fa73b229 | 2332 | |
323c5de1 | 2333 | if ((response = cupsDoRequest(http, request, "/")) != NULL) |
fa73b229 | 2334 | { |
323c5de1 | 2335 | cgiSetIPPVars(response, NULL, NULL, NULL, 0); |
fa73b229 | 2336 | |
323c5de1 | 2337 | ippDelete(response); |
fa73b229 | 2338 | } |
ef416fc2 | 2339 | |
323c5de1 | 2340 | cgiStartHTML(cgiText(_("Set Allowed Users"))); |
757d2cad | 2341 | |
355e94dc MS |
2342 | if (cupsLastError() == IPP_NOT_AUTHORIZED) |
2343 | { | |
2344 | puts("Status: 401\n"); | |
2345 | exit(0); | |
2346 | } | |
2347 | else if (cupsLastError() > IPP_OK_CONFLICT) | |
f3c17241 | 2348 | cgiShowIPPError(_("Unable to get printer attributes")); |
323c5de1 | 2349 | else |
2350 | cgiCopyTemplateLang("users.tmpl"); | |
2351 | ||
2352 | cgiEndHTML(); | |
2353 | } | |
2354 | else | |
757d2cad | 2355 | { |
2356 | /* | |
323c5de1 | 2357 | * Save the changes... |
757d2cad | 2358 | */ |
2359 | ||
323c5de1 | 2360 | for (num_users = 0, ptr = (char *)users; *ptr; num_users ++) |
757d2cad | 2361 | { |
323c5de1 | 2362 | /* |
2363 | * Skip whitespace and commas... | |
2364 | */ | |
fa73b229 | 2365 | |
323c5de1 | 2366 | while (*ptr == ',' || isspace(*ptr & 255)) |
2367 | ptr ++; | |
ef416fc2 | 2368 | |
1f6f3dbc MS |
2369 | if (!*ptr) |
2370 | break; | |
2371 | ||
323c5de1 | 2372 | if (*ptr == '\'' || *ptr == '\"') |
2373 | { | |
2374 | /* | |
2375 | * Scan quoted name... | |
2376 | */ | |
ef416fc2 | 2377 | |
323c5de1 | 2378 | quote = *ptr++; |
ef416fc2 | 2379 | |
323c5de1 | 2380 | for (end = ptr; *end; end ++) |
2381 | if (*end == quote) | |
2382 | break; | |
2383 | } | |
2384 | else | |
2385 | { | |
2386 | /* | |
2387 | * Scan space or comma-delimited name... | |
2388 | */ | |
ef416fc2 | 2389 | |
323c5de1 | 2390 | for (end = ptr; *end; end ++) |
2391 | if (isspace(*end & 255) || *end == ',') | |
2392 | break; | |
2393 | } | |
ef416fc2 | 2394 | |
323c5de1 | 2395 | /* |
2396 | * Advance to the next name... | |
2397 | */ | |
ef416fc2 | 2398 | |
323c5de1 | 2399 | ptr = end; |
2400 | } | |
ef416fc2 | 2401 | |
323c5de1 | 2402 | /* |
2403 | * Build a CUPS-Add-Printer/Class request, which requires the following | |
2404 | * attributes: | |
2405 | * | |
2406 | * attributes-charset | |
2407 | * attributes-natural-language | |
2408 | * printer-uri | |
2409 | * requesting-user-name-{allowed,denied} | |
2410 | */ | |
ef416fc2 | 2411 | |
323c5de1 | 2412 | request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER); |
ef416fc2 | 2413 | |
323c5de1 | 2414 | httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, |
2415 | "localhost", 0, is_class ? "/classes/%s" : "/printers/%s", | |
2416 | printer); | |
2417 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", | |
2418 | NULL, uri); | |
f7deaa1a | 2419 | |
323c5de1 | 2420 | if (num_users == 0) |
2421 | ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, | |
2422 | "requesting-user-name-allowed", NULL, "all"); | |
2423 | else | |
2424 | { | |
2425 | attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME, | |
2426 | type, num_users, NULL, NULL); | |
ef416fc2 | 2427 | |
323c5de1 | 2428 | for (i = 0, ptr = (char *)users; *ptr; i ++) |
2429 | { | |
2430 | /* | |
2431 | * Skip whitespace and commas... | |
2432 | */ | |
ef416fc2 | 2433 | |
323c5de1 | 2434 | while (*ptr == ',' || isspace(*ptr & 255)) |
2435 | ptr ++; | |
ef416fc2 | 2436 | |
1f6f3dbc MS |
2437 | if (!*ptr) |
2438 | break; | |
2439 | ||
323c5de1 | 2440 | if (*ptr == '\'' || *ptr == '\"') |
2441 | { | |
2442 | /* | |
2443 | * Scan quoted name... | |
2444 | */ | |
7594b224 | 2445 | |
323c5de1 | 2446 | quote = *ptr++; |
7594b224 | 2447 | |
323c5de1 | 2448 | for (end = ptr; *end; end ++) |
2449 | if (*end == quote) | |
2450 | break; | |
2451 | } | |
2452 | else | |
2453 | { | |
2454 | /* | |
2455 | * Scan space or comma-delimited name... | |
2456 | */ | |
480ef0fe | 2457 | |
323c5de1 | 2458 | for (end = ptr; *end; end ++) |
2459 | if (isspace(*end & 255) || *end == ',') | |
2460 | break; | |
2461 | } | |
ef416fc2 | 2462 | |
323c5de1 | 2463 | /* |
2464 | * Terminate the name... | |
2465 | */ | |
ef416fc2 | 2466 | |
323c5de1 | 2467 | if (*end) |
2468 | *end++ = '\0'; | |
ef416fc2 | 2469 | |
323c5de1 | 2470 | /* |
2471 | * Add the name... | |
2472 | */ | |
ef416fc2 | 2473 | |
86c184ff | 2474 | ippSetString(request, &attr, i, ptr); |
ef416fc2 | 2475 | |
323c5de1 | 2476 | /* |
2477 | * Advance to the next name... | |
2478 | */ | |
ef416fc2 | 2479 | |
323c5de1 | 2480 | ptr = end; |
2481 | } | |
2482 | } | |
ef416fc2 | 2483 | |
2484 | /* | |
323c5de1 | 2485 | * Do the request and get back a response... |
ef416fc2 | 2486 | */ |
2487 | ||
323c5de1 | 2488 | ippDelete(cupsDoRequest(http, request, "/admin/")); |
ef416fc2 | 2489 | |
355e94dc MS |
2490 | if (cupsLastError() == IPP_NOT_AUTHORIZED) |
2491 | { | |
2492 | puts("Status: 401\n"); | |
2493 | exit(0); | |
2494 | } | |
2495 | else if (cupsLastError() > IPP_OK_CONFLICT) | |
ef416fc2 | 2496 | { |
323c5de1 | 2497 | cgiStartHTML(cgiText(_("Set Allowed Users"))); |
f3c17241 | 2498 | cgiShowIPPError(_("Unable to change printer")); |
ef416fc2 | 2499 | } |
323c5de1 | 2500 | else |
ef416fc2 | 2501 | { |
2502 | /* | |
323c5de1 | 2503 | * Redirect successful updates back to the printer page... |
ef416fc2 | 2504 | */ |
2505 | ||
323c5de1 | 2506 | char url[1024], /* Printer/class URL */ |
2507 | refresh[1024]; /* Refresh URL */ | |
ef416fc2 | 2508 | |
2509 | ||
323c5de1 | 2510 | cgiRewriteURL(uri, url, sizeof(url), NULL); |
2511 | cgiFormEncode(uri, url, sizeof(uri)); | |
2512 | snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", | |
2513 | uri); | |
2514 | cgiSetVariable("refresh_page", refresh); | |
ef416fc2 | 2515 | |
323c5de1 | 2516 | cgiStartHTML(cgiText(_("Set Allowed Users"))); |
ef416fc2 | 2517 | |
323c5de1 | 2518 | cgiCopyTemplateLang(is_class ? "class-modified.tmpl" : |
2519 | "printer-modified.tmpl"); | |
2520 | } | |
ef416fc2 | 2521 | |
323c5de1 | 2522 | cgiEndHTML(); |
2523 | } | |
2524 | } | |
ef416fc2 | 2525 | |
ef416fc2 | 2526 | |
58dc1933 MS |
2527 | /* |
2528 | * 'do_set_default()' - Set the server default printer/class. | |
2529 | */ | |
2530 | ||
2531 | static void | |
2532 | do_set_default(http_t *http) /* I - HTTP connection */ | |
2533 | { | |
2534 | const char *title; /* Page title */ | |
2535 | ipp_t *request; /* IPP request */ | |
2536 | char uri[HTTP_MAX_URI]; /* Printer URI */ | |
2537 | const char *printer, /* Printer name (purge-jobs) */ | |
2538 | *is_class; /* Is a class? */ | |
2539 | ||
2540 | ||
2541 | is_class = cgiGetVariable("IS_CLASS"); | |
2542 | printer = cgiGetVariable("PRINTER_NAME"); | |
2543 | title = cgiText(_("Set As Server Default")); | |
2544 | ||
2545 | if (!printer) | |
2546 | { | |
4d301e69 | 2547 | cgiSetVariable("ERROR", cgiText(_("Missing form variable"))); |
58dc1933 MS |
2548 | cgiStartHTML(title); |
2549 | cgiCopyTemplateLang("error.tmpl"); | |
2550 | cgiEndHTML(); | |
2551 | return; | |
2552 | } | |
2553 | ||
2554 | /* | |
2555 | * Build a printer request, which requires the following | |
2556 | * attributes: | |
2557 | * | |
2558 | * attributes-charset | |
2559 | * attributes-natural-language | |
2560 | * printer-uri | |
2561 | */ | |
2562 | ||
2563 | request = ippNewRequest(CUPS_SET_DEFAULT); | |
2564 | ||
2565 | httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, | |
2566 | "localhost", 0, is_class ? "/classes/%s" : "/printers/%s", | |
2567 | printer); | |
2568 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", | |
2569 | NULL, uri); | |
2570 | ||
2571 | /* | |
2572 | * Do the request and get back a response... | |
2573 | */ | |
2574 | ||
2575 | ippDelete(cupsDoRequest(http, request, "/admin/")); | |
2576 | ||
2577 | if (cupsLastError() == IPP_NOT_AUTHORIZED) | |
2578 | { | |
2579 | puts("Status: 401\n"); | |
2580 | exit(0); | |
2581 | } | |
2582 | else if (cupsLastError() > IPP_OK_CONFLICT) | |
2583 | { | |
2584 | cgiStartHTML(title); | |
f3c17241 | 2585 | cgiShowIPPError(_("Unable to set server default")); |
58dc1933 MS |
2586 | } |
2587 | else | |
2588 | { | |
2589 | /* | |
2590 | * Redirect successful updates back to the printer page... | |
2591 | */ | |
2592 | ||
2593 | char url[1024], /* Printer/class URL */ | |
2594 | refresh[1024]; /* Refresh URL */ | |
2595 | ||
2596 | ||
2597 | cgiRewriteURL(uri, url, sizeof(url), NULL); | |
2598 | cgiFormEncode(uri, url, sizeof(uri)); | |
2599 | snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri); | |
2600 | cgiSetVariable("refresh_page", refresh); | |
2601 | ||
2602 | cgiStartHTML(title); | |
2603 | cgiCopyTemplateLang("printer-default.tmpl"); | |
2604 | } | |
2605 | ||
2606 | cgiEndHTML(); | |
2607 | } | |
2608 | ||
2609 | ||
323c5de1 | 2610 | /* |
2611 | * 'do_set_options()' - Configure the default options for a queue. | |
2612 | */ | |
ef416fc2 | 2613 | |
323c5de1 | 2614 | static void |
2615 | do_set_options(http_t *http, /* I - HTTP connection */ | |
2616 | int is_class) /* I - Set options for class? */ | |
2617 | { | |
2618 | int i, j, k, m; /* Looping vars */ | |
2619 | int have_options; /* Have options? */ | |
2620 | ipp_t *request, /* IPP request */ | |
2621 | *response; /* IPP response */ | |
2622 | ipp_attribute_t *attr; /* IPP attribute */ | |
2623 | char uri[HTTP_MAX_URI]; /* Job URI */ | |
2624 | const char *var; /* Variable value */ | |
2625 | const char *printer; /* Printer printer name */ | |
2626 | const char *filename; /* PPD filename */ | |
2627 | char tempfile[1024]; /* Temporary filename */ | |
2628 | cups_file_t *in, /* Input file */ | |
2629 | *out; /* Output file */ | |
749b1e90 MS |
2630 | char line[1024], /* Line from PPD file */ |
2631 | value[1024], /* Option value */ | |
2632 | keyword[1024], /* Keyword from Default line */ | |
323c5de1 | 2633 | *keyptr; /* Pointer into keyword... */ |
2634 | ppd_file_t *ppd; /* PPD file */ | |
2635 | ppd_group_t *group; /* Option group */ | |
2636 | ppd_option_t *option; /* Option */ | |
749b1e90 MS |
2637 | ppd_coption_t *coption; /* Custom option */ |
2638 | ppd_cparam_t *cparam; /* Custom parameter */ | |
1f6f3dbc | 2639 | ppd_attr_t *ppdattr; /* PPD attribute */ |
323c5de1 | 2640 | const char *title; /* Page title */ |
ef416fc2 | 2641 | |
ef416fc2 | 2642 | |
323c5de1 | 2643 | title = cgiText(is_class ? _("Set Class Options") : _("Set Printer Options")); |
ef416fc2 | 2644 | |
323c5de1 | 2645 | fprintf(stderr, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http, |
2646 | is_class); | |
ef416fc2 | 2647 | |
323c5de1 | 2648 | /* |
2649 | * Get the printer name... | |
2650 | */ | |
ef416fc2 | 2651 | |
323c5de1 | 2652 | if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL) |
2653 | httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, | |
2654 | "localhost", 0, is_class ? "/classes/%s" : "/printers/%s", | |
2655 | printer); | |
2656 | else | |
2657 | { | |
4d301e69 | 2658 | cgiSetVariable("ERROR", cgiText(_("Missing form variable"))); |
323c5de1 | 2659 | cgiStartHTML(title); |
2660 | cgiCopyTemplateLang("error.tmpl"); | |
2661 | cgiEndHTML(); | |
2662 | return; | |
2663 | } | |
ef416fc2 | 2664 | |
323c5de1 | 2665 | fprintf(stderr, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer, uri); |
ef416fc2 | 2666 | |
1f6f3dbc MS |
2667 | /* |
2668 | * If the user clicks on the Auto-Configure button, send an AutoConfigure | |
2669 | * command file to the printer... | |
2670 | */ | |
2671 | ||
2672 | if (cgiGetVariable("AUTOCONFIGURE")) | |
2673 | { | |
58dc1933 | 2674 | cgiPrintCommand(http, printer, "AutoConfigure", "Set Default Options"); |
1f6f3dbc MS |
2675 | return; |
2676 | } | |
2677 | ||
323c5de1 | 2678 | /* |
2679 | * Get the PPD file... | |
2680 | */ | |
ef416fc2 | 2681 | |
323c5de1 | 2682 | if (is_class) |
2683 | filename = NULL; | |
2684 | else | |
2685 | filename = cupsGetPPD2(http, printer); | |
ef416fc2 | 2686 | |
323c5de1 | 2687 | if (filename) |
2688 | { | |
2689 | fprintf(stderr, "DEBUG: Got PPD file: \"%s\"\n", filename); | |
ef416fc2 | 2690 | |
323c5de1 | 2691 | if ((ppd = ppdOpenFile(filename)) == NULL) |
2692 | { | |
2693 | cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i))); | |
f3c17241 | 2694 | cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file"))); |
323c5de1 | 2695 | cgiStartHTML(title); |
2696 | cgiCopyTemplateLang("error.tmpl"); | |
2697 | cgiEndHTML(); | |
2698 | return; | |
2699 | } | |
2700 | } | |
2701 | else | |
2702 | { | |
2703 | fputs("DEBUG: No PPD file\n", stderr); | |
2704 | ppd = NULL; | |
2705 | } | |
ef416fc2 | 2706 | |
323c5de1 | 2707 | if (cgiGetVariable("job_sheets_start") != NULL || |
2708 | cgiGetVariable("job_sheets_end") != NULL) | |
2709 | have_options = 1; | |
2710 | else | |
2711 | have_options = 0; | |
ef416fc2 | 2712 | |
323c5de1 | 2713 | if (ppd) |
2714 | { | |
2715 | ppdMarkDefaults(ppd); | |
ef416fc2 | 2716 | |
749b1e90 MS |
2717 | for (option = ppdFirstOption(ppd); |
2718 | option; | |
2719 | option = ppdNextOption(ppd)) | |
ef55b745 | 2720 | { |
749b1e90 MS |
2721 | if ((var = cgiGetVariable(option->keyword)) != NULL) |
2722 | { | |
2723 | have_options = 1; | |
2724 | ppdMarkOption(ppd, option->keyword, var); | |
ef55b745 | 2725 | fprintf(stderr, "DEBUG: Set %s to %s...\n", option->keyword, var); |
749b1e90 | 2726 | } |
ef55b745 MS |
2727 | else |
2728 | fprintf(stderr, "DEBUG: Didn't find %s...\n", option->keyword); | |
2729 | } | |
323c5de1 | 2730 | } |
fa73b229 | 2731 | |
323c5de1 | 2732 | if (!have_options || ppdConflicts(ppd)) |
fa73b229 | 2733 | { |
2734 | /* | |
323c5de1 | 2735 | * Show the options to the user... |
fa73b229 | 2736 | */ |
2737 | ||
323c5de1 | 2738 | fputs("DEBUG: Showing options...\n", stderr); |
fa73b229 | 2739 | |
58dc1933 MS |
2740 | /* |
2741 | * Show auto-configure button if supported... | |
2742 | */ | |
2743 | ||
1f6f3dbc MS |
2744 | if (ppd) |
2745 | { | |
2746 | if (ppd->num_filters == 0 || | |
2747 | ((ppdattr = ppdFindAttr(ppd, "cupsCommands", NULL)) != NULL && | |
2748 | ppdattr->value && strstr(ppdattr->value, "AutoConfigure"))) | |
2749 | cgiSetVariable("HAVE_AUTOCONFIGURE", "YES"); | |
ef55b745 | 2750 | else |
1f6f3dbc MS |
2751 | { |
2752 | for (i = 0; i < ppd->num_filters; i ++) | |
2753 | if (!strncmp(ppd->filters[i], "application/vnd.cups-postscript", 31)) | |
2754 | { | |
2755 | cgiSetVariable("HAVE_AUTOCONFIGURE", "YES"); | |
2756 | break; | |
2757 | } | |
2758 | } | |
2759 | } | |
2760 | ||
58dc1933 MS |
2761 | /* |
2762 | * Get the printer attributes... | |
2763 | */ | |
2764 | ||
2765 | request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); | |
2766 | ||
2767 | httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, | |
2768 | "localhost", 0, "/printers/%s", printer); | |
2769 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", | |
2770 | NULL, uri); | |
2771 | ||
2772 | response = cupsDoRequest(http, request, "/"); | |
2773 | ||
2774 | /* | |
2775 | * List the groups used as "tabs"... | |
2776 | */ | |
2777 | ||
2778 | i = 0; | |
2779 | ||
2780 | if (ppd) | |
2781 | { | |
2782 | for (group = ppd->groups; | |
2783 | i < ppd->num_groups; | |
2784 | i ++, group ++) | |
2785 | { | |
2786 | cgiSetArray("GROUP_ID", i, group->name); | |
2787 | ||
2788 | if (!strcmp(group->name, "InstallableOptions")) | |
2789 | cgiSetArray("GROUP", i, cgiText(_("Options Installed"))); | |
2790 | else | |
2791 | cgiSetArray("GROUP", i, group->text); | |
2792 | } | |
2793 | } | |
2794 | ||
2795 | if (ippFindAttribute(response, "job-sheets-supported", IPP_TAG_ZERO)) | |
2796 | { | |
2797 | cgiSetArray("GROUP_ID", i, "CUPS_BANNERS"); | |
2798 | cgiSetArray("GROUP", i ++, cgiText(_("Banners"))); | |
2799 | } | |
2800 | ||
2801 | if (ippFindAttribute(response, "printer-error-policy-supported", | |
2802 | IPP_TAG_ZERO) || | |
2803 | ippFindAttribute(response, "printer-op-policy-supported", | |
2804 | IPP_TAG_ZERO)) | |
2805 | { | |
2806 | cgiSetArray("GROUP_ID", i, "CUPS_POLICIES"); | |
2807 | cgiSetArray("GROUP", i ++, cgiText(_("Policies"))); | |
2808 | } | |
2809 | ||
2810 | if ((attr = ippFindAttribute(response, "port-monitor-supported", | |
2811 | IPP_TAG_NAME)) != NULL && attr->num_values > 1) | |
2812 | { | |
2813 | cgiSetArray("GROUP_ID", i, "CUPS_PORT_MONITOR"); | |
2814 | cgiSetArray("GROUP", i, cgiText(_("Port Monitor"))); | |
2815 | } | |
2816 | ||
323c5de1 | 2817 | cgiStartHTML(cgiText(_("Set Printer Options"))); |
2818 | cgiCopyTemplateLang("set-printer-options-header.tmpl"); | |
fa73b229 | 2819 | |
323c5de1 | 2820 | if (ppd) |
2821 | { | |
2822 | ppdLocalize(ppd); | |
f7deaa1a | 2823 | |
323c5de1 | 2824 | if (ppdConflicts(ppd)) |
2825 | { | |
2826 | for (i = ppd->num_groups, k = 0, group = ppd->groups; | |
2827 | i > 0; | |
2828 | i --, group ++) | |
2829 | for (j = group->num_options, option = group->options; | |
2830 | j > 0; | |
2831 | j --, option ++) | |
2832 | if (option->conflicted) | |
2833 | { | |
2834 | cgiSetArray("ckeyword", k, option->keyword); | |
2835 | cgiSetArray("ckeytext", k, option->text); | |
ef55b745 MS |
2836 | |
2837 | for (m = 0; m < option->num_choices; m ++) | |
2838 | { | |
2839 | if (option->choices[m].marked) | |
2840 | { | |
2841 | cgiSetArray("cchoice", k, option->choices[m].text); | |
2842 | break; | |
2843 | } | |
2844 | } | |
2845 | ||
323c5de1 | 2846 | k ++; |
2847 | } | |
f7deaa1a | 2848 | |
323c5de1 | 2849 | cgiCopyTemplateLang("option-conflict.tmpl"); |
2850 | } | |
f7deaa1a | 2851 | |
323c5de1 | 2852 | for (i = ppd->num_groups, group = ppd->groups; |
2853 | i > 0; | |
2854 | i --, group ++) | |
2855 | { | |
7cf5915e MS |
2856 | for (j = group->num_options, option = group->options; |
2857 | j > 0; | |
2858 | j --, option ++) | |
2859 | { | |
2860 | if (!strcmp(option->keyword, "PageRegion")) | |
2861 | continue; | |
2862 | ||
2863 | if (option->num_choices > 1) | |
2864 | break; | |
2865 | } | |
2866 | ||
2867 | if (j == 0) | |
2868 | continue; | |
2869 | ||
58dc1933 MS |
2870 | cgiSetVariable("GROUP_ID", group->name); |
2871 | ||
323c5de1 | 2872 | if (!strcmp(group->name, "InstallableOptions")) |
2873 | cgiSetVariable("GROUP", cgiText(_("Options Installed"))); | |
2874 | else | |
2875 | cgiSetVariable("GROUP", group->text); | |
f7deaa1a | 2876 | |
323c5de1 | 2877 | cgiCopyTemplateLang("option-header.tmpl"); |
ef55b745 | 2878 | |
323c5de1 | 2879 | for (j = group->num_options, option = group->options; |
2880 | j > 0; | |
2881 | j --, option ++) | |
2882 | { | |
7cf5915e | 2883 | if (!strcmp(option->keyword, "PageRegion") || option->num_choices < 2) |
323c5de1 | 2884 | continue; |
ef416fc2 | 2885 | |
323c5de1 | 2886 | cgiSetVariable("KEYWORD", option->keyword); |
2887 | cgiSetVariable("KEYTEXT", option->text); | |
749b1e90 | 2888 | |
323c5de1 | 2889 | if (option->conflicted) |
2890 | cgiSetVariable("CONFLICTED", "1"); | |
2891 | else | |
2892 | cgiSetVariable("CONFLICTED", "0"); | |
2893 | ||
2894 | cgiSetSize("CHOICES", 0); | |
2895 | cgiSetSize("TEXT", 0); | |
2896 | for (k = 0, m = 0; k < option->num_choices; k ++) | |
2897 | { | |
323c5de1 | 2898 | cgiSetArray("CHOICES", m, option->choices[k].choice); |
2899 | cgiSetArray("TEXT", m, option->choices[k].text); | |
ef416fc2 | 2900 | |
323c5de1 | 2901 | m ++; |
ef416fc2 | 2902 | |
323c5de1 | 2903 | if (option->choices[k].marked) |
2904 | cgiSetVariable("DEFCHOICE", option->choices[k].choice); | |
2905 | } | |
ef416fc2 | 2906 | |
749b1e90 MS |
2907 | cgiSetSize("PARAMS", 0); |
2908 | cgiSetSize("PARAMTEXT", 0); | |
2909 | cgiSetSize("PARAMVALUE", 0); | |
2910 | cgiSetSize("INPUTTYPE", 0); | |
2911 | ||
2912 | if ((coption = ppdFindCustomOption(ppd, option->keyword))) | |
2913 | { | |
2914 | const char *units = NULL; /* Units value, if any */ | |
2915 | ||
749b1e90 MS |
2916 | cgiSetVariable("ISCUSTOM", "1"); |
2917 | ||
2918 | for (cparam = ppdFirstCustomParam(coption), m = 0; | |
2919 | cparam; | |
2920 | cparam = ppdNextCustomParam(coption), m ++) | |
2921 | { | |
88f9aafc MS |
2922 | if (!_cups_strcasecmp(option->keyword, "PageSize") && |
2923 | _cups_strcasecmp(cparam->name, "Width") && | |
2924 | _cups_strcasecmp(cparam->name, "Height")) | |
749b1e90 MS |
2925 | { |
2926 | m --; | |
2927 | continue; | |
2928 | } | |
2929 | ||
2930 | cgiSetArray("PARAMS", m, cparam->name); | |
2931 | cgiSetArray("PARAMTEXT", m, cparam->text); | |
2932 | cgiSetArray("INPUTTYPE", m, "text"); | |
2933 | ||
2934 | switch (cparam->type) | |
2935 | { | |
8e048e4d MS |
2936 | case PPD_CUSTOM_UNKNOWN : |
2937 | break; | |
2938 | ||
749b1e90 | 2939 | case PPD_CUSTOM_POINTS : |
88f9aafc | 2940 | if (!_cups_strncasecmp(option->defchoice, "Custom.", 7)) |
749b1e90 MS |
2941 | { |
2942 | units = option->defchoice + strlen(option->defchoice) - 2; | |
2943 | ||
2944 | if (strcmp(units, "mm") && strcmp(units, "cm") && | |
2945 | strcmp(units, "in") && strcmp(units, "ft")) | |
2946 | { | |
2947 | if (units[1] == 'm') | |
2948 | units ++; | |
2949 | else | |
2950 | units = "pt"; | |
2951 | } | |
2952 | } | |
2953 | else | |
2954 | units = "pt"; | |
2955 | ||
2956 | if (!strcmp(units, "mm")) | |
2957 | snprintf(value, sizeof(value), "%g", | |
2958 | cparam->current.custom_points / 72.0 * 25.4); | |
2959 | else if (!strcmp(units, "cm")) | |
2960 | snprintf(value, sizeof(value), "%g", | |
2961 | cparam->current.custom_points / 72.0 * 2.54); | |
2962 | else if (!strcmp(units, "in")) | |
2963 | snprintf(value, sizeof(value), "%g", | |
2964 | cparam->current.custom_points / 72.0); | |
2965 | else if (!strcmp(units, "ft")) | |
2966 | snprintf(value, sizeof(value), "%g", | |
2967 | cparam->current.custom_points / 72.0 / 12.0); | |
2968 | else if (!strcmp(units, "m")) | |
2969 | snprintf(value, sizeof(value), "%g", | |
2970 | cparam->current.custom_points / 72.0 * 0.0254); | |
2971 | else | |
2972 | snprintf(value, sizeof(value), "%g", | |
2973 | cparam->current.custom_points); | |
2974 | cgiSetArray("PARAMVALUE", m, value); | |
2975 | break; | |
2976 | ||
2977 | case PPD_CUSTOM_CURVE : | |
2978 | case PPD_CUSTOM_INVCURVE : | |
2979 | case PPD_CUSTOM_REAL : | |
2980 | snprintf(value, sizeof(value), "%g", | |
2981 | cparam->current.custom_real); | |
2982 | cgiSetArray("PARAMVALUE", m, value); | |
2983 | break; | |
2984 | ||
2985 | case PPD_CUSTOM_INT: | |
2986 | snprintf(value, sizeof(value), "%d", | |
2987 | cparam->current.custom_int); | |
2988 | cgiSetArray("PARAMVALUE", m, value); | |
2989 | break; | |
2990 | ||
2991 | case PPD_CUSTOM_PASSCODE: | |
2992 | case PPD_CUSTOM_PASSWORD: | |
2993 | if (cparam->current.custom_password) | |
2994 | cgiSetArray("PARAMVALUE", m, | |
2995 | cparam->current.custom_password); | |
2996 | else | |
2997 | cgiSetArray("PARAMVALUE", m, ""); | |
2998 | cgiSetArray("INPUTTYPE", m, "password"); | |
2999 | break; | |
3000 | ||
3001 | case PPD_CUSTOM_STRING: | |
3002 | if (cparam->current.custom_string) | |
3003 | cgiSetArray("PARAMVALUE", m, | |
3004 | cparam->current.custom_string); | |
3005 | else | |
3006 | cgiSetArray("PARAMVALUE", m, ""); | |
3007 | break; | |
3008 | } | |
3009 | } | |
3010 | ||
3011 | if (units) | |
3012 | { | |
3013 | cgiSetArray("PARAMS", m, "Units"); | |
3014 | cgiSetArray("PARAMTEXT", m, cgiText(_("Units"))); | |
3015 | cgiSetArray("PARAMVALUE", m, units); | |
3016 | } | |
3017 | } | |
3018 | else | |
3019 | cgiSetVariable("ISCUSTOM", "0"); | |
3020 | ||
323c5de1 | 3021 | switch (option->ui) |
3022 | { | |
3023 | case PPD_UI_BOOLEAN : | |
3024 | cgiCopyTemplateLang("option-boolean.tmpl"); | |
3025 | break; | |
3026 | case PPD_UI_PICKONE : | |
3027 | cgiCopyTemplateLang("option-pickone.tmpl"); | |
3028 | break; | |
3029 | case PPD_UI_PICKMANY : | |
3030 | cgiCopyTemplateLang("option-pickmany.tmpl"); | |
3031 | break; | |
3032 | } | |
3033 | } | |
ef416fc2 | 3034 | |
323c5de1 | 3035 | cgiCopyTemplateLang("option-trailer.tmpl"); |
3036 | } | |
3037 | } | |
ef416fc2 | 3038 | |
58dc1933 MS |
3039 | if ((attr = ippFindAttribute(response, "job-sheets-supported", |
3040 | IPP_TAG_ZERO)) != NULL) | |
3041 | { | |
3042 | /* | |
3043 | * Add the job sheets options... | |
3044 | */ | |
fa73b229 | 3045 | |
58dc1933 MS |
3046 | cgiSetVariable("GROUP_ID", "CUPS_BANNERS"); |
3047 | cgiSetVariable("GROUP", cgiText(_("Banners"))); | |
3048 | cgiCopyTemplateLang("option-header.tmpl"); | |
ef416fc2 | 3049 | |
58dc1933 MS |
3050 | cgiSetSize("CHOICES", attr->num_values); |
3051 | cgiSetSize("TEXT", attr->num_values); | |
3052 | for (k = 0; k < attr->num_values; k ++) | |
3053 | { | |
3054 | cgiSetArray("CHOICES", k, attr->values[k].string.text); | |
3055 | cgiSetArray("TEXT", k, attr->values[k].string.text); | |
3056 | } | |
ef416fc2 | 3057 | |
58dc1933 | 3058 | attr = ippFindAttribute(response, "job-sheets-default", IPP_TAG_ZERO); |
ef416fc2 | 3059 | |
58dc1933 | 3060 | cgiSetVariable("KEYWORD", "job_sheets_start"); |
eac3a0a0 MS |
3061 | cgiSetVariable("KEYTEXT", |
3062 | /* TRANSLATORS: Banner/cover sheet before the print job. */ | |
3063 | cgiText(_("Starting Banner"))); | |
58dc1933 MS |
3064 | cgiSetVariable("DEFCHOICE", attr != NULL ? |
3065 | attr->values[0].string.text : ""); | |
3066 | ||
3067 | cgiCopyTemplateLang("option-pickone.tmpl"); | |
3068 | ||
3069 | cgiSetVariable("KEYWORD", "job_sheets_end"); | |
eac3a0a0 MS |
3070 | cgiSetVariable("KEYTEXT", |
3071 | /* TRANSLATORS: Banner/cover sheet after the print job. */ | |
3072 | cgiText(_("Ending Banner"))); | |
58dc1933 MS |
3073 | cgiSetVariable("DEFCHOICE", attr != NULL && attr->num_values > 1 ? |
3074 | attr->values[1].string.text : ""); | |
3075 | ||
3076 | cgiCopyTemplateLang("option-pickone.tmpl"); | |
3077 | ||
3078 | cgiCopyTemplateLang("option-trailer.tmpl"); | |
3079 | } | |
3080 | ||
3081 | if (ippFindAttribute(response, "printer-error-policy-supported", | |
3082 | IPP_TAG_ZERO) || | |
3083 | ippFindAttribute(response, "printer-op-policy-supported", | |
3084 | IPP_TAG_ZERO)) | |
323c5de1 | 3085 | { |
58dc1933 MS |
3086 | /* |
3087 | * Add the error and operation policy options... | |
3088 | */ | |
ef416fc2 | 3089 | |
58dc1933 MS |
3090 | cgiSetVariable("GROUP_ID", "CUPS_POLICIES"); |
3091 | cgiSetVariable("GROUP", cgiText(_("Policies"))); | |
3092 | cgiCopyTemplateLang("option-header.tmpl"); | |
3093 | ||
3094 | /* | |
3095 | * Error policy... | |
3096 | */ | |
ef416fc2 | 3097 | |
58dc1933 MS |
3098 | attr = ippFindAttribute(response, "printer-error-policy-supported", |
3099 | IPP_TAG_ZERO); | |
3100 | ||
3101 | if (attr) | |
3102 | { | |
323c5de1 | 3103 | cgiSetSize("CHOICES", attr->num_values); |
3104 | cgiSetSize("TEXT", attr->num_values); | |
3105 | for (k = 0; k < attr->num_values; k ++) | |
3106 | { | |
3107 | cgiSetArray("CHOICES", k, attr->values[k].string.text); | |
3108 | cgiSetArray("TEXT", k, attr->values[k].string.text); | |
3109 | } | |
ef416fc2 | 3110 | |
58dc1933 MS |
3111 | attr = ippFindAttribute(response, "printer-error-policy", |
3112 | IPP_TAG_ZERO); | |
ef416fc2 | 3113 | |
58dc1933 MS |
3114 | cgiSetVariable("KEYWORD", "printer_error_policy"); |
3115 | cgiSetVariable("KEYTEXT", cgiText(_("Error Policy"))); | |
3116 | cgiSetVariable("DEFCHOICE", attr == NULL ? | |
3117 | "" : attr->values[0].string.text); | |
323c5de1 | 3118 | } |
ef416fc2 | 3119 | |
58dc1933 | 3120 | cgiCopyTemplateLang("option-pickone.tmpl"); |
ef416fc2 | 3121 | |
58dc1933 MS |
3122 | /* |
3123 | * Operation policy... | |
3124 | */ | |
ef416fc2 | 3125 | |
58dc1933 MS |
3126 | attr = ippFindAttribute(response, "printer-op-policy-supported", |
3127 | IPP_TAG_ZERO); | |
323c5de1 | 3128 | |
58dc1933 MS |
3129 | if (attr) |
3130 | { | |
3131 | cgiSetSize("CHOICES", attr->num_values); | |
3132 | cgiSetSize("TEXT", attr->num_values); | |
3133 | for (k = 0; k < attr->num_values; k ++) | |
323c5de1 | 3134 | { |
58dc1933 MS |
3135 | cgiSetArray("CHOICES", k, attr->values[k].string.text); |
3136 | cgiSetArray("TEXT", k, attr->values[k].string.text); | |
3137 | } | |
ef416fc2 | 3138 | |
58dc1933 | 3139 | attr = ippFindAttribute(response, "printer-op-policy", IPP_TAG_ZERO); |
ef416fc2 | 3140 | |
58dc1933 MS |
3141 | cgiSetVariable("KEYWORD", "printer_op_policy"); |
3142 | cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy"))); | |
3143 | cgiSetVariable("DEFCHOICE", attr == NULL ? | |
3144 | "" : attr->values[0].string.text); | |
fa73b229 | 3145 | |
323c5de1 | 3146 | cgiCopyTemplateLang("option-pickone.tmpl"); |
323c5de1 | 3147 | } |
ef416fc2 | 3148 | |
58dc1933 | 3149 | cgiCopyTemplateLang("option-trailer.tmpl"); |
ef416fc2 | 3150 | } |
ef416fc2 | 3151 | |
ef416fc2 | 3152 | /* |
323c5de1 | 3153 | * Binary protocol support... |
ef416fc2 | 3154 | */ |
3155 | ||
58dc1933 MS |
3156 | if ((attr = ippFindAttribute(response, "port-monitor-supported", |
3157 | IPP_TAG_NAME)) != NULL && attr->num_values > 1) | |
ef416fc2 | 3158 | { |
58dc1933 MS |
3159 | cgiSetVariable("GROUP_ID", "CUPS_PORT_MONITOR"); |
3160 | cgiSetVariable("GROUP", cgiText(_("Port Monitor"))); | |
ef416fc2 | 3161 | |
58dc1933 MS |
3162 | cgiSetSize("CHOICES", attr->num_values); |
3163 | cgiSetSize("TEXT", attr->num_values); | |
ef416fc2 | 3164 | |
58dc1933 | 3165 | for (i = 0; i < attr->num_values; i ++) |
ef416fc2 | 3166 | { |
58dc1933 MS |
3167 | cgiSetArray("CHOICES", i, attr->values[i].string.text); |
3168 | cgiSetArray("TEXT", i, attr->values[i].string.text); | |
ef416fc2 | 3169 | } |
3170 | ||
58dc1933 MS |
3171 | attr = ippFindAttribute(response, "port-monitor", IPP_TAG_NAME); |
3172 | cgiSetVariable("KEYWORD", "port_monitor"); | |
3173 | cgiSetVariable("KEYTEXT", cgiText(_("Port Monitor"))); | |
3174 | cgiSetVariable("DEFCHOICE", attr ? attr->values[0].string.text : "none"); | |
ef416fc2 | 3175 | |
58dc1933 | 3176 | cgiCopyTemplateLang("option-header.tmpl"); |
323c5de1 | 3177 | cgiCopyTemplateLang("option-pickone.tmpl"); |
323c5de1 | 3178 | cgiCopyTemplateLang("option-trailer.tmpl"); |
ef416fc2 | 3179 | } |
3180 | ||
323c5de1 | 3181 | cgiCopyTemplateLang("set-printer-options-trailer.tmpl"); |
3182 | cgiEndHTML(); | |
58dc1933 MS |
3183 | |
3184 | ippDelete(response); | |
323c5de1 | 3185 | } |
3186 | else | |
3187 | { | |
ef416fc2 | 3188 | /* |
323c5de1 | 3189 | * Set default options... |
ef416fc2 | 3190 | */ |
3191 | ||
323c5de1 | 3192 | fputs("DEBUG: Setting options...\n", stderr); |
ef416fc2 | 3193 | |
323c5de1 | 3194 | if (filename) |
ef416fc2 | 3195 | { |
323c5de1 | 3196 | out = cupsTempFile2(tempfile, sizeof(tempfile)); |
3197 | in = cupsFileOpen(filename, "r"); | |
ef416fc2 | 3198 | |
323c5de1 | 3199 | if (!in || !out) |
ef416fc2 | 3200 | { |
323c5de1 | 3201 | cgiSetVariable("ERROR", strerror(errno)); |
3202 | cgiStartHTML(cgiText(_("Set Printer Options"))); | |
3203 | cgiCopyTemplateLang("error.tmpl"); | |
3204 | cgiEndHTML(); | |
ef416fc2 | 3205 | |
323c5de1 | 3206 | if (in) |
3207 | cupsFileClose(in); | |
ef416fc2 | 3208 | |
323c5de1 | 3209 | if (out) |
ef416fc2 | 3210 | { |
323c5de1 | 3211 | cupsFileClose(out); |
3212 | unlink(tempfile); | |
3213 | } | |
ef416fc2 | 3214 | |
323c5de1 | 3215 | unlink(filename); |
3216 | return; | |
3217 | } | |
ef416fc2 | 3218 | |
323c5de1 | 3219 | while (cupsFileGets(in, line, sizeof(line))) |
3220 | { | |
58dc1933 | 3221 | if (!strncmp(line, "*cupsProtocol:", 14)) |
323c5de1 | 3222 | continue; |
3223 | else if (strncmp(line, "*Default", 8)) | |
3224 | cupsFilePrintf(out, "%s\n", line); | |
ef416fc2 | 3225 | else |
3226 | { | |
3227 | /* | |
323c5de1 | 3228 | * Get default option name... |
ef416fc2 | 3229 | */ |
3230 | ||
323c5de1 | 3231 | strlcpy(keyword, line + 8, sizeof(keyword)); |
3232 | ||
3233 | for (keyptr = keyword; *keyptr; keyptr ++) | |
3234 | if (*keyptr == ':' || isspace(*keyptr & 255)) | |
ef416fc2 | 3235 | break; |
ef416fc2 | 3236 | |
323c5de1 | 3237 | *keyptr = '\0'; |
ef416fc2 | 3238 | |
323c5de1 | 3239 | if (!strcmp(keyword, "PageRegion") || |
3240 | !strcmp(keyword, "PaperDimension") || | |
3241 | !strcmp(keyword, "ImageableArea")) | |
749b1e90 | 3242 | var = get_option_value(ppd, "PageSize", value, sizeof(value)); |
323c5de1 | 3243 | else |
749b1e90 | 3244 | var = get_option_value(ppd, keyword, value, sizeof(value)); |
ef416fc2 | 3245 | |
749b1e90 | 3246 | if (!var) |
323c5de1 | 3247 | cupsFilePrintf(out, "%s\n", line); |
749b1e90 MS |
3248 | else |
3249 | cupsFilePrintf(out, "*Default%s: %s\n", keyword, var); | |
323c5de1 | 3250 | } |
3251 | } | |
ef416fc2 | 3252 | |
323c5de1 | 3253 | cupsFileClose(in); |
3254 | cupsFileClose(out); | |
3255 | } | |
3256 | else | |
3257 | { | |
3258 | /* | |
3259 | * Make sure temporary filename is cleared when there is no PPD... | |
3260 | */ | |
ef416fc2 | 3261 | |
323c5de1 | 3262 | tempfile[0] = '\0'; |
ef416fc2 | 3263 | } |
3264 | ||
323c5de1 | 3265 | /* |
3266 | * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the | |
3267 | * following attributes: | |
3268 | * | |
3269 | * attributes-charset | |
3270 | * attributes-natural-language | |
3271 | * printer-uri | |
3272 | * job-sheets-default | |
3273 | * printer-error-policy | |
3274 | * printer-op-policy | |
3275 | * [ppd file] | |
3276 | */ | |
3277 | ||
3278 | request = ippNewRequest(is_class ? CUPS_ADD_MODIFY_CLASS : | |
3279 | CUPS_ADD_MODIFY_PRINTER); | |
3280 | ||
3281 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", | |
3282 | NULL, uri); | |
3283 | ||
3284 | attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME, | |
3285 | "job-sheets-default", 2, NULL, NULL); | |
86c184ff MS |
3286 | ippSetString(request, &attr, 0, cgiGetVariable("job_sheets_start")); |
3287 | ippSetString(request, &attr, 1, cgiGetVariable("job_sheets_end")); | |
323c5de1 | 3288 | |
3289 | if ((var = cgiGetVariable("printer_error_policy")) != NULL) | |
1f0275e3 MS |
3290 | ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, |
3291 | "printer-error-policy", NULL, var); | |
323c5de1 | 3292 | |
3293 | if ((var = cgiGetVariable("printer_op_policy")) != NULL) | |
1f0275e3 MS |
3294 | ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, |
3295 | "printer-op-policy", NULL, var); | |
323c5de1 | 3296 | |
58dc1933 MS |
3297 | if ((var = cgiGetVariable("port_monitor")) != NULL) |
3298 | ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, | |
3299 | "port-monitor", NULL, var); | |
3300 | ||
ef416fc2 | 3301 | /* |
3302 | * Do the request and get back a response... | |
3303 | */ | |
3304 | ||
323c5de1 | 3305 | if (filename) |
3306 | ippDelete(cupsDoFileRequest(http, request, "/admin/", tempfile)); | |
3307 | else | |
3308 | ippDelete(cupsDoRequest(http, request, "/admin/")); | |
ef416fc2 | 3309 | |
355e94dc MS |
3310 | if (cupsLastError() == IPP_NOT_AUTHORIZED) |
3311 | { | |
3312 | puts("Status: 401\n"); | |
3313 | exit(0); | |
3314 | } | |
3315 | else if (cupsLastError() > IPP_OK_CONFLICT) | |
ef416fc2 | 3316 | { |
323c5de1 | 3317 | cgiStartHTML(title); |
f3c17241 | 3318 | cgiShowIPPError(_("Unable to set options")); |
ef416fc2 | 3319 | } |
3320 | else | |
3321 | { | |
3322 | /* | |
3323 | * Redirect successful updates back to the printer page... | |
3324 | */ | |
3325 | ||
323c5de1 | 3326 | char refresh[1024]; /* Refresh URL */ |
ef416fc2 | 3327 | |
fa73b229 | 3328 | |
323c5de1 | 3329 | cgiFormEncode(uri, printer, sizeof(uri)); |
3330 | snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=/%s/%s", | |
3331 | is_class ? "classes" : "printers", uri); | |
ef416fc2 | 3332 | cgiSetVariable("refresh_page", refresh); |
3333 | ||
323c5de1 | 3334 | cgiStartHTML(title); |
ef416fc2 | 3335 | |
323c5de1 | 3336 | cgiCopyTemplateLang("printer-configured.tmpl"); |
ef416fc2 | 3337 | } |
3338 | ||
3339 | cgiEndHTML(); | |
323c5de1 | 3340 | |
3341 | if (filename) | |
3342 | unlink(tempfile); | |
ef416fc2 | 3343 | } |
323c5de1 | 3344 | |
3345 | if (filename) | |
3346 | unlink(filename); | |
ef416fc2 | 3347 | } |
3348 | ||
3349 | ||
3350 | /* | |
749b1e90 | 3351 | * 'do_set_sharing()' - Set printer-is-shared value. |
ef416fc2 | 3352 | */ |
3353 | ||
3354 | static void | |
fa73b229 | 3355 | do_set_sharing(http_t *http) /* I - HTTP connection */ |
ef416fc2 | 3356 | { |
3357 | ipp_t *request, /* IPP request */ | |
3358 | *response; /* IPP response */ | |
3359 | char uri[HTTP_MAX_URI]; /* Printer URI */ | |
3360 | const char *printer, /* Printer name */ | |
fa73b229 | 3361 | *is_class, /* Is a class? */ |
ef416fc2 | 3362 | *shared; /* Sharing value */ |
ef416fc2 | 3363 | |
3364 | ||
fa73b229 | 3365 | is_class = cgiGetVariable("IS_CLASS"); |
3366 | printer = cgiGetVariable("PRINTER_NAME"); | |
3367 | shared = cgiGetVariable("SHARED"); | |
ef416fc2 | 3368 | |
fa73b229 | 3369 | if (!printer || !shared) |
ef416fc2 | 3370 | { |
4d301e69 | 3371 | cgiSetVariable("ERROR", cgiText(_("Missing form variable"))); |
fa73b229 | 3372 | cgiStartHTML(cgiText(_("Set Publishing"))); |
ef416fc2 | 3373 | cgiCopyTemplateLang("error.tmpl"); |
3374 | cgiEndHTML(); | |
3375 | return; | |
3376 | } | |
3377 | ||
3378 | /* | |
fa73b229 | 3379 | * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the |
3380 | * following attributes: | |
ef416fc2 | 3381 | * |
3382 | * attributes-charset | |
3383 | * attributes-natural-language | |
3384 | * printer-uri | |
3385 | * printer-is-shared | |
3386 | */ | |
3387 | ||
fa73b229 | 3388 | request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER); |
ef416fc2 | 3389 | |
a4d04587 | 3390 | httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, |
3391 | "localhost", 0, is_class ? "/classes/%s" : "/printers/%s", | |
3392 | printer); | |
ef416fc2 | 3393 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", |
3394 | NULL, uri); | |
3395 | ||
7e86f2f6 | 3396 | ippAddBoolean(request, IPP_TAG_OPERATION, "printer-is-shared", (char)atoi(shared)); |
ef416fc2 | 3397 | |
3398 | /* | |
3399 | * Do the request and get back a response... | |
3400 | */ | |
3401 | ||
3402 | if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) | |
3403 | { | |
ef416fc2 | 3404 | cgiSetIPPVars(response, NULL, NULL, NULL, 0); |
3405 | ||
3406 | ippDelete(response); | |
3407 | } | |
ef416fc2 | 3408 | |
355e94dc MS |
3409 | if (cupsLastError() == IPP_NOT_AUTHORIZED) |
3410 | { | |
3411 | puts("Status: 401\n"); | |
3412 | exit(0); | |
3413 | } | |
3414 | else if (cupsLastError() > IPP_OK_CONFLICT) | |
ef416fc2 | 3415 | { |
fa73b229 | 3416 | cgiStartHTML(cgiText(_("Set Publishing"))); |
f3c17241 | 3417 | cgiShowIPPError(_("Unable to change printer-is-shared attribute")); |
ef416fc2 | 3418 | } |
3419 | else | |
3420 | { | |
3421 | /* | |
3422 | * Redirect successful updates back to the printer page... | |
3423 | */ | |
3424 | ||
fa73b229 | 3425 | char url[1024], /* Printer/class URL */ |
3426 | refresh[1024]; /* Refresh URL */ | |
ef416fc2 | 3427 | |
ef416fc2 | 3428 | |
fa73b229 | 3429 | cgiRewriteURL(uri, url, sizeof(url), NULL); |
3430 | cgiFormEncode(uri, url, sizeof(uri)); | |
f301802f | 3431 | snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri); |
fa73b229 | 3432 | cgiSetVariable("refresh_page", refresh); |
ef416fc2 | 3433 | |
fa73b229 | 3434 | cgiStartHTML(cgiText(_("Set Publishing"))); |
3435 | cgiCopyTemplateLang(is_class ? "class-modified.tmpl" : | |
3436 | "printer-modified.tmpl"); | |
ef416fc2 | 3437 | } |
3438 | ||
3439 | cgiEndHTML(); | |
3440 | } | |
3441 | ||
3442 | ||
749b1e90 MS |
3443 | /* |
3444 | * 'get_option_value()' - Return the value of an option. | |
3445 | * | |
3446 | * This function also handles generation of custom option values. | |
3447 | */ | |
3448 | ||
3449 | static char * /* O - Value string or NULL on error */ | |
3450 | get_option_value( | |
3451 | ppd_file_t *ppd, /* I - PPD file */ | |
3452 | const char *name, /* I - Option name */ | |
3453 | char *buffer, /* I - String buffer */ | |
3454 | size_t bufsize) /* I - Size of buffer */ | |
3455 | { | |
3456 | char *bufptr, /* Pointer into buffer */ | |
3457 | *bufend; /* End of buffer */ | |
3458 | ppd_coption_t *coption; /* Custom option */ | |
3459 | ppd_cparam_t *cparam; /* Current custom parameter */ | |
3460 | char keyword[256]; /* Parameter name */ | |
3461 | const char *val, /* Parameter value */ | |
3462 | *uval; /* Units value */ | |
3463 | long integer; /* Integer value */ | |
3464 | double number, /* Number value */ | |
3465 | number_points; /* Number in points */ | |
3466 | ||
3467 | ||
3468 | /* | |
3469 | * See if we have a custom option choice... | |
3470 | */ | |
3471 | ||
3472 | if ((val = cgiGetVariable(name)) == NULL) | |
3473 | { | |
3474 | /* | |
3475 | * Option not found! | |
3476 | */ | |
3477 | ||
3478 | return (NULL); | |
3479 | } | |
88f9aafc | 3480 | else if (_cups_strcasecmp(val, "Custom") || |
749b1e90 MS |
3481 | (coption = ppdFindCustomOption(ppd, name)) == NULL) |
3482 | { | |
3483 | /* | |
3484 | * Not a custom choice... | |
3485 | */ | |
3486 | ||
3487 | strlcpy(buffer, val, bufsize); | |
3488 | return (buffer); | |
3489 | } | |
3490 | ||
3491 | /* | |
3492 | * OK, we have a custom option choice, format it... | |
3493 | */ | |
3494 | ||
3495 | *buffer = '\0'; | |
3496 | ||
3497 | if (!strcmp(coption->keyword, "PageSize")) | |
3498 | { | |
3499 | const char *lval; /* Length string value */ | |
3500 | double width, /* Width value */ | |
3501 | width_points, /* Width in points */ | |
3502 | length, /* Length value */ | |
3503 | length_points; /* Length in points */ | |
3504 | ||
3505 | ||
3506 | val = cgiGetVariable("PageSize.Width"); | |
3507 | lval = cgiGetVariable("PageSize.Height"); | |
3508 | uval = cgiGetVariable("PageSize.Units"); | |
3509 | ||
3510 | if (!val || !lval || !uval || | |
3511 | (width = strtod(val, NULL)) == 0.0 || | |
3512 | (length = strtod(lval, NULL)) == 0.0 || | |
3513 | (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") && | |
3514 | strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m"))) | |
3515 | return (NULL); | |
3516 | ||
3517 | width_points = get_points(width, uval); | |
3518 | length_points = get_points(length, uval); | |
3519 | ||
3520 | if (width_points < ppd->custom_min[0] || | |
3521 | width_points > ppd->custom_max[0] || | |
3522 | length_points < ppd->custom_min[1] || | |
3523 | length_points > ppd->custom_max[1]) | |
3524 | return (NULL); | |
3525 | ||
3526 | snprintf(buffer, bufsize, "Custom.%gx%g%s", width, length, uval); | |
3527 | } | |
ef55b745 | 3528 | else if (cupsArrayCount(coption->params) == 1) |
749b1e90 MS |
3529 | { |
3530 | cparam = ppdFirstCustomParam(coption); | |
3531 | snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword, cparam->name); | |
3532 | ||
3533 | if ((val = cgiGetVariable(keyword)) == NULL) | |
3534 | return (NULL); | |
3535 | ||
3536 | switch (cparam->type) | |
3537 | { | |
8e048e4d MS |
3538 | case PPD_CUSTOM_UNKNOWN : |
3539 | break; | |
3540 | ||
749b1e90 MS |
3541 | case PPD_CUSTOM_CURVE : |
3542 | case PPD_CUSTOM_INVCURVE : | |
3543 | case PPD_CUSTOM_REAL : | |
3544 | if ((number = strtod(val, NULL)) == 0.0 || | |
3545 | number < cparam->minimum.custom_real || | |
3546 | number > cparam->maximum.custom_real) | |
3547 | return (NULL); | |
3548 | ||
3549 | snprintf(buffer, bufsize, "Custom.%g", number); | |
3550 | break; | |
3551 | ||
3552 | case PPD_CUSTOM_INT : | |
3553 | if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN || | |
3554 | integer == LONG_MAX || | |
3555 | integer < cparam->minimum.custom_int || | |
3556 | integer > cparam->maximum.custom_int) | |
3557 | return (NULL); | |
3558 | ||
3559 | snprintf(buffer, bufsize, "Custom.%ld", integer); | |
3560 | break; | |
3561 | ||
3562 | case PPD_CUSTOM_POINTS : | |
3563 | snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword); | |
3564 | ||
3565 | if ((number = strtod(val, NULL)) == 0.0 || | |
3566 | (uval = cgiGetVariable(keyword)) == NULL || | |
3567 | (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") && | |
3568 | strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m"))) | |
3569 | return (NULL); | |
3570 | ||
3571 | number_points = get_points(number, uval); | |
3572 | if (number_points < cparam->minimum.custom_points || | |
3573 | number_points > cparam->maximum.custom_points) | |
3574 | return (NULL); | |
3575 | ||
3576 | snprintf(buffer, bufsize, "Custom.%g%s", number, uval); | |
3577 | break; | |
3578 | ||
3579 | case PPD_CUSTOM_PASSCODE : | |
3580 | for (uval = val; *uval; uval ++) | |
3581 | if (!isdigit(*uval & 255)) | |
3582 | return (NULL); | |
3583 | ||
3584 | case PPD_CUSTOM_PASSWORD : | |
3585 | case PPD_CUSTOM_STRING : | |
3586 | integer = (long)strlen(val); | |
3587 | if (integer < cparam->minimum.custom_string || | |
3588 | integer > cparam->maximum.custom_string) | |
3589 | return (NULL); | |
3590 | ||
3591 | snprintf(buffer, bufsize, "Custom.%s", val); | |
3592 | break; | |
3593 | } | |
3594 | } | |
3595 | else | |
3596 | { | |
3597 | const char *prefix = "{"; /* Prefix string */ | |
3598 | ||
3599 | ||
3600 | bufptr = buffer; | |
3601 | bufend = buffer + bufsize; | |
3602 | ||
3603 | for (cparam = ppdFirstCustomParam(coption); | |
3604 | cparam; | |
3605 | cparam = ppdNextCustomParam(coption)) | |
3606 | { | |
3607 | snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword, | |
3608 | cparam->name); | |
3609 | ||
3610 | if ((val = cgiGetVariable(keyword)) == NULL) | |
3611 | return (NULL); | |
3612 | ||
07623986 | 3613 | snprintf(bufptr, (size_t)(bufend - bufptr), "%s%s=", prefix, cparam->name); |
749b1e90 MS |
3614 | bufptr += strlen(bufptr); |
3615 | prefix = " "; | |
3616 | ||
3617 | switch (cparam->type) | |
3618 | { | |
8e048e4d MS |
3619 | case PPD_CUSTOM_UNKNOWN : |
3620 | break; | |
3621 | ||
749b1e90 MS |
3622 | case PPD_CUSTOM_CURVE : |
3623 | case PPD_CUSTOM_INVCURVE : | |
3624 | case PPD_CUSTOM_REAL : | |
3625 | if ((number = strtod(val, NULL)) == 0.0 || | |
3626 | number < cparam->minimum.custom_real || | |
3627 | number > cparam->maximum.custom_real) | |
3628 | return (NULL); | |
3629 | ||
07623986 | 3630 | snprintf(bufptr, (size_t)(bufend - bufptr), "%g", number); |
749b1e90 MS |
3631 | break; |
3632 | ||
3633 | case PPD_CUSTOM_INT : | |
3634 | if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN || | |
3635 | integer == LONG_MAX || | |
3636 | integer < cparam->minimum.custom_int || | |
3637 | integer > cparam->maximum.custom_int) | |
3638 | return (NULL); | |
3639 | ||
07623986 | 3640 | snprintf(bufptr, (size_t)(bufend - bufptr), "%ld", integer); |
749b1e90 MS |
3641 | break; |
3642 | ||
3643 | case PPD_CUSTOM_POINTS : | |
3644 | snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword); | |
3645 | ||
3646 | if ((number = strtod(val, NULL)) == 0.0 || | |
3647 | (uval = cgiGetVariable(keyword)) == NULL || | |
3648 | (strcmp(uval, "pt") && strcmp(uval, "in") && | |
3649 | strcmp(uval, "ft") && strcmp(uval, "cm") && | |
3650 | strcmp(uval, "mm") && strcmp(uval, "m"))) | |
3651 | return (NULL); | |
3652 | ||
3653 | number_points = get_points(number, uval); | |
3654 | if (number_points < cparam->minimum.custom_points || | |
3655 | number_points > cparam->maximum.custom_points) | |
3656 | return (NULL); | |
3657 | ||
07623986 | 3658 | snprintf(bufptr, (size_t)(bufend - bufptr), "%g%s", number, uval); |
749b1e90 MS |
3659 | break; |
3660 | ||
3661 | case PPD_CUSTOM_PASSCODE : | |
3662 | for (uval = val; *uval; uval ++) | |
3663 | if (!isdigit(*uval & 255)) | |
3664 | return (NULL); | |
3665 | ||
3666 | case PPD_CUSTOM_PASSWORD : | |
3667 | case PPD_CUSTOM_STRING : | |
3668 | integer = (long)strlen(val); | |
3669 | if (integer < cparam->minimum.custom_string || | |
3670 | integer > cparam->maximum.custom_string) | |
3671 | return (NULL); | |
3672 | ||
3673 | if ((bufptr + 2) > bufend) | |
3674 | return (NULL); | |
3675 | ||
3676 | bufend --; | |
3677 | *bufptr++ = '\"'; | |
3678 | ||
3679 | while (*val && bufptr < bufend) | |
3680 | { | |
3681 | if (*val == '\\' || *val == '\"') | |
3682 | { | |
3683 | if ((bufptr + 1) >= bufend) | |
3684 | return (NULL); | |
3685 | ||
3686 | *bufptr++ = '\\'; | |
3687 | } | |
3688 | ||
3689 | *bufptr++ = *val++; | |
3690 | } | |
3691 | ||
3692 | if (bufptr >= bufend) | |
3693 | return (NULL); | |
3694 | ||
3695 | *bufptr++ = '\"'; | |
3696 | *bufptr = '\0'; | |
3697 | bufend ++; | |
3698 | break; | |
3699 | } | |
3700 | ||
3701 | bufptr += strlen(bufptr); | |
3702 | } | |
3703 | ||
3704 | if (bufptr == buffer || (bufend - bufptr) < 2) | |
3705 | return (NULL); | |
3706 | ||
5a9febac | 3707 | memcpy(bufptr, "}", 2); |
749b1e90 MS |
3708 | } |
3709 | ||
3710 | return (buffer); | |
3711 | } | |
3712 | ||
3713 | ||
3714 | /* | |
3715 | * 'get_points()' - Get a value in points. | |
3716 | */ | |
3717 | ||
3718 | static double /* O - Number in points */ | |
3719 | get_points(double number, /* I - Original number */ | |
3720 | const char *uval) /* I - Units */ | |
3721 | { | |
3722 | if (!strcmp(uval, "mm")) /* Millimeters */ | |
3723 | return (number * 72.0 / 25.4); | |
3724 | else if (!strcmp(uval, "cm")) /* Centimeters */ | |
3725 | return (number * 72.0 / 2.54); | |
3726 | else if (!strcmp(uval, "in")) /* Inches */ | |
3727 | return (number * 72.0); | |
3728 | else if (!strcmp(uval, "ft")) /* Feet */ | |
3729 | return (number * 72.0 * 12.0); | |
3730 | else if (!strcmp(uval, "m")) /* Meters */ | |
3731 | return (number * 72.0 / 0.0254); | |
3732 | else /* Points */ | |
3733 | return (number); | |
3734 | } |