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