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