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