]> git.ipfire.org Git - thirdparty/cups.git/blame - systemv/lpadmin.c
Remove all of the Subversion keywords from various source files.
[thirdparty/cups.git] / systemv / lpadmin.c
CommitLineData
ef416fc2 1/*
7e86f2f6 2 * "lpadmin" command for CUPS.
ef416fc2 3 *
fffed089 4 * Copyright 2007-2015 by Apple Inc.
7e86f2f6 5 * Copyright 1997-2006 by Easy Software Products.
ef416fc2 6 *
7e86f2f6
MS
7 * These coded instructions, statements, and computer programs are the
8 * property of Apple Inc. and are protected by Federal copyright
9 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
10 * which should have been included with this file. If this file is
11 * file is missing or damaged, see the license at "http://www.cups.org/".
ef416fc2 12 */
13
14/*
15 * Include necessary headers...
16 */
17
fffed089
MS
18#define _CUPS_NO_DEPRECATED
19#define _PPD_DEPRECATED
71e16022 20#include <cups/cups-private.h>
f787e1e3 21#include <cups/ppd-private.h>
ef416fc2 22
23
24/*
25 * Local functions...
26 */
27
eac3a0a0
MS
28static int add_printer_to_class(http_t *http, char *printer, char *pclass);
29static int default_printer(http_t *http, char *printer);
30static int delete_printer(http_t *http, char *printer);
31static int delete_printer_from_class(http_t *http, char *printer,
32 char *pclass);
33static int delete_printer_option(http_t *http, char *printer,
34 char *option);
35static int enable_printer(http_t *http, char *printer);
fffed089 36static char *get_printer_ppd(const char *uri, char *buffer, size_t bufsize);
eac3a0a0
MS
37static cups_ptype_t get_printer_type(http_t *http, char *printer, char *uri,
38 size_t urisize);
39static int set_printer_options(http_t *http, char *printer,
40 int num_options, cups_option_t *options,
41 char *file);
42static int validate_name(const char *name);
ef416fc2 43
44
45/*
46 * 'main()' - Parse options and configure the scheduler.
47 */
48
49int
50main(int argc, /* I - Number of command-line arguments */
51 char *argv[]) /* I - Command-line arguments */
52{
53 int i; /* Looping var */
54 http_t *http; /* Connection to server */
55 char *printer, /* Destination printer */
56 *pclass, /* Printer class name */
57 *val; /* Pointer to allow/deny value */
58 int num_options; /* Number of options */
59 cups_option_t *options; /* Options */
e67e2f9e 60 char *file, /* New PPD file */
fffed089
MS
61 evefile[1024] = "";
62 /* IPP Everywhere PPD */
63 const char *ppd_name, /* ppd-name value */
64 *device_uri; /* device-uri value */
ef416fc2 65
66
07725fee 67 _cupsSetLocale(argv);
d09495fa 68
ef416fc2 69 http = NULL;
70 printer = NULL;
71 num_options = 0;
72 options = NULL;
7cf5915e 73 file = NULL;
ef416fc2 74
75 for (i = 1; i < argc; i ++)
76 if (argv[i][0] == '-')
77 switch (argv[i][1])
78 {
79 case 'c' : /* Add printer to class */
80 if (!http)
81 {
fffed089 82 http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL);
ef416fc2 83
84 if (http == NULL)
85 {
fa73b229 86 _cupsLangPrintf(stderr,
0837b7e8 87 _("lpadmin: Unable to connect to server: %s"),
ef416fc2 88 strerror(errno));
89 return (1);
90 }
91 }
92
93 if (printer == NULL)
94 {
fa73b229 95 _cupsLangPuts(stderr,
ef416fc2 96 _("lpadmin: Unable to add a printer to the class:\n"
97 " You must specify a printer name "
0837b7e8 98 "first."));
ef416fc2 99 return (1);
100 }
101
102 if (argv[i][2])
103 pclass = argv[i] + 2;
104 else
105 {
106 i ++;
107
108 if (i >= argc)
109 {
fa73b229 110 _cupsLangPuts(stderr,
0837b7e8
MS
111 _("lpadmin: Expected class name after \"-c\" "
112 "option."));
ef416fc2 113 return (1);
114 }
115
116 pclass = argv[i];
117 }
118
119 if (!validate_name(pclass))
120 {
fa73b229 121 _cupsLangPuts(stderr,
ef416fc2 122 _("lpadmin: Class name can only contain printable "
0837b7e8 123 "characters."));
ef416fc2 124 return (1);
125 }
126
127 if (add_printer_to_class(http, printer, pclass))
128 return (1);
129 break;
130
131 case 'd' : /* Set as default destination */
132 if (!http)
133 {
fffed089 134 http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL);
ef416fc2 135
136 if (http == NULL)
137 {
fa73b229 138 _cupsLangPrintf(stderr,
0837b7e8 139 _("lpadmin: Unable to connect to server: %s"),
ef416fc2 140 strerror(errno));
141 return (1);
142 }
143 }
144
145 if (argv[i][2])
146 printer = argv[i] + 2;
147 else
148 {
149 i ++;
150
151 if (i >= argc)
152 {
fa73b229 153 _cupsLangPuts(stderr,
0837b7e8
MS
154 _("lpadmin: Expected printer name after \"-d\" "
155 "option."));
ef416fc2 156 return (1);
157 }
158
159 printer = argv[i];
160 }
161
162 if (!validate_name(printer))
163 {
fa73b229 164 _cupsLangPuts(stderr,
ef416fc2 165 _("lpadmin: Printer name can only contain "
0837b7e8 166 "printable characters."));
ef416fc2 167 return (1);
168 }
169
170 if (default_printer(http, printer))
171 return (1);
172
173 i = argc;
174 break;
175
176 case 'h' : /* Connect to host */
177 if (http)
178 {
179 httpClose(http);
180 http = NULL;
181 }
182
183 if (argv[i][2] != '\0')
184 cupsSetServer(argv[i] + 2);
185 else
186 {
187 i ++;
188
189 if (i >= argc)
190 {
fa73b229 191 _cupsLangPuts(stderr,
0837b7e8
MS
192 _("lpadmin: Expected hostname after \"-h\" "
193 "option."));
ef416fc2 194 return (1);
195 }
196
197 cupsSetServer(argv[i]);
198 }
199 break;
200
e67e2f9e
MS
201 case 'P' : /* Use the specified PPD file */
202 case 'i' : /* Use the specified PPD file */
ef416fc2 203 if (argv[i][2])
7cf5915e 204 file = argv[i] + 2;
ef416fc2 205 else
206 {
207 i ++;
208
209 if (i >= argc)
210 {
e67e2f9e 211 _cupsLangPrintf(stderr, _("lpadmin: Expected PPD after \"-%c\" option."), argv[i - 1][1]);
ef416fc2 212 return (1);
213 }
214
7cf5915e 215 file = argv[i];
ef416fc2 216 }
217 break;
218
219 case 'E' : /* Enable the printer */
220 if (printer == NULL)
221 {
222#ifdef HAVE_SSL
fffed089 223 cupsSetEncryption(HTTP_ENCRYPTION_REQUIRED);
ef416fc2 224
225 if (http)
fffed089 226 httpEncryption(http, HTTP_ENCRYPTION_REQUIRED);
ef416fc2 227#else
0837b7e8 228 _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."),
ef416fc2 229 argv[0]);
230#endif /* HAVE_SSL */
231 break;
232 }
233
234 if (!http)
235 {
fffed089 236 http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL);
ef416fc2 237
238 if (http == NULL)
239 {
fa73b229 240 _cupsLangPrintf(stderr,
0837b7e8 241 _("lpadmin: Unable to connect to server: %s"),
ef416fc2 242 strerror(errno));
243 return (1);
244 }
245 }
246
247 if (enable_printer(http, printer))
248 return (1);
249 break;
250
251 case 'm' : /* Use the specified standard script/PPD file */
ef416fc2 252 if (argv[i][2])
7cf5915e
MS
253 num_options = cupsAddOption("ppd-name", argv[i] + 2, num_options,
254 &options);
ef416fc2 255 else
256 {
257 i ++;
258
259 if (i >= argc)
260 {
fa73b229 261 _cupsLangPuts(stderr,
0837b7e8
MS
262 _("lpadmin: Expected model after \"-m\" "
263 "option."));
ef416fc2 264 return (1);
265 }
266
7cf5915e
MS
267 num_options = cupsAddOption("ppd-name", argv[i], num_options,
268 &options);
ef416fc2 269 }
270 break;
271
272 case 'o' : /* Set option */
273 if (argv[i][2])
274 num_options = cupsParseOptions(argv[i] + 2, num_options, &options);
275 else
276 {
277 i ++;
278
279 if (i >= argc)
280 {
fa73b229 281 _cupsLangPuts(stderr,
0837b7e8
MS
282 _("lpadmin: Expected name=value after \"-o\" "
283 "option."));
ef416fc2 284 return (1);
285 }
286
287 num_options = cupsParseOptions(argv[i], num_options, &options);
288 }
289 break;
290
291 case 'p' : /* Add/modify a printer */
ef416fc2 292 if (argv[i][2])
293 printer = argv[i] + 2;
294 else
295 {
296 i ++;
297
298 if (i >= argc)
299 {
fa73b229 300 _cupsLangPuts(stderr,
0837b7e8
MS
301 _("lpadmin: Expected printer after \"-p\" "
302 "option."));
ef416fc2 303 return (1);
304 }
305
306 printer = argv[i];
307 }
308
309 if (!validate_name(printer))
310 {
fa73b229 311 _cupsLangPuts(stderr,
ef416fc2 312 _("lpadmin: Printer name can only contain "
0837b7e8 313 "printable characters."));
ef416fc2 314 return (1);
315 }
316 break;
317
318 case 'r' : /* Remove printer from class */
319 if (!http)
320 {
fffed089 321 http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL);
ef416fc2 322
323 if (http == NULL)
324 {
fa73b229 325 _cupsLangPrintf(stderr,
0837b7e8 326 _("lpadmin: Unable to connect to server: %s"),
ef416fc2 327 strerror(errno));
328 return (1);
329 }
330 }
331
332 if (printer == NULL)
333 {
fa73b229 334 _cupsLangPuts(stderr,
ef416fc2 335 _("lpadmin: Unable to remove a printer from the "
336 "class:\n"
337 " You must specify a printer name "
0837b7e8 338 "first."));
ef416fc2 339 return (1);
340 }
341
342 if (argv[i][2])
343 pclass = argv[i] + 2;
344 else
345 {
346 i ++;
347
348 if (i >= argc)
349 {
fa73b229 350 _cupsLangPuts(stderr,
0837b7e8
MS
351 _("lpadmin: Expected class after \"-r\" "
352 "option."));
ef416fc2 353 return (1);
354 }
355
356 pclass = argv[i];
357 }
358
359 if (!validate_name(pclass))
360 {
fa73b229 361 _cupsLangPuts(stderr,
ef416fc2 362 _("lpadmin: Class name can only contain printable "
0837b7e8 363 "characters."));
ef416fc2 364 return (1);
365 }
366
367 if (delete_printer_from_class(http, printer, pclass))
368 return (1);
369 break;
370
eac3a0a0
MS
371 case 'R' : /* Remove option */
372 if (!http)
373 {
fffed089 374 http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL);
eac3a0a0
MS
375
376 if (http == NULL)
377 {
378 _cupsLangPrintf(stderr,
379 _("lpadmin: Unable to connect to server: %s"),
380 strerror(errno));
381 return (1);
382 }
383 }
384
385 if (printer == NULL)
386 {
387 _cupsLangPuts(stderr,
388 _("lpadmin: Unable to delete option:\n"
389 " You must specify a printer name "
390 "first."));
391 return (1);
392 }
393
394 if (argv[i][2])
395 val = argv[i] + 2;
396 else
397 {
398 i ++;
399
400 if (i >= argc)
401 {
402 _cupsLangPuts(stderr,
403 _("lpadmin: Expected name after \"-R\" "
404 "option."));
405 return (1);
406 }
407
408 val = argv[i];
409 }
410
411 if (delete_printer_option(http, printer, val))
412 return (1);
413 break;
414
f301802f 415 case 'U' : /* Username */
416 if (argv[i][2] != '\0')
417 cupsSetUser(argv[i] + 2);
418 else
419 {
420 i ++;
421 if (i >= argc)
422 {
423 _cupsLangPrintf(stderr,
424 _("%s: Error - expected username after "
0837b7e8 425 "\"-U\" option."), argv[0]);
f301802f 426 return (1);
427 }
428
429 cupsSetUser(argv[i]);
430 }
431 break;
88f9aafc 432
ef416fc2 433 case 'u' : /* Allow/deny users */
434 if (argv[i][2])
435 val = argv[i] + 2;
436 else
437 {
438 i ++;
439
440 if (i >= argc)
441 {
fa73b229 442 _cupsLangPuts(stderr,
ef416fc2 443 _("lpadmin: Expected allow/deny:userlist after "
0837b7e8 444 "\"-u\" option."));
ef416fc2 445 return (1);
446 }
447
448 val = argv[i];
449 }
450
88f9aafc 451 if (!_cups_strncasecmp(val, "allow:", 6))
ef416fc2 452 num_options = cupsAddOption("requesting-user-name-allowed",
453 val + 6, num_options, &options);
88f9aafc 454 else if (!_cups_strncasecmp(val, "deny:", 5))
ef416fc2 455 num_options = cupsAddOption("requesting-user-name-denied",
456 val + 5, num_options, &options);
457 else
458 {
fa73b229 459 _cupsLangPrintf(stderr,
0837b7e8 460 _("lpadmin: Unknown allow/deny option \"%s\"."),
ef416fc2 461 val);
462 return (1);
463 }
464 break;
465
466 case 'v' : /* Set the device-uri attribute */
ef416fc2 467 if (argv[i][2])
7cf5915e
MS
468 num_options = cupsAddOption("device-uri", argv[i] + 2,
469 num_options, &options);
ef416fc2 470 else
471 {
472 i ++;
473
474 if (i >= argc)
475 {
fa73b229 476 _cupsLangPuts(stderr,
0837b7e8
MS
477 _("lpadmin: Expected device URI after \"-v\" "
478 "option."));
ef416fc2 479 return (1);
480 }
481
7cf5915e
MS
482 num_options = cupsAddOption("device-uri", argv[i],
483 num_options, &options);
ef416fc2 484 }
485 break;
486
487 case 'x' : /* Delete a printer */
488 if (!http)
489 {
fffed089 490 http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL);
ef416fc2 491
492 if (http == NULL)
493 {
fa73b229 494 _cupsLangPrintf(stderr,
0837b7e8 495 _("lpadmin: Unable to connect to server: %s"),
ef416fc2 496 strerror(errno));
497 return (1);
498 }
499 }
500
501 if (argv[i][2])
502 printer = argv[i] + 2;
503 else
504 {
505 i ++;
506
507 if (i >= argc)
508 {
fa73b229 509 _cupsLangPuts(stderr,
ef416fc2 510 _("lpadmin: Expected printer or class after "
0837b7e8 511 "\"-x\" option."));
ef416fc2 512 return (1);
513 }
514
515 printer = argv[i];
516 }
517
518 if (!validate_name(printer))
519 {
fa73b229 520 _cupsLangPuts(stderr,
ef416fc2 521 _("lpadmin: Printer name can only contain "
0837b7e8 522 "printable characters."));
ef416fc2 523 return (1);
524 }
525
526 if (delete_printer(http, printer))
527 return (1);
528
529 i = argc;
530 break;
531
532 case 'D' : /* Set the printer-info attribute */
ef416fc2 533 if (argv[i][2])
7cf5915e
MS
534 num_options = cupsAddOption("printer-info", argv[i] + 2,
535 num_options, &options);
ef416fc2 536 else
537 {
538 i ++;
539
540 if (i >= argc)
541 {
fa73b229 542 _cupsLangPuts(stderr,
ef416fc2 543 _("lpadmin: Expected description after "
0837b7e8 544 "\"-D\" option."));
ef416fc2 545 return (1);
546 }
547
7cf5915e
MS
548 num_options = cupsAddOption("printer-info", argv[i],
549 num_options, &options);
ef416fc2 550 }
551 break;
552
553 case 'I' : /* Set the supported file types (ignored) */
554 i ++;
555
556 if (i >= argc)
557 {
fa73b229 558 _cupsLangPuts(stderr,
0837b7e8
MS
559 _("lpadmin: Expected file type(s) after \"-I\" "
560 "option."));
ef416fc2 561 return (1);
562 }
563
fa73b229 564 _cupsLangPuts(stderr,
0837b7e8 565 _("lpadmin: Warning - content type list ignored."));
ef416fc2 566 break;
88f9aafc 567
ef416fc2 568 case 'L' : /* Set the printer-location attribute */
ef416fc2 569 if (argv[i][2])
7cf5915e
MS
570 num_options = cupsAddOption("printer-location", argv[i] + 2,
571 num_options, &options);
ef416fc2 572 else
573 {
574 i ++;
575
576 if (i >= argc)
577 {
fa73b229 578 _cupsLangPuts(stderr,
0837b7e8
MS
579 _("lpadmin: Expected location after \"-L\" "
580 "option."));
ef416fc2 581 return (1);
582 }
583
7cf5915e
MS
584 num_options = cupsAddOption("printer-location", argv[i],
585 num_options, &options);
ef416fc2 586 }
587 break;
588
ef416fc2 589 default :
fa73b229 590 _cupsLangPrintf(stderr,
0837b7e8 591 _("lpadmin: Unknown option \"%c\"."), argv[i][1]);
ef416fc2 592 return (1);
593 }
594 else
595 {
0837b7e8 596 _cupsLangPrintf(stderr, _("lpadmin: Unknown argument \"%s\"."),
ef416fc2 597 argv[i]);
598 return (1);
599 }
600
601 /*
602 * Set options as needed...
603 */
604
fffed089
MS
605 if ((ppd_name = cupsGetOption("ppd-name", num_options, options)) != NULL && !strcmp(ppd_name, "everywhere") && (device_uri = cupsGetOption("device-uri", num_options, options)) != NULL)
606 {
607 if ((file = get_printer_ppd(device_uri, evefile, sizeof(evefile))) == NULL)
608 return (1);
609
610 num_options = cupsRemoveOption("ppd-name", num_options, &options);
611 }
612
7cf5915e 613 if (num_options || file)
ef416fc2 614 {
615 if (!http)
616 {
fffed089 617 http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL);
ef416fc2 618
619 if (http == NULL)
620 {
fa73b229 621 _cupsLangPrintf(stderr,
0837b7e8 622 _("lpadmin: Unable to connect to server: %s"),
ef416fc2 623 strerror(errno));
624 return (1);
625 }
626 }
627
628 if (printer == NULL)
629 {
fa73b229 630 _cupsLangPuts(stderr,
ef416fc2 631 _("lpadmin: Unable to set the printer options:\n"
0837b7e8 632 " You must specify a printer name first."));
ef416fc2 633 return (1);
634 }
635
7cf5915e 636 if (set_printer_options(http, printer, num_options, options, file))
ef416fc2 637 return (1);
638 }
639
fffed089
MS
640 if (evefile[0])
641 unlink(evefile);
642
ef416fc2 643 if (printer == NULL)
644 {
fa73b229 645 _cupsLangPuts(stdout,
ef416fc2 646 _("Usage:\n"
647 "\n"
648 " lpadmin [-h server] -d destination\n"
649 " lpadmin [-h server] -x destination\n"
650 " lpadmin [-h server] -p printer [-c add-class] "
651 "[-i interface] [-m model]\n"
652 " [-r remove-class] [-v device] "
653 "[-D description]\n"
654 " [-P ppd-file] [-o name=value]\n"
655 " [-u allow:user,user] "
0837b7e8 656 "[-u deny:user,user]"));
ef416fc2 657 }
658
659 if (http)
660 httpClose(http);
661
662 return (0);
663}
664
665
666/*
667 * 'add_printer_to_class()' - Add a printer to a class.
668 */
669
670static int /* O - 0 on success, 1 on fail */
671add_printer_to_class(http_t *http, /* I - Server connection */
672 char *printer, /* I - Printer to add */
673 char *pclass) /* I - Class to add to */
674{
675 int i; /* Looping var */
676 ipp_t *request, /* IPP Request */
677 *response; /* IPP Response */
678 ipp_attribute_t *attr, /* Current attribute */
679 *members; /* Members in class */
ef416fc2 680 char uri[HTTP_MAX_URI]; /* URI for printer/class */
681
682
683 DEBUG_printf(("add_printer_to_class(%p, \"%s\", \"%s\")\n", http,
684 printer, pclass));
685
686 /*
fffed089 687 * Build an IPP_OP_GET_PRINTER_ATTRIBUTES request, which requires the following
ef416fc2 688 * attributes:
689 *
690 * attributes-charset
691 * attributes-natural-language
692 * printer-uri
eac3a0a0 693 * requesting-user-name
ef416fc2 694 */
695
fffed089 696 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
fa73b229 697
a4d04587 698 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
699 "localhost", 0, "/classes/%s", pclass);
ef416fc2 700 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
701 "printer-uri", NULL, uri);
eac3a0a0
MS
702 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
703 NULL, cupsUser());
ef416fc2 704
705 /*
706 * Do the request and get back a response...
707 */
708
709 response = cupsDoRequest(http, request, "/");
710
711 /*
fffed089 712 * Build a CUPS-Add-Modify-Class request, which requires the following
ef416fc2 713 * attributes:
714 *
715 * attributes-charset
716 * attributes-natural-language
717 * printer-uri
eac3a0a0 718 * requesting-user-name
ef416fc2 719 * member-uris
720 */
721
fffed089 722 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_CLASS);
ef416fc2 723
724 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
725 "printer-uri", NULL, uri);
eac3a0a0
MS
726 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
727 NULL, cupsUser());
ef416fc2 728
729 /*
730 * See if the printer is already in the class...
731 */
732
733 if (response != NULL &&
eac3a0a0
MS
734 (members = ippFindAttribute(response, "member-names",
735 IPP_TAG_NAME)) != NULL)
ef416fc2 736 for (i = 0; i < members->num_values; i ++)
88f9aafc 737 if (_cups_strcasecmp(printer, members->values[i].string.text) == 0)
ef416fc2 738 {
fa73b229 739 _cupsLangPrintf(stderr,
0837b7e8
MS
740 _("lpadmin: Printer %s is already a member of class "
741 "%s."), printer, pclass);
ef416fc2 742 ippDelete(request);
743 ippDelete(response);
744 return (0);
745 }
746
747 /*
748 * OK, the printer isn't part of the class, so add it...
749 */
750
a4d04587 751 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
752 "localhost", 0, "/printers/%s", printer);
ef416fc2 753
754 if (response != NULL &&
eac3a0a0
MS
755 (members = ippFindAttribute(response, "member-uris",
756 IPP_TAG_URI)) != NULL)
ef416fc2 757 {
758 /*
759 * Add the printer to the existing list...
760 */
761
762 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI,
763 "member-uris", members->num_values + 1, NULL, NULL);
764 for (i = 0; i < members->num_values; i ++)
eac3a0a0
MS
765 attr->values[i].string.text =
766 _cupsStrAlloc(members->values[i].string.text);
ef416fc2 767
1f0275e3 768 attr->values[i].string.text = _cupsStrAlloc(uri);
ef416fc2 769 }
770 else
1f0275e3
MS
771 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "member-uris", NULL,
772 uri);
ef416fc2 773
774 /*
775 * Then send the request...
776 */
777
778 ippDelete(response);
779
eac3a0a0 780 ippDelete(cupsDoRequest(http, request, "/admin/"));
fffed089 781 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
ef416fc2 782 {
eac3a0a0 783 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
ef416fc2 784
785 return (1);
786 }
787 else
ef416fc2 788 return (0);
ef416fc2 789}
790
791
792/*
793 * 'default_printer()' - Set the default printing destination.
794 */
795
796static int /* O - 0 on success, 1 on fail */
797default_printer(http_t *http, /* I - Server connection */
798 char *printer) /* I - Printer name */
799{
eac3a0a0 800 ipp_t *request; /* IPP Request */
ef416fc2 801 char uri[HTTP_MAX_URI]; /* URI for printer/class */
802
803
804 DEBUG_printf(("default_printer(%p, \"%s\")\n", http, printer));
805
806 /*
fffed089 807 * Build a CUPS-Set-Default request, which requires the following
ef416fc2 808 * attributes:
809 *
810 * attributes-charset
811 * attributes-natural-language
812 * printer-uri
eac3a0a0 813 * requesting-user-name
ef416fc2 814 */
815
a4d04587 816 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
817 "localhost", 0, "/printers/%s", printer);
ef416fc2 818
fffed089 819 request = ippNewRequest(IPP_OP_CUPS_SET_DEFAULT);
ef416fc2 820
821 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
822 "printer-uri", NULL, uri);
eac3a0a0
MS
823 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
824 NULL, cupsUser());
ef416fc2 825
826 /*
827 * Do the request and get back a response...
828 */
829
eac3a0a0 830 ippDelete(cupsDoRequest(http, request, "/admin/"));
ef416fc2 831
fffed089 832 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
ef416fc2 833 {
eac3a0a0 834 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
ef416fc2 835
836 return (1);
837 }
838 else
ef416fc2 839 return (0);
ef416fc2 840}
841
842
843/*
844 * 'delete_printer()' - Delete a printer from the system...
845 */
846
847static int /* O - 0 on success, 1 on fail */
848delete_printer(http_t *http, /* I - Server connection */
849 char *printer) /* I - Printer to delete */
850{
eac3a0a0 851 ipp_t *request; /* IPP Request */
ef416fc2 852 char uri[HTTP_MAX_URI]; /* URI for printer/class */
853
854
855 DEBUG_printf(("delete_printer(%p, \"%s\")\n", http, printer));
856
857 /*
fffed089 858 * Build a CUPS-Delete-Printer request, which requires the following
ef416fc2 859 * attributes:
860 *
861 * attributes-charset
862 * attributes-natural-language
863 * printer-uri
eac3a0a0 864 * requesting-user-name
ef416fc2 865 */
866
fffed089 867 request = ippNewRequest(IPP_OP_CUPS_DELETE_PRINTER);
fa73b229 868
a4d04587 869 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
870 "localhost", 0, "/printers/%s", printer);
ef416fc2 871 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
872 "printer-uri", NULL, uri);
eac3a0a0
MS
873 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
874 NULL, cupsUser());
ef416fc2 875
876 /*
877 * Do the request and get back a response...
878 */
879
eac3a0a0 880 ippDelete(cupsDoRequest(http, request, "/admin/"));
ef416fc2 881
fffed089 882 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
ef416fc2 883 {
eac3a0a0 884 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
ef416fc2 885
886 return (1);
887 }
888 else
ef416fc2 889 return (0);
ef416fc2 890}
891
892
893/*
894 * 'delete_printer_from_class()' - Delete a printer from a class.
895 */
896
897static int /* O - 0 on success, 1 on fail */
fa73b229 898delete_printer_from_class(
899 http_t *http, /* I - Server connection */
900 char *printer, /* I - Printer to remove */
901 char *pclass) /* I - Class to remove from */
ef416fc2 902{
903 int i, j, k; /* Looping vars */
904 ipp_t *request, /* IPP Request */
905 *response; /* IPP Response */
906 ipp_attribute_t *attr, /* Current attribute */
907 *members; /* Members in class */
ef416fc2 908 char uri[HTTP_MAX_URI]; /* URI for printer/class */
909
910
911 DEBUG_printf(("delete_printer_from_class(%p, \"%s\", \"%s\")\n", http,
912 printer, pclass));
913
914 /*
fffed089 915 * Build an IPP_OP_GET_PRINTER_ATTRIBUTES request, which requires the following
ef416fc2 916 * attributes:
917 *
918 * attributes-charset
919 * attributes-natural-language
920 * printer-uri
eac3a0a0 921 * requesting-user-name
ef416fc2 922 */
923
fffed089 924 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
fa73b229 925
a4d04587 926 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
927 "localhost", 0, "/classes/%s", pclass);
ef416fc2 928 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
929 "printer-uri", NULL, uri);
eac3a0a0
MS
930 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
931 NULL, cupsUser());
ef416fc2 932
933 /*
934 * Do the request and get back a response...
935 */
936
937 if ((response = cupsDoRequest(http, request, "/classes/")) == NULL ||
fffed089 938 response->request.status.status_code == IPP_STATUS_ERROR_NOT_FOUND)
ef416fc2 939 {
eac3a0a0 940 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
fa73b229 941
ef416fc2 942 ippDelete(response);
fa73b229 943
ef416fc2 944 return (1);
945 }
946
947 /*
948 * See if the printer is already in the class...
949 */
950
951 if ((members = ippFindAttribute(response, "member-names", IPP_TAG_NAME)) == NULL)
952 {
0837b7e8 953 _cupsLangPuts(stderr, _("lpadmin: No member names were seen."));
fa73b229 954
ef416fc2 955 ippDelete(response);
fa73b229 956
ef416fc2 957 return (1);
958 }
959
960 for (i = 0; i < members->num_values; i ++)
88f9aafc 961 if (!_cups_strcasecmp(printer, members->values[i].string.text))
ef416fc2 962 break;
963
964 if (i >= members->num_values)
965 {
fa73b229 966 _cupsLangPrintf(stderr,
0837b7e8 967 _("lpadmin: Printer %s is not a member of class %s."),
fa73b229 968 printer, pclass);
969
ef416fc2 970 ippDelete(response);
fa73b229 971
ef416fc2 972 return (1);
973 }
974
975 if (members->num_values == 1)
976 {
977 /*
fffed089 978 * Build a CUPS-Delete-Class request, which requires the following
ef416fc2 979 * attributes:
980 *
981 * attributes-charset
982 * attributes-natural-language
983 * printer-uri
eac3a0a0 984 * requesting-user-name
ef416fc2 985 */
986
fffed089 987 request = ippNewRequest(IPP_OP_CUPS_DELETE_CLASS);
ef416fc2 988
989 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
990 "printer-uri", NULL, uri);
eac3a0a0
MS
991 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
992 "requesting-user-name", NULL, cupsUser());
ef416fc2 993 }
994 else
995 {
996 /*
fffed089 997 * Build a IPP_OP_CUPS_ADD_MODIFY_CLASS request, which requires the following
ef416fc2 998 * attributes:
999 *
1000 * attributes-charset
1001 * attributes-natural-language
1002 * printer-uri
eac3a0a0 1003 * requesting-user-name
ef416fc2 1004 * member-uris
1005 */
1006
fffed089 1007 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_CLASS);
ef416fc2 1008
1009 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1010 "printer-uri", NULL, uri);
eac3a0a0
MS
1011 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1012 "requesting-user-name", NULL, cupsUser());
ef416fc2 1013
1014 /*
1015 * Delete the printer from the class...
1016 */
1017
1018 members = ippFindAttribute(response, "member-uris", IPP_TAG_URI);
1019 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI,
1020 "member-uris", members->num_values - 1, NULL, NULL);
1021
1022 for (j = 0, k = 0; j < members->num_values; j ++)
1023 if (j != i)
1f0275e3
MS
1024 attr->values[k ++].string.text =
1025 _cupsStrAlloc(members->values[j].string.text);
ef416fc2 1026 }
1027
1028 /*
1029 * Then send the request...
1030 */
1031
1032 ippDelete(response);
1033
eac3a0a0
MS
1034 ippDelete(cupsDoRequest(http, request, "/admin/"));
1035
fffed089 1036 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
ef416fc2 1037 {
eac3a0a0 1038 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
fa73b229 1039
ef416fc2 1040 return (1);
1041 }
eac3a0a0
MS
1042 else
1043 return (0);
1044}
ef416fc2 1045
ef416fc2 1046
eac3a0a0
MS
1047/*
1048 * 'delete_printer_option()' - Delete a printer option.
1049 */
1050
1051static int /* O - 0 on success, 1 on fail */
1052delete_printer_option(http_t *http, /* I - Server connection */
1053 char *printer, /* I - Printer */
1054 char *option) /* I - Option to delete */
1055{
1056 ipp_t *request; /* IPP request */
1057 char uri[HTTP_MAX_URI]; /* URI for printer/class */
1058
1059
1060 /*
fffed089 1061 * Build a IPP_OP_CUPS_ADD_MODIFY_PRINTER or IPP_OP_CUPS_ADD_MODIFY_CLASS request, which
eac3a0a0
MS
1062 * requires the following attributes:
1063 *
1064 * attributes-charset
1065 * attributes-natural-language
1066 * printer-uri
1067 * requesting-user-name
1068 * option with deleteAttr tag
1069 */
1070
a2326b5b 1071 if (get_printer_type(http, printer, uri, sizeof(uri)) & CUPS_PRINTER_CLASS)
fffed089 1072 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_CLASS);
ef416fc2 1073 else
fffed089 1074 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_PRINTER);
eac3a0a0
MS
1075
1076 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1077 "printer-uri", NULL, uri);
1078 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1079 "requesting-user-name", NULL, cupsUser());
1080 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_DELETEATTR, option, 0);
1081
1082 /*
1083 * Do the request and get back a response...
1084 */
1085
1086 ippDelete(cupsDoRequest(http, request, "/admin/"));
1087
fffed089 1088 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
ef416fc2 1089 {
eac3a0a0 1090 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
ef416fc2 1091
eac3a0a0 1092 return (1);
ef416fc2 1093 }
eac3a0a0
MS
1094 else
1095 return (0);
ef416fc2 1096}
1097
1098
1099/*
1100 * 'enable_printer()' - Enable a printer...
1101 */
1102
1103static int /* O - 0 on success, 1 on fail */
1104enable_printer(http_t *http, /* I - Server connection */
1105 char *printer) /* I - Printer to enable */
1106{
eac3a0a0 1107 ipp_t *request; /* IPP Request */
ef416fc2 1108 char uri[HTTP_MAX_URI]; /* URI for printer/class */
1109
1110
1111 DEBUG_printf(("enable_printer(%p, \"%s\")\n", http, printer));
1112
1113 /*
fffed089 1114 * Build a IPP_OP_CUPS_ADD_MODIFY_PRINTER or IPP_OP_CUPS_ADD_MODIFY_CLASS request, which
eac3a0a0 1115 * require the following attributes:
ef416fc2 1116 *
1117 * attributes-charset
1118 * attributes-natural-language
1119 * printer-uri
eac3a0a0 1120 * requesting-user-name
ef416fc2 1121 * printer-state
1122 * printer-is-accepting-jobs
1123 */
1124
a2326b5b 1125 if (get_printer_type(http, printer, uri, sizeof(uri)) & CUPS_PRINTER_CLASS)
fffed089 1126 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_CLASS);
eac3a0a0 1127 else
fffed089 1128 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_PRINTER);
fa73b229 1129
ef416fc2 1130 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1131 "printer-uri", NULL, uri);
eac3a0a0
MS
1132 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1133 "requesting-user-name", NULL, cupsUser());
ef416fc2 1134 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
fffed089 1135 IPP_PSTATE_IDLE);
ef416fc2 1136 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
1137
1138 /*
1139 * Do the request and get back a response...
1140 */
1141
eac3a0a0 1142 ippDelete(cupsDoRequest(http, request, "/admin/"));
fa73b229 1143
fffed089 1144 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
ef416fc2 1145 {
eac3a0a0 1146 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
ef416fc2 1147
1148 return (1);
1149 }
1150 else
eac3a0a0
MS
1151 return (0);
1152}
1153
1154
fffed089
MS
1155/*
1156 * 'get_printer_ppd()' - Get an IPP Everywhere PPD file for the given URI.
1157 */
1158
1159static char * /* O - Filename or NULL */
1160get_printer_ppd(const char *uri, /* I - Printer URI */
1161 char *buffer, /* I - Filename buffer */
1162 size_t bufsize) /* I - Size of filename buffer */
1163{
1164 http_t *http; /* Connection to printer */
1165 ipp_t *request, /* Get-Printer-Attributes request */
1166 *response; /* Get-Printer-Attributes response */
fb2d5470
MS
1167 char resolved[1024], /* Resolved URI */
1168 scheme[32], /* URI scheme */
fffed089
MS
1169 userpass[256], /* Username:password */
1170 host[256], /* Hostname */
1171 resource[256]; /* Resource path */
1172 int port; /* Port number */
1173
1174
1175 /*
1176 * Connect to the printer...
1177 */
1178
fb2d5470
MS
1179 if (strstr(uri, "._tcp"))
1180 {
1181 /*
1182 * Resolve URI...
1183 */
1184
1185 if (!_httpResolveURI(uri, resolved, sizeof(resolved), _HTTP_RESOLVE_DEFAULT, NULL, NULL))
1186 {
1187 _cupsLangPrintf(stderr, _("%s: Unable to resolve \"%s\"."), "lpadmin", uri);
1188 return (NULL);
1189 }
1190
1191 uri = resolved;
1192 }
1193
fffed089
MS
1194 if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
1195 {
1196 _cupsLangPrintf(stderr, _("%s: Bad printer URI \"%s\"."), "lpadmin", uri);
1197 return (NULL);
1198 }
1199
1200 http = httpConnect2(host, port, NULL, AF_UNSPEC, !strcmp(scheme, "ipps") ? HTTP_ENCRYPTION_ALWAYS : HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL);
1201 if (!http)
1202 {
1203 _cupsLangPrintf(stderr, _("%s: Unable to connect to \"%s:%d\": %s"), "lpadmin", host, port, cupsLastErrorString());
1204 return (NULL);
1205 }
1206
1207 /*
1208 * Send a Get-Printer-Attributes request...
1209 */
1210
1211 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
1212 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1213 response = cupsDoRequest(http, request, resource);
1214
1215 if (!_ppdCreateFromIPP(buffer, bufsize, response))
1216 _cupsLangPrintf(stderr, _("%s: Unable to create PPD file: %s"), "lpadmin", strerror(errno));
1217
1218 ippDelete(response);
1219 httpClose(http);
1220
1221 if (buffer[0])
1222 return (buffer);
1223 else
1224 return (NULL);
1225}
1226
1227
eac3a0a0
MS
1228/*
1229 * 'get_printer_type()' - Determine the printer type and URI.
1230 */
1231
1232static cups_ptype_t /* O - printer-type value */
1233get_printer_type(http_t *http, /* I - Server connection */
1234 char *printer, /* I - Printer name */
1235 char *uri, /* I - URI buffer */
1236 size_t urisize) /* I - Size of URI buffer */
1237{
1238 ipp_t *request, /* IPP request */
1239 *response; /* IPP response */
1240 ipp_attribute_t *attr; /* printer-type attribute */
1241 cups_ptype_t type; /* printer-type value */
1242
1243
1244 /*
1245 * Build a GET_PRINTER_ATTRIBUTES request, which requires the following
1246 * attributes:
1247 *
1248 * attributes-charset
1249 * attributes-natural-language
1250 * printer-uri
1251 * requested-attributes
1252 * requesting-user-name
1253 */
1254
7e86f2f6 1255 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, (int)urisize, "ipp", NULL, "localhost", ippPort(), "/printers/%s", printer);
eac3a0a0 1256
fffed089 1257 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
eac3a0a0
MS
1258 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1259 "printer-uri", NULL, uri);
1260 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1261 "requested-attributes", NULL, "printer-type");
1262 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1263 "requesting-user-name", NULL, cupsUser());
1264
1265 /*
1266 * Do the request...
1267 */
1268
1269 response = cupsDoRequest(http, request, "/");
1270 if ((attr = ippFindAttribute(response, "printer-type",
1271 IPP_TAG_ENUM)) != NULL)
ef416fc2 1272 {
eac3a0a0 1273 type = (cups_ptype_t)attr->values[0].integer;
ef416fc2 1274
a2326b5b 1275 if (type & CUPS_PRINTER_CLASS)
7e86f2f6 1276 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, (int)urisize, "ipp", NULL, "localhost", ippPort(), "/classes/%s", printer);
ef416fc2 1277 }
eac3a0a0
MS
1278 else
1279 type = CUPS_PRINTER_LOCAL;
1280
1281 ippDelete(response);
1282
1283 return (type);
ef416fc2 1284}
1285
1286
ef416fc2 1287/*
1288 * 'set_printer_options()' - Set the printer options.
1289 */
1290
1291static int /* O - 0 on success, 1 on fail */
fa73b229 1292set_printer_options(
1293 http_t *http, /* I - Server connection */
1294 char *printer, /* I - Printer */
1295 int num_options, /* I - Number of options */
7cf5915e
MS
1296 cups_option_t *options, /* I - Options */
1297 char *file) /* I - PPD file/interface script */
ef416fc2 1298{
eac3a0a0 1299 ipp_t *request; /* IPP Request */
b423cd4c 1300 const char *ppdfile; /* PPD filename */
61c9d9f8 1301 int ppdchanged = 0; /* PPD changed? */
b423cd4c 1302 ppd_file_t *ppd; /* PPD file */
1303 ppd_choice_t *choice; /* Marked choice */
ef416fc2 1304 char uri[HTTP_MAX_URI], /* URI for printer/class */
1305 line[1024], /* Line from PPD file */
1306 keyword[1024], /* Keyword from Default line */
1307 *keyptr, /* Pointer into keyword... */
1308 tempfile[1024]; /* Temporary filename */
7cf5915e 1309 cups_file_t *in, /* PPD file */
ef416fc2 1310 *out; /* Temporary file */
61c9d9f8
MS
1311 const char *ppdname, /* ppd-name value */
1312 *protocol, /* Old protocol option */
eac3a0a0
MS
1313 *customval, /* Custom option value */
1314 *boolval; /* Boolean value */
1315 int wrote_ipp_supplies = 0, /* Wrote cupsIPPSupplies keyword? */
61c9d9f8
MS
1316 wrote_snmp_supplies = 0,/* Wrote cupsSNMPSupplies keyword? */
1317 copied_options = 0; /* Copied options? */
ef416fc2 1318
1319
7cf5915e
MS
1320 DEBUG_printf(("set_printer_options(http=%p, printer=\"%s\", num_options=%d, "
1321 "options=%p, file=\"%s\")\n", http, printer, num_options,
1322 options, file));
ef416fc2 1323
ef416fc2 1324 /*
fffed089
MS
1325 * Build a CUPS-Add-Modify-Printer or CUPS-Add-Modify-Class request,
1326 * which requires the following attributes:
ef416fc2 1327 *
1328 * attributes-charset
1329 * attributes-natural-language
1330 * printer-uri
eac3a0a0 1331 * requesting-user-name
ef416fc2 1332 * other options
1333 */
1334
a2326b5b 1335 if (get_printer_type(http, printer, uri, sizeof(uri)) & CUPS_PRINTER_CLASS)
fffed089 1336 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_CLASS);
eac3a0a0 1337 else
fffed089 1338 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_PRINTER);
ef416fc2 1339
fffed089
MS
1340 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1341 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
ef416fc2 1342
1343 /*
1344 * Add the options...
1345 */
1346
fffed089
MS
1347 if (file)
1348 ppdfile = file;
61c9d9f8
MS
1349 else if ((ppdname = cupsGetOption("ppd-name", num_options, options)) != NULL && strcmp(ppdname, "raw") && num_options > 1)
1350 {
1351 if ((ppdfile = cupsGetServerPPD(http, ppdname)) != NULL)
1352 {
1353 /*
1354 * Copy options array and remove ppd-name from it...
1355 */
1356
1357 cups_option_t *temp = NULL, *optr;
1358 int i, num_temp = 0;
1359 for (i = num_options, optr = options; i > 0; i --, optr ++)
1360 if (strcmp(optr->name, "ppd-name"))
1361 num_temp = cupsAddOption(optr->name, optr->value, num_temp, &temp);
1362
1363 copied_options = 1;
1364 ppdchanged = 1;
1365 num_options = num_temp;
1366 options = temp;
1367 }
1368 }
fffed089
MS
1369 else if (request->request.op.operation_id == IPP_OP_CUPS_ADD_MODIFY_PRINTER)
1370 ppdfile = cupsGetPPD(printer);
1371 else
1372 ppdfile = NULL;
1373
b0f26938 1374 cupsEncodeOptions2(request, num_options, options, IPP_TAG_OPERATION);
b423cd4c 1375 cupsEncodeOptions2(request, num_options, options, IPP_TAG_PRINTER);
1376
1377 if ((protocol = cupsGetOption("protocol", num_options, options)) != NULL)
1378 {
88f9aafc 1379 if (!_cups_strcasecmp(protocol, "bcp"))
a41f09e2 1380 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor",
b423cd4c 1381 NULL, "bcp");
88f9aafc 1382 else if (!_cups_strcasecmp(protocol, "tbcp"))
a41f09e2 1383 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor",
b423cd4c 1384 NULL, "tbcp");
1385 }
ef416fc2 1386
fffed089 1387 if (ppdfile)
ef416fc2 1388 {
1389 /*
1390 * Set default options in the PPD file...
1391 */
1392
61c9d9f8
MS
1393 if ((ppd = ppdOpenFile(ppdfile)) == NULL)
1394 {
1395 int linenum; /* Line number of error */
1396 ppd_status_t status = ppdLastError(&linenum);
1397 /* Status code */
1398
1399 _cupsLangPrintf(stderr, _("lpadmin: Unable to open PPD \"%s\": %s on line %d."), ppdfile, ppdErrorString(status), linenum);
1400 }
1401
b423cd4c 1402 ppdMarkDefaults(ppd);
1403 cupsMarkOptions(ppd, num_options, options);
1404
0268488e 1405 if ((out = cupsTempFile2(tempfile, sizeof(tempfile))) == NULL)
ef416fc2 1406 {
0837b7e8 1407 _cupsLangPrintError(NULL, _("lpadmin: Unable to create temporary file"));
ef416fc2 1408 ippDelete(request);
7cf5915e
MS
1409 if (ppdfile != file)
1410 unlink(ppdfile);
61c9d9f8
MS
1411 if (copied_options)
1412 cupsFreeOptions(num_options, options);
ef416fc2 1413 return (1);
1414 }
1415
7cf5915e 1416 if ((in = cupsFileOpen(ppdfile, "r")) == NULL)
ef416fc2 1417 {
fa73b229 1418 _cupsLangPrintf(stderr,
0837b7e8 1419 _("lpadmin: Unable to open PPD file \"%s\" - %s"),
ef416fc2 1420 ppdfile, strerror(errno));
1421 ippDelete(request);
7cf5915e
MS
1422 if (ppdfile != file)
1423 unlink(ppdfile);
61c9d9f8
MS
1424 if (copied_options)
1425 cupsFreeOptions(num_options, options);
7cf5915e 1426 cupsFileClose(out);
ef416fc2 1427 unlink(tempfile);
1428 return (1);
1429 }
1430
7cf5915e 1431 while (cupsFileGets(in, line, sizeof(line)))
ef416fc2 1432 {
eac3a0a0
MS
1433 if (!strncmp(line, "*cupsIPPSupplies:", 17) &&
1434 (boolval = cupsGetOption("cupsIPPSupplies", num_options,
1435 options)) != NULL)
1436 {
1437 wrote_ipp_supplies = 1;
1438 cupsFilePrintf(out, "*cupsIPPSupplies: %s\n",
88f9aafc
MS
1439 (!_cups_strcasecmp(boolval, "true") ||
1440 !_cups_strcasecmp(boolval, "yes") ||
1441 !_cups_strcasecmp(boolval, "on")) ? "True" : "False");
eac3a0a0
MS
1442 }
1443 else if (!strncmp(line, "*cupsSNMPSupplies:", 18) &&
1444 (boolval = cupsGetOption("cupsSNMPSupplies", num_options,
1445 options)) != NULL)
1446 {
1447 wrote_snmp_supplies = 1;
1448 cupsFilePrintf(out, "*cupsSNMPSupplies: %s\n",
88f9aafc
MS
1449 (!_cups_strcasecmp(boolval, "true") ||
1450 !_cups_strcasecmp(boolval, "yes") ||
1451 !_cups_strcasecmp(boolval, "on")) ? "True" : "False");
eac3a0a0
MS
1452 }
1453 else if (strncmp(line, "*Default", 8))
7cf5915e 1454 cupsFilePrintf(out, "%s\n", line);
ef416fc2 1455 else
1456 {
1457 /*
1458 * Get default option name...
1459 */
1460
1461 strlcpy(keyword, line + 8, sizeof(keyword));
1462
1463 for (keyptr = keyword; *keyptr; keyptr ++)
1464 if (*keyptr == ':' || isspace(*keyptr & 255))
1465 break;
1466
b423cd4c 1467 *keyptr++ = '\0';
1468 while (isspace(*keyptr & 255))
1469 keyptr ++;
1470
1471 if (!strcmp(keyword, "PageRegion") ||
1472 !strcmp(keyword, "PageSize") ||
1473 !strcmp(keyword, "PaperDimension") ||
1474 !strcmp(keyword, "ImageableArea"))
1475 {
1476 if ((choice = ppdFindMarkedChoice(ppd, "PageSize")) == NULL)
1477 choice = ppdFindMarkedChoice(ppd, "PageRegion");
1478 }
ef416fc2 1479 else
b423cd4c 1480 choice = ppdFindMarkedChoice(ppd, keyword);
ef416fc2 1481
b423cd4c 1482 if (choice && strcmp(choice->choice, keyptr))
1483 {
7cf5915e
MS
1484 if (strcmp(choice->choice, "Custom"))
1485 {
1486 cupsFilePrintf(out, "*Default%s: %s\n", keyword, choice->choice);
1487 ppdchanged = 1;
1488 }
1489 else if ((customval = cupsGetOption(keyword, num_options,
1490 options)) != NULL)
1491 {
1492 cupsFilePrintf(out, "*Default%s: %s\n", keyword, customval);
1493 ppdchanged = 1;
1494 }
1495 else
1496 cupsFilePrintf(out, "%s\n", line);
b423cd4c 1497 }
ef416fc2 1498 else
7cf5915e 1499 cupsFilePrintf(out, "%s\n", line);
ef416fc2 1500 }
1501 }
1502
eac3a0a0
MS
1503 if (!wrote_ipp_supplies &&
1504 (boolval = cupsGetOption("cupsIPPSupplies", num_options,
1505 options)) != NULL)
1506 {
1507 cupsFilePrintf(out, "*cupsIPPSupplies: %s\n",
88f9aafc
MS
1508 (!_cups_strcasecmp(boolval, "true") ||
1509 !_cups_strcasecmp(boolval, "yes") ||
1510 !_cups_strcasecmp(boolval, "on")) ? "True" : "False");
eac3a0a0
MS
1511 }
1512
1513 if (!wrote_snmp_supplies &&
1514 (boolval = cupsGetOption("cupsSNMPSupplies", num_options,
1515 options)) != NULL)
1516 {
1517 cupsFilePrintf(out, "*cupsSNMPSupplies: %s\n",
88f9aafc
MS
1518 (!_cups_strcasecmp(boolval, "true") ||
1519 !_cups_strcasecmp(boolval, "yes") ||
1520 !_cups_strcasecmp(boolval, "on")) ? "True" : "False");
eac3a0a0
MS
1521 }
1522
7cf5915e
MS
1523 cupsFileClose(in);
1524 cupsFileClose(out);
b423cd4c 1525 ppdClose(ppd);
ef416fc2 1526
1527 /*
1528 * Do the request...
1529 */
1530
b423cd4c 1531 ippDelete(cupsDoFileRequest(http, request, "/admin/",
7cf5915e 1532 ppdchanged ? tempfile : file));
ef416fc2 1533
1534 /*
1535 * Clean up temp files... (TODO: catch signals in case we CTRL-C during
1536 * lpadmin)
1537 */
1538
7cf5915e
MS
1539 if (ppdfile != file)
1540 unlink(ppdfile);
ef416fc2 1541 unlink(tempfile);
1542 }
1543 else
1544 {
1545 /*
1546 * No PPD file - just set the options...
1547 */
1548
b423cd4c 1549 ippDelete(cupsDoRequest(http, request, "/admin/"));
ef416fc2 1550 }
1551
61c9d9f8
MS
1552 if (copied_options)
1553 cupsFreeOptions(num_options, options);
1554
ef416fc2 1555 /*
1556 * Check the response...
1557 */
1558
fffed089 1559 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
ef416fc2 1560 {
eac3a0a0 1561 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
ef416fc2 1562
1563 return (1);
1564 }
1565 else
ef416fc2 1566 return (0);
ef416fc2 1567}
1568
1569
1570/*
1571 * 'validate_name()' - Make sure the printer name only contains valid chars.
1572 */
1573
fa73b229 1574static int /* O - 0 if name is no good, 1 if name is good */
1575validate_name(const char *name) /* I - Name to check */
ef416fc2 1576{
fa73b229 1577 const char *ptr; /* Pointer into name */
ef416fc2 1578
1579
1580 /*
1581 * Scan the whole name...
1582 */
1583
1584 for (ptr = name; *ptr; ptr ++)
1585 if (*ptr == '@')
1586 break;
1587 else if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' ||
1588 *ptr == '#')
1589 return (0);
1590
1591 /*
1592 * All the characters are good; validate the length, too...
1593 */
1594
1595 return ((ptr - name) < 128);
1596}