Load cups into easysw/current.
[thirdparty/cups.git] / systemv / lpadmin.c
1 /*
2  * "$Id: lpadmin.c 4906 2006-01-10 20:53:28Z mike $"
3  *
4  *   "lpadmin" command for the Common UNIX Printing System (CUPS).
5  *
6  *   Copyright 1997-2006 by Easy Software Products.
7  *
8  *   These coded instructions, statements, and computer programs are the
9  *   property of Easy Software Products and are protected by Federal
10  *   copyright law.  Distribution and use rights are outlined in the file
11  *   "LICENSE.txt" which should have been included with this file.  If this
12  *   file is missing or damaged please contact Easy Software Products
13  *   at:
14  *
15  *       Attn: CUPS Licensing Information
16  *       Easy Software Products
17  *       44141 Airport View Drive, Suite 204
18  *       Hollywood, Maryland 20636 USA
19  *
20  *       Voice: (301) 373-9600
21  *       EMail: cups-info@cups.org
22  *         WWW: http://www.cups.org
23  *
24  * Contents:
25  *
26  *   main()                      - Parse options and configure the scheduler.
27  *   add_printer_to_class()      - Add a printer to a class.
28  *   default_printer()           - Set the default printing destination.
29  *   delete_printer()            - Delete a printer from the system...
30  *   delete_printer_from_class() - Delete a printer from a class.
31  *   enable_printer()            - Enable a printer...
32  *   set_printer_device()        - Set the device-uri attribute.
33  *   set_printer_file()          - Set the interface script or PPD file.
34  *   set_printer_info()          - Set the printer description string.
35  *   set_printer_location()      - Set the printer location string.
36  *   set_printer_model()         - Set the driver model file.
37  *   set_printer_options()       - Set the printer options.
38  *   validate_name()             - Make sure the printer name only contains
39  *                                 valid chars...
40  */
41
42 /*
43  * Include necessary headers...
44  */
45
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <ctype.h>
49 #include <errno.h>
50 #include <cups/string.h>
51 #include <cups/cups.h>
52 #include <cups/i18n.h>
53 #include <cups/debug.h>
54 #ifdef HAVE_LIBZ
55 #  include <zlib.h>
56 #endif /* HAVE_LIBZ */
57
58
59 /*
60  * Local functions...
61  */
62
63 static int      add_printer_to_class(http_t *, char *, char *);
64 static int      default_printer(http_t *, char *);
65 static int      delete_printer(http_t *, char *);
66 static int      delete_printer_from_class(http_t *, char *, char *);
67 static int      enable_printer(http_t *, char *);
68 static char     *get_line(char *, int, FILE *fp);
69 static int      set_printer_device(http_t *, char *, char *);
70 static int      set_printer_file(http_t *, char *, char *);
71 static int      set_printer_info(http_t *, char *, char *);
72 static int      set_printer_location(http_t *, char *, char *);
73 static int      set_printer_model(http_t *, char *, char *);
74 static int      set_printer_options(http_t *, char *, int, cups_option_t *);
75 static int      validate_name(const char *);
76
77
78 /*
79  * 'main()' - Parse options and configure the scheduler.
80  */
81
82 int
83 main(int  argc,                 /* I - Number of command-line arguments */
84      char *argv[])              /* I - Command-line arguments */
85 {
86   int           i;              /* Looping var */
87   http_t        *http;          /* Connection to server */
88   char          *printer,       /* Destination printer */
89                 *pclass,        /* Printer class name */
90                 *val;           /* Pointer to allow/deny value */
91   int           num_options;    /* Number of options */
92   cups_option_t *options;       /* Options */
93
94
95   http        = NULL;
96   printer     = NULL;
97   num_options = 0;
98   options     = NULL;
99
100   for (i = 1; i < argc; i ++)
101     if (argv[i][0] == '-')
102       switch (argv[i][1])
103       {
104         case 'c' : /* Add printer to class */
105             if (!http)
106             {
107               http = httpConnectEncrypt(cupsServer(), ippPort(),
108                                         cupsEncryption());
109
110               if (http == NULL)
111               {
112                 _cupsLangPrintf(stderr, NULL,
113                                 _("lpadmin: Unable to connect to server: %s\n"),
114                                 strerror(errno));
115                 return (1);
116               }
117             }
118
119             if (printer == NULL)
120             {
121               _cupsLangPuts(stderr, NULL,
122                             _("lpadmin: Unable to add a printer to the class:\n"
123                               "         You must specify a printer name "
124                               "first!\n"));
125               return (1);
126             }
127
128             if (argv[i][2])
129               pclass = argv[i] + 2;
130             else
131             {
132               i ++;
133
134               if (i >= argc)
135               {
136                 _cupsLangPuts(stderr, NULL,
137                               _("lpadmin: Expected class name after \'-c\' "
138                                 "option!\n"));
139                 return (1);
140               }
141
142               pclass = argv[i];
143             }
144
145             if (!validate_name(pclass))
146             {
147               _cupsLangPuts(stderr, NULL,
148                             _("lpadmin: Class name can only contain printable "
149                               "characters!\n"));
150               return (1);
151             }
152
153             if (add_printer_to_class(http, printer, pclass))
154               return (1);
155             break;
156
157         case 'd' : /* Set as default destination */
158             if (!http)
159             {
160               http = httpConnectEncrypt(cupsServer(), ippPort(),
161                                         cupsEncryption());
162
163               if (http == NULL)
164               {
165                 _cupsLangPrintf(stderr, NULL,
166                                 _("lpadmin: Unable to connect to server: %s\n"),
167                                 strerror(errno));
168                 return (1);
169               }
170             }
171
172             if (argv[i][2])
173               printer = argv[i] + 2;
174             else
175             {
176               i ++;
177
178               if (i >= argc)
179               {
180                 _cupsLangPuts(stderr, NULL,
181                               _("lpadmin: Expected printer name after \'-d\' "
182                                 "option!\n"));
183                 return (1);
184               }
185
186               printer = argv[i];
187             }
188
189             if (!validate_name(printer))
190             {
191               _cupsLangPuts(stderr, NULL,
192                             _("lpadmin: Printer name can only contain "
193                               "printable characters!\n"));
194               return (1);
195             }
196
197             if (default_printer(http, printer))
198               return (1);
199
200             i = argc;
201             break;
202
203         case 'h' : /* Connect to host */
204             if (http)
205             {
206               httpClose(http);
207               http = NULL;
208             }
209
210             if (argv[i][2] != '\0')
211               cupsSetServer(argv[i] + 2);
212             else
213             {
214               i ++;
215
216               if (i >= argc)
217               {
218                 _cupsLangPuts(stderr, NULL,
219                               _("lpadmin: Expected hostname after \'-h\' "
220                                 "option!\n"));
221                 return (1);
222               }
223
224               cupsSetServer(argv[i]);
225             }
226             break;
227
228         case 'i' : /* Use the specified interface script */
229             if (!http)
230             {
231               http = httpConnectEncrypt(cupsServer(), ippPort(),
232                                         cupsEncryption());
233
234               if (http == NULL)
235               {
236                 _cupsLangPrintf(stderr, NULL,
237                                 _("lpadmin: Unable to connect to server: %s\n"),
238                                 strerror(errno));
239                 return (1);
240               }
241             }
242
243             if (printer == NULL)
244             {
245               _cupsLangPuts(stderr, NULL,
246                             _("lpadmin: Unable to set the interface script:\n"
247                               "         You must specify a printer name "
248                               "first!\n"));
249               return (1);
250             }
251
252             if (argv[i][2])
253             {
254               if (set_printer_file(http, printer, argv[i] + 2))
255                 return (1);
256             }
257             else
258             {
259               i ++;
260
261               if (i >= argc)
262               {
263                 _cupsLangPuts(stderr, NULL,
264                               _("lpadmin: Expected interface after \'-i\' "
265                                 "option!\n"));
266                 return (1);
267               }
268
269               if (set_printer_file(http, printer, argv[i]))
270                 return (1);
271             }
272             break;
273
274         case 'E' : /* Enable the printer */
275             if (printer == NULL)
276             {
277 #ifdef HAVE_SSL
278               cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
279
280               if (http)
281                 httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
282 #else
283               _cupsLangPrintf(stderr, NULL,
284                               _("%s: Sorry, no encryption support compiled in!\n"),
285                               argv[0]);
286 #endif /* HAVE_SSL */
287               break;
288             }
289
290             if (!http)
291             {
292               http = httpConnectEncrypt(cupsServer(), ippPort(),
293                                         cupsEncryption());
294
295               if (http == NULL)
296               {
297                 _cupsLangPrintf(stderr, NULL,
298                                 _("lpadmin: Unable to connect to server: %s\n"),
299                                 strerror(errno));
300                 return (1);
301               }
302             }
303
304             if (enable_printer(http, printer))
305               return (1);
306             break;
307
308         case 'm' : /* Use the specified standard script/PPD file */
309             if (!http)
310             {
311               http = httpConnectEncrypt(cupsServer(), ippPort(),
312                                         cupsEncryption());
313
314               if (http == NULL)
315               {
316                 _cupsLangPrintf(stderr, NULL,
317                                 _("lpadmin: Unable to connect to server: %s\n"),
318                                 strerror(errno));
319                 return (1);
320               }
321             }
322
323             if (printer == NULL)
324             {
325               _cupsLangPuts(stderr, NULL,
326                             _("lpadmin: Unable to set the interface script or "
327                               "PPD file:\n"
328                               "         You must specify a printer name "
329                               "first!\n"));
330               return (1);
331             }
332
333             if (argv[i][2])
334             {
335               if (set_printer_model(http, printer, argv[i] + 2))
336                 return (1);
337             }
338             else
339             {
340               i ++;
341
342               if (i >= argc)
343               {
344                 _cupsLangPuts(stderr, NULL,
345                               _("lpadmin: Expected model after \'-m\' "
346                                 "option!\n"));
347                 return (1);
348               }
349
350               if (set_printer_model(http, printer, argv[i]))
351                 return (1);
352             }
353             break;
354
355         case 'o' : /* Set option */
356             if (argv[i][2])
357               num_options = cupsParseOptions(argv[i] + 2, num_options, &options);
358             else
359             {
360               i ++;
361
362               if (i >= argc)
363               {
364                 _cupsLangPuts(stderr, NULL,
365                               _("lpadmin: Expected name=value after \'-o\' "
366                                 "option!\n"));
367                 return (1);
368               }
369
370               num_options = cupsParseOptions(argv[i], num_options, &options);
371             }
372             break;
373
374         case 'p' : /* Add/modify a printer */
375             if (!http)
376             {
377               http = httpConnectEncrypt(cupsServer(), ippPort(),
378                                         cupsEncryption());
379
380               if (http == NULL)
381               {
382                 _cupsLangPrintf(stderr, NULL,
383                                 _("lpadmin: Unable to connect to server: %s\n"),
384                                 strerror(errno));
385                 return (1);
386               }
387             }
388
389             if (argv[i][2])
390               printer = argv[i] + 2;
391             else
392             {
393               i ++;
394
395               if (i >= argc)
396               {
397                 _cupsLangPuts(stderr, NULL,
398                               _("lpadmin: Expected printer after \'-p\' "
399                                 "option!\n"));
400                 return (1);
401               }
402
403               printer = argv[i];
404             }
405
406             if (!validate_name(printer))
407             {
408               _cupsLangPuts(stderr, NULL,
409                             _("lpadmin: Printer name can only contain "
410                               "printable characters!\n"));
411               return (1);
412             }
413             break;
414
415         case 'r' : /* Remove printer from class */
416             if (!http)
417             {
418               http = httpConnectEncrypt(cupsServer(), ippPort(),
419                                         cupsEncryption());
420
421               if (http == NULL)
422               {
423                 _cupsLangPrintf(stderr, NULL,
424                                 _("lpadmin: Unable to connect to server: %s\n"),
425                                 strerror(errno));
426                 return (1);
427               }
428             }
429
430             if (printer == NULL)
431             {
432               _cupsLangPuts(stderr, NULL,
433                             _("lpadmin: Unable to remove a printer from the "
434                               "class:\n"
435                               "         You must specify a printer name "
436                               "first!\n"));
437               return (1);
438             }
439
440             if (argv[i][2])
441               pclass = argv[i] + 2;
442             else
443             {
444               i ++;
445
446               if (i >= argc)
447               {
448                 _cupsLangPuts(stderr, NULL,
449                               _("lpadmin: Expected class after \'-r\' "
450                                 "option!\n"));
451                 return (1);
452               }
453
454               pclass = argv[i];
455             }
456
457             if (!validate_name(pclass))
458             {
459               _cupsLangPuts(stderr, NULL,
460                             _("lpadmin: Class name can only contain printable "
461                               "characters!\n"));
462               return (1);
463             }
464
465             if (delete_printer_from_class(http, printer, pclass))
466               return (1);
467             break;
468
469         case 'u' : /* Allow/deny users */
470             if (argv[i][2])
471               val = argv[i] + 2;
472             else
473             {
474               i ++;
475
476               if (i >= argc)
477               {
478                 _cupsLangPuts(stderr, NULL,
479                               _("lpadmin: Expected allow/deny:userlist after "
480                                 "\'-u\' option!\n"));
481                 return (1);
482               }
483
484               val = argv[i];
485             }
486
487             if (!strncasecmp(val, "allow:", 6))
488               num_options = cupsAddOption("requesting-user-name-allowed",
489                                           val + 6, num_options, &options);
490             else if (!strncasecmp(val, "deny:", 5))
491               num_options = cupsAddOption("requesting-user-name-denied",
492                                           val + 5, num_options, &options);
493             else
494             {
495               _cupsLangPrintf(stderr, NULL,
496                               _("lpadmin: Unknown allow/deny option \"%s\"!\n"),
497                               val);
498               return (1);
499             }
500             break;
501
502         case 'v' : /* Set the device-uri attribute */
503             if (!http)
504             {
505               http = httpConnectEncrypt(cupsServer(), ippPort(),
506                                         cupsEncryption());
507
508               if (http == NULL)
509               {
510                 _cupsLangPrintf(stderr, NULL,
511                                 _("lpadmin: Unable to connect to server: %s\n"),
512                                 strerror(errno));
513                 return (1);
514               }
515             }
516
517             if (printer == NULL)
518             {
519               _cupsLangPuts(stderr, NULL,
520                             _("lpadmin: Unable to set the device URI:\n"
521                               "         You must specify a printer name "
522                               "first!\n"));
523               return (1);
524             }
525
526             if (argv[i][2])
527             {
528               if (set_printer_device(http, printer, argv[i] + 2))
529                 return (1);
530             }
531             else
532             {
533               i ++;
534
535               if (i >= argc)
536               {
537                 _cupsLangPuts(stderr, NULL,
538                               _("lpadmin: Expected device URI after \'-v\' "
539                                 "option!\n"));
540                 return (1);
541               }
542
543               if (set_printer_device(http, printer, argv[i]))
544                 return (1);
545             }
546             break;
547
548         case 'x' : /* Delete a printer */
549             if (!http)
550             {
551               http = httpConnectEncrypt(cupsServer(), ippPort(),
552                                         cupsEncryption());
553
554               if (http == NULL)
555               {
556                 _cupsLangPrintf(stderr, NULL,
557                                 _("lpadmin: Unable to connect to server: %s\n"),
558                                 strerror(errno));
559                 return (1);
560               }
561             }
562
563             if (argv[i][2])
564               printer = argv[i] + 2;
565             else
566             {
567               i ++;
568
569               if (i >= argc)
570               {
571                 _cupsLangPuts(stderr, NULL,
572                               _("lpadmin: Expected printer or class after "
573                                 "\'-x\' option!\n"));
574                 return (1);
575               }
576
577               printer = argv[i];
578             }
579
580             if (!validate_name(printer))
581             {
582               _cupsLangPuts(stderr, NULL,
583                             _("lpadmin: Printer name can only contain "
584                               "printable characters!\n"));
585               return (1);
586             }
587
588             if (delete_printer(http, printer))
589               return (1);
590
591             i = argc;
592             break;
593
594         case 'D' : /* Set the printer-info attribute */
595             if (!http)
596             {
597               http = httpConnectEncrypt(cupsServer(), ippPort(),
598                                         cupsEncryption());
599
600               if (http == NULL)
601               {
602                 _cupsLangPrintf(stderr, NULL,
603                                 _("lpadmin: Unable to connect to server: %s\n"),
604                                 strerror(errno));
605                 return (1);
606               }
607             }
608
609             if (printer == NULL)
610             {
611               _cupsLangPuts(stderr, NULL,
612                             _("lpadmin: Unable to set the printer "
613                               "description:\n"
614                               "         You must specify a printer name "
615                               "first!\n"));
616               return (1);
617             }
618
619             if (argv[i][2])
620             {
621               if (set_printer_info(http, printer, argv[i] + 2))
622                 return (1);
623             }
624             else
625             {
626               i ++;
627
628               if (i >= argc)
629               {
630                 _cupsLangPuts(stderr, NULL,
631                               _("lpadmin: Expected description after "
632                                 "\'-D\' option!\n"));
633                 return (1);
634               }
635
636               if (set_printer_info(http, printer, argv[i]))
637                 return (1);
638             }
639             break;
640
641         case 'I' : /* Set the supported file types (ignored) */
642             i ++;
643
644             if (i >= argc)
645             {
646               _cupsLangPuts(stderr, NULL,
647                             _("lpadmin: Expected file type(s) after \'-I\' "
648                               "option!\n"));
649               return (1);
650             }
651
652             _cupsLangPuts(stderr, NULL,
653                           _("lpadmin: Warning - content type list ignored!\n"));
654             break;
655             
656         case 'L' : /* Set the printer-location attribute */
657             if (!http)
658             {
659               http = httpConnectEncrypt(cupsServer(), ippPort(),
660                                         cupsEncryption());
661
662               if (http == NULL)
663               {
664                 _cupsLangPrintf(stderr, NULL,
665                                 _("lpadmin: Unable to connect to server: %s\n"),
666                                 strerror(errno));
667                 return (1);
668               }
669             }
670
671             if (printer == NULL)
672             {
673               _cupsLangPuts(stderr, NULL,
674                             _("lpadmin: Unable to set the printer location:\n"
675                               "         You must specify a printer name "
676                               "first!\n"));
677               return (1);
678             }
679
680             if (argv[i][2])
681             {
682               if (set_printer_location(http, printer, argv[i] + 2))
683                 return (1);
684             }
685             else
686             {
687               i ++;
688
689               if (i >= argc)
690               {
691                 _cupsLangPuts(stderr, NULL,
692                               _("lpadmin: Expected location after \'-L\' "
693                                 "option!\n"));
694                 return (1);
695               }
696
697               if (set_printer_location(http, printer, argv[i]))
698                 return (1);
699             }
700             break;
701
702         case 'P' : /* Use the specified PPD file */
703             if (!http)
704             {
705               http = httpConnectEncrypt(cupsServer(), ippPort(),
706                                         cupsEncryption());
707
708               if (http == NULL)
709               {
710                 _cupsLangPrintf(stderr, NULL,
711                                 _("lpadmin: Unable to connect to server: %s\n"),
712                                 strerror(errno));
713                 return (1);
714               }
715             }
716
717             if (printer == NULL)
718             {
719               _cupsLangPuts(stderr, NULL,
720                             _("lpadmin: Unable to set the PPD file:\n"
721                               "         You must specify a printer name "
722                               "first!\n"));
723               return (1);
724             }
725
726             if (argv[i][2])
727             {
728               if (set_printer_file(http, printer, argv[i] + 2))
729                 return (1);
730             }
731             else
732             {
733               i ++;
734
735               if (i >= argc)
736               {
737                 _cupsLangPuts(stderr, NULL,
738                               _("lpadmin: Expected PPD after \'-P\' option!\n"));
739                 return (1);
740               }
741
742               if (set_printer_file(http, printer, argv[i]))
743                 return (1);
744             }
745             break;
746
747         default :
748             _cupsLangPrintf(stderr, NULL,
749                             _("lpadmin: Unknown option \'%c\'!\n"), argv[i][1]);
750             return (1);
751       }
752     else
753     {
754       _cupsLangPrintf(stderr, NULL, _("lpadmin: Unknown argument \'%s\'!\n"),
755                       argv[i]);
756       return (1);
757     }
758
759  /*
760   * Set options as needed...
761   */
762
763   if (num_options)
764   {
765     if (!http)
766     {
767       http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
768
769       if (http == NULL)
770       {
771         _cupsLangPrintf(stderr, NULL,
772                         _("lpadmin: Unable to connect to server: %s\n"),
773                         strerror(errno));
774         return (1);
775       }
776     }
777
778     if (printer == NULL)
779     {
780       _cupsLangPuts(stderr, NULL,
781                     _("lpadmin: Unable to set the printer options:\n"
782                       "         You must specify a printer name first!\n"));
783       return (1);
784     }
785
786     if (set_printer_options(http, printer, num_options, options))
787       return (1);
788   }
789
790   if (printer == NULL)
791   {
792     _cupsLangPuts(stdout, NULL,
793                   _("Usage:\n"
794                     "\n"
795                     "    lpadmin [-h server] -d destination\n"
796                     "    lpadmin [-h server] -x destination\n"
797                     "    lpadmin [-h server] -p printer [-c add-class] "
798                     "[-i interface] [-m model]\n"
799                     "                       [-r remove-class] [-v device] "
800                     "[-D description]\n"
801                     "                       [-P ppd-file] [-o name=value]\n"
802                     "                       [-u allow:user,user] "
803                     "[-u deny:user,user]\n"
804                     "\n"));
805   }
806
807   if (http)
808     httpClose(http);
809
810   return (0);
811 }
812
813
814 /*
815  * 'add_printer_to_class()' - Add a printer to a class.
816  */
817
818 static int                              /* O - 0 on success, 1 on fail */
819 add_printer_to_class(http_t *http,      /* I - Server connection */
820                      char   *printer,   /* I - Printer to add */
821                      char   *pclass)    /* I - Class to add to */
822 {
823   int           i;                      /* Looping var */
824   ipp_t         *request,               /* IPP Request */
825                 *response;              /* IPP Response */
826   ipp_attribute_t *attr,                /* Current attribute */
827                 *members;               /* Members in class */
828   cups_lang_t   *language;              /* Default language */
829   char          uri[HTTP_MAX_URI];      /* URI for printer/class */
830
831
832   DEBUG_printf(("add_printer_to_class(%p, \"%s\", \"%s\")\n", http,
833                 printer, pclass));
834
835  /*
836   * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
837   * attributes:
838   *
839   *    attributes-charset
840   *    attributes-natural-language
841   *    printer-uri
842   */
843
844   httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
845                    "/classes/%s", pclass);
846
847   request = ippNew();
848
849   request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
850   request->request.op.request_id   = 1;
851
852   language = cupsLangDefault();
853
854   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
855                "attributes-charset", NULL, cupsLangEncoding(language));
856
857   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
858                "attributes-natural-language", NULL, language->language);
859
860   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
861                "printer-uri", NULL, uri);
862
863  /*
864   * Do the request and get back a response...
865   */
866
867   response = cupsDoRequest(http, request, "/");
868
869  /*
870   * Build a CUPS_ADD_CLASS request, which requires the following
871   * attributes:
872   *
873   *    attributes-charset
874   *    attributes-natural-language
875   *    printer-uri
876   *    member-uris
877   */
878
879   request = ippNew();
880
881   request->request.op.operation_id = CUPS_ADD_CLASS;
882   request->request.op.request_id   = 1;
883
884   language = cupsLangDefault();
885
886   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
887                "attributes-charset", NULL, cupsLangEncoding(language));
888
889   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
890                "attributes-natural-language", NULL, language->language);
891
892   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
893                "printer-uri", NULL, uri);
894
895  /*
896   * See if the printer is already in the class...
897   */
898
899   if (response != NULL &&
900       (members = ippFindAttribute(response, "member-names", IPP_TAG_NAME)) != NULL)
901     for (i = 0; i < members->num_values; i ++)
902       if (strcasecmp(printer, members->values[i].string.text) == 0)
903       {
904         fprintf(stderr, "lpadmin: Printer %s is already a member of class %s.\n",
905                 printer, pclass);
906         ippDelete(request);
907         ippDelete(response);
908         return (0);
909       }
910
911  /*
912   * OK, the printer isn't part of the class, so add it...
913   */
914
915   httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
916                    "/printers/%s", printer);
917
918   if (response != NULL &&
919       (members = ippFindAttribute(response, "member-uris", IPP_TAG_URI)) != NULL)
920   {
921    /*
922     * Add the printer to the existing list...
923     */
924
925     attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI,
926                          "member-uris", members->num_values + 1, NULL, NULL);
927     for (i = 0; i < members->num_values; i ++)
928       attr->values[i].string.text = strdup(members->values[i].string.text);
929
930     attr->values[i].string.text = strdup(uri);
931   }
932   else
933     attr = ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "member-uris", NULL, uri);
934
935  /*
936   * Then send the request...
937   */
938
939   ippDelete(response);
940
941   if ((response = cupsDoRequest(http, request, "/admin/")) == NULL)
942   {
943     fprintf(stderr, "lpadmin: add-class failed: %s\n",
944             ippErrorString(cupsLastError()));
945
946     return (1);
947   }
948   else if (response->request.status.status_code > IPP_OK_CONFLICT)
949   {
950     fprintf(stderr, "lpadmin: add-class failed: %s\n",
951             ippErrorString(response->request.status.status_code));
952
953     ippDelete(response);
954
955     return (1);
956   }
957   else
958   {
959     ippDelete(response);
960
961     return (0);
962   }
963 }
964
965
966 /*
967  * 'default_printer()' - Set the default printing destination.
968  */
969
970 static int                              /* O - 0 on success, 1 on fail */
971 default_printer(http_t *http,           /* I - Server connection */
972                 char   *printer)        /* I - Printer name */
973 {
974   ipp_t         *request,               /* IPP Request */
975                 *response;              /* IPP Response */
976   cups_lang_t   *language;              /* Default language */
977   char          uri[HTTP_MAX_URI];      /* URI for printer/class */
978
979
980   DEBUG_printf(("default_printer(%p, \"%s\")\n", http, printer));
981
982  /*
983   * Build a CUPS_SET_DEFAULT request, which requires the following
984   * attributes:
985   *
986   *    attributes-charset
987   *    attributes-natural-language
988   *    printer-uri
989   */
990
991   httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
992                    "/printers/%s", printer);
993
994   request = ippNew();
995
996   request->request.op.operation_id = CUPS_SET_DEFAULT;
997   request->request.op.request_id   = 1;
998
999   language = cupsLangDefault();
1000
1001   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1002                "attributes-charset", NULL, cupsLangEncoding(language));
1003
1004   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1005                "attributes-natural-language", NULL, language->language);
1006
1007   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1008                "printer-uri", NULL, uri);
1009
1010  /*
1011   * Do the request and get back a response...
1012   */
1013
1014   if ((response = cupsDoRequest(http, request, "/admin/")) == NULL)
1015   {
1016     fprintf(stderr, "lpadmin: set-default failed: %s\n",
1017             ippErrorString(cupsLastError()));
1018
1019     return (1);
1020   }
1021   else if (response->request.status.status_code > IPP_OK_CONFLICT)
1022   {
1023     fprintf(stderr, "lpadmin: set-default failed: %s\n",
1024             ippErrorString(response->request.status.status_code));
1025
1026     ippDelete(response);
1027
1028     return (1);
1029   }
1030   else
1031   {
1032     ippDelete(response);
1033
1034     return (0);
1035   }
1036 }
1037
1038
1039 /*
1040  * 'delete_printer()' - Delete a printer from the system...
1041  */
1042
1043 static int                              /* O - 0 on success, 1 on fail */
1044 delete_printer(http_t *http,            /* I - Server connection */
1045                char   *printer)         /* I - Printer to delete */
1046 {
1047   ipp_t         *request,               /* IPP Request */
1048                 *response;              /* IPP Response */
1049   cups_lang_t   *language;              /* Default language */
1050   char          uri[HTTP_MAX_URI];      /* URI for printer/class */
1051
1052
1053   DEBUG_printf(("delete_printer(%p, \"%s\")\n", http, printer));
1054
1055  /*
1056   * Build a CUPS_DELETE_PRINTER request, which requires the following
1057   * attributes:
1058   *
1059   *    attributes-charset
1060   *    attributes-natural-language
1061   *    printer-uri
1062   */
1063
1064   httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
1065                    "/printers/%s", printer);
1066
1067   request = ippNew();
1068
1069   request->request.op.operation_id = CUPS_DELETE_PRINTER;
1070   request->request.op.request_id   = 1;
1071
1072   language = cupsLangDefault();
1073
1074   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1075                "attributes-charset", NULL, cupsLangEncoding(language));
1076
1077   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1078                "attributes-natural-language", NULL, language->language);
1079
1080   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1081                "printer-uri", NULL, uri);
1082
1083  /*
1084   * Do the request and get back a response...
1085   */
1086
1087   if ((response = cupsDoRequest(http, request, "/admin/")) == NULL)
1088   {
1089     fprintf(stderr, "lpadmin: delete-printer failed: %s\n",
1090             ippErrorString(cupsLastError()));
1091
1092     return (1);
1093   }
1094   else if (response->request.status.status_code > IPP_OK_CONFLICT)
1095   {
1096     fprintf(stderr, "lpadmin: delete-printer failed: %s\n",
1097             ippErrorString(response->request.status.status_code));
1098
1099     ippDelete(response);
1100
1101     return (1);
1102   }
1103   else
1104   {
1105     ippDelete(response);
1106
1107     return (0);
1108   }
1109 }
1110
1111
1112 /*
1113  * 'delete_printer_from_class()' - Delete a printer from a class.
1114  */
1115
1116 static int                              /* O - 0 on success, 1 on fail */
1117 delete_printer_from_class(http_t *http, /* I - Server connection */
1118                           char   *printer,
1119                                         /* I - Printer to remove */
1120                           char   *pclass)
1121                                         /* I - Class to remove from */
1122 {
1123   int           i, j, k;                /* Looping vars */
1124   ipp_t         *request,               /* IPP Request */
1125                 *response;              /* IPP Response */
1126   ipp_attribute_t *attr,                /* Current attribute */
1127                 *members;               /* Members in class */
1128   cups_lang_t   *language;              /* Default language */
1129   char          uri[HTTP_MAX_URI];      /* URI for printer/class */
1130
1131
1132   DEBUG_printf(("delete_printer_from_class(%p, \"%s\", \"%s\")\n", http,
1133                 printer, pclass));
1134
1135  /*
1136   * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
1137   * attributes:
1138   *
1139   *    attributes-charset
1140   *    attributes-natural-language
1141   *    printer-uri
1142   */
1143
1144   httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
1145                    "/classes/%s", pclass);
1146
1147   request = ippNew();
1148
1149   request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
1150   request->request.op.request_id   = 1;
1151
1152   language = cupsLangDefault();
1153
1154   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1155                "attributes-charset", NULL, cupsLangEncoding(language));
1156
1157   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1158                "attributes-natural-language", NULL, language->language);
1159
1160   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1161                "printer-uri", NULL, uri);
1162
1163  /*
1164   * Do the request and get back a response...
1165   */
1166
1167   if ((response = cupsDoRequest(http, request, "/classes/")) == NULL ||
1168       response->request.status.status_code == IPP_NOT_FOUND)
1169   {
1170     ippDelete(response);
1171     fprintf(stderr, "lpadmin: Class %s does not exist!\n", pclass);
1172     return (1);
1173   }
1174
1175  /*
1176   * See if the printer is already in the class...
1177   */
1178
1179   if ((members = ippFindAttribute(response, "member-names", IPP_TAG_NAME)) == NULL)
1180   {
1181     ippDelete(response);
1182     fputs("lpadmin: No member names were seen!\n", stderr);
1183     return (1);
1184   }
1185
1186   for (i = 0; i < members->num_values; i ++)
1187     if (strcasecmp(printer, members->values[i].string.text) == 0)
1188       break;
1189
1190   if (i >= members->num_values)
1191   {
1192     fprintf(stderr, "lpadmin: Printer %s is not a member of class %s.\n",
1193             printer, pclass);
1194     ippDelete(response);
1195     return (1);
1196   }
1197
1198   if (members->num_values == 1)
1199   {
1200    /*
1201     * Build a CUPS_DELETE_CLASS request, which requires the following
1202     * attributes:
1203     *
1204     *    attributes-charset
1205     *    attributes-natural-language
1206     *    printer-uri
1207     */
1208
1209     request = ippNew();
1210
1211     request->request.op.operation_id = CUPS_DELETE_CLASS;
1212     request->request.op.request_id   = 1;
1213
1214     language = cupsLangDefault();
1215
1216     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1217                  "attributes-charset", NULL, cupsLangEncoding(language));
1218
1219     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1220                  "attributes-natural-language", NULL, language->language);
1221
1222     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1223                  "printer-uri", NULL, uri);
1224   }
1225   else
1226   {
1227    /*
1228     * Build a CUPS_ADD_CLASS request, which requires the following
1229     * attributes:
1230     *
1231     *    attributes-charset
1232     *    attributes-natural-language
1233     *    printer-uri
1234     *    member-uris
1235     */
1236
1237     request = ippNew();
1238
1239     request->request.op.operation_id = CUPS_ADD_CLASS;
1240     request->request.op.request_id   = 1;
1241
1242     language = cupsLangDefault();
1243
1244     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1245                  "attributes-charset", NULL, cupsLangEncoding(language));
1246
1247     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1248                  "attributes-natural-language", NULL, language->language);
1249
1250     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1251                  "printer-uri", NULL, uri);
1252
1253    /*
1254     * Delete the printer from the class...
1255     */
1256
1257     members = ippFindAttribute(response, "member-uris", IPP_TAG_URI);
1258     attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI,
1259                          "member-uris", members->num_values - 1, NULL, NULL);
1260
1261     for (j = 0, k = 0; j < members->num_values; j ++)
1262       if (j != i)
1263         attr->values[k ++].string.text = strdup(members->values[j].string.text);
1264   }
1265
1266  /*
1267   * Then send the request...
1268   */
1269
1270   ippDelete(response);
1271
1272   if ((response = cupsDoRequest(http, request, "/admin/")) == NULL)
1273   {
1274     fprintf(stderr, "lpadmin: add/delete-class failed: %s\n",
1275             ippErrorString(cupsLastError()));
1276     return (1);
1277   }
1278   else if (response->request.status.status_code > IPP_OK_CONFLICT)
1279   {
1280     fprintf(stderr, "lpadmin: add/delete-class failed: %s\n",
1281             ippErrorString(response->request.status.status_code));
1282
1283     ippDelete(response);
1284
1285     return (1);
1286   }
1287   else
1288   {
1289     ippDelete(response);
1290
1291     return (0);
1292   }
1293 }
1294
1295
1296 /*
1297  * 'enable_printer()' - Enable a printer...
1298  */
1299
1300 static int                              /* O - 0 on success, 1 on fail */
1301 enable_printer(http_t *http,            /* I - Server connection */
1302                char   *printer)         /* I - Printer to enable */
1303 {
1304   ipp_t         *request,               /* IPP Request */
1305                 *response;              /* IPP Response */
1306   cups_lang_t   *language;              /* Default language */
1307   char          uri[HTTP_MAX_URI];      /* URI for printer/class */
1308
1309
1310   DEBUG_printf(("enable_printer(%p, \"%s\")\n", http, printer));
1311
1312  /*
1313   * Build a CUPS_ADD_PRINTER request, which requires the following
1314   * attributes:
1315   *
1316   *    attributes-charset
1317   *    attributes-natural-language
1318   *    printer-uri
1319   *    printer-state
1320   *    printer-is-accepting-jobs
1321   */
1322
1323   httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
1324                    "/printers/%s", printer);
1325
1326   request = ippNew();
1327
1328   request->request.op.operation_id = CUPS_ADD_PRINTER;
1329   request->request.op.request_id   = 1;
1330
1331   language = cupsLangDefault();
1332
1333   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1334                "attributes-charset", NULL, cupsLangEncoding(language));
1335
1336   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1337                "attributes-natural-language", NULL, language->language);
1338
1339   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1340                "printer-uri", NULL, uri);
1341
1342   ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
1343                 IPP_PRINTER_IDLE);
1344
1345   ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
1346
1347  /*
1348   * Do the request and get back a response...
1349   */
1350
1351   if ((response = cupsDoRequest(http, request, "/admin/")) == NULL)
1352   {
1353     fprintf(stderr, "lpadmin: add-printer (enable) failed: %s\n",
1354             ippErrorString(cupsLastError()));
1355     return (1);
1356   }
1357   else if (response->request.status.status_code > IPP_OK_CONFLICT)
1358   {
1359     fprintf(stderr, "lpadmin: add-printer (enable) failed: %s\n",
1360             ippErrorString(response->request.status.status_code));
1361
1362     ippDelete(response);
1363
1364     return (1);
1365   }
1366   else
1367   {
1368     ippDelete(response);
1369
1370     return (0);
1371   }
1372 }
1373
1374
1375 /*
1376  * 'get_line()' - Get a line that is terminated by a LF, CR, or CR LF.
1377  */
1378
1379 static char *                           /* O - Pointer to buf or NULL on EOF */
1380 get_line(char *buf,                     /* I - Line buffer */
1381          int  length,                   /* I - Length of buffer */
1382          FILE *fp)                      /* I - File to read from */
1383 {
1384   char  *bufptr;                        /* Pointer into buffer */
1385   int   ch;                             /* Character from file */
1386
1387
1388   length --;
1389   bufptr = buf;
1390
1391   while ((ch = getc(fp)) != EOF)
1392   {
1393     if (ch == '\n')
1394       break;
1395     else if (ch == '\r')
1396     {
1397      /*
1398       * Look for LF...
1399       */
1400
1401       ch = getc(fp);
1402       if (ch != '\n' && ch != EOF)
1403         ungetc(ch, fp);
1404
1405       break;
1406     }
1407
1408     *bufptr++ = ch;
1409     length --;
1410     if (length == 0)
1411       break;
1412   }
1413
1414   *bufptr = '\0';
1415
1416   if (ch == EOF)
1417     return (NULL);
1418   else
1419     return (buf);
1420 }
1421
1422
1423 /*
1424  * 'set_printer_device()' - Set the device-uri attribute.
1425  */
1426
1427 static int                              /* O - 0 on success, 1 on fail */
1428 set_printer_device(http_t *http,        /* I - Server connection */
1429                    char   *printer,     /* I - Printer */
1430                    char   *device)      /* I - New device URI */
1431 {
1432   ipp_t         *request,               /* IPP Request */
1433                 *response;              /* IPP Response */
1434   cups_lang_t   *language;              /* Default language */
1435   char          uri[HTTP_MAX_URI];      /* URI for printer/class */
1436
1437
1438   DEBUG_printf(("set_printer_device(%p, \"%s\", \"%s\")\n", http, printer,
1439                 device));
1440
1441  /*
1442   * Build a CUPS_ADD_PRINTER request, which requires the following
1443   * attributes:
1444   *
1445   *    attributes-charset
1446   *    attributes-natural-language
1447   *    printer-uri
1448   */
1449
1450   httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
1451                    "/printers/%s", printer);
1452
1453   request = ippNew();
1454
1455   request->request.op.operation_id = CUPS_ADD_PRINTER;
1456   request->request.op.request_id   = 1;
1457
1458   language = cupsLangDefault();
1459
1460   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1461                "attributes-charset", NULL, cupsLangEncoding(language));
1462
1463   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1464                "attributes-natural-language", NULL, language->language);
1465
1466   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1467                "printer-uri", NULL, uri);
1468
1469  /*
1470   * Add the device URI...
1471   */
1472
1473   if (device[0] == '/')
1474   {
1475    /*
1476     * Convert filename to URI...
1477     */
1478
1479     snprintf(uri, sizeof(uri), "file:%s", device);
1480     ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
1481                  uri);
1482   }
1483   else
1484     ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
1485                  device);
1486
1487  /*
1488   * Do the request and get back a response...
1489   */
1490
1491   if ((response = cupsDoRequest(http, request, "/admin/")) == NULL)
1492   {
1493     fprintf(stderr, "lpadmin: add-printer (set device) failed: %s\n",
1494             ippErrorString(cupsLastError()));
1495     return (1);
1496   }
1497   else if (response->request.status.status_code > IPP_OK_CONFLICT)
1498   {
1499     fprintf(stderr, "lpadmin: add-printer (set device) failed: %s\n",
1500             ippErrorString(response->request.status.status_code));
1501
1502     ippDelete(response);
1503
1504     return (1);
1505   }
1506   else
1507   {
1508     ippDelete(response);
1509
1510     return (0);
1511   }
1512 }
1513
1514
1515 /*
1516  * 'set_printer_file()' - Set the interface script or PPD file.
1517  */
1518
1519 static int                              /* O - 0 on success, 1 on fail */
1520 set_printer_file(http_t *http,          /* I - Server connection */
1521                  char   *printer,       /* I - Printer */
1522                  char   *file)          /* I - PPD file or interface script */
1523 {
1524   ipp_status_t  status;                 /* IPP status code */
1525   ipp_t         *request,               /* IPP Request */
1526                 *response;              /* IPP Response */
1527   cups_lang_t   *language;              /* Default language */
1528   char          uri[HTTP_MAX_URI];      /* URI for printer/class */
1529 #ifdef HAVE_LIBZ
1530   char          tempfile[1024];         /* Temporary filename */
1531   int           fd;                     /* Temporary file */
1532   gzFile        *gz;                    /* GZIP'd file */
1533   char          buffer[8192];           /* Copy buffer */
1534   int           bytes;                  /* Bytes in buffer */
1535
1536
1537   DEBUG_printf(("set_printer_file(%p, \"%s\", \"%s\")\n", http, printer,
1538                 file));
1539
1540  /*
1541   * See if the file is gzip'd; if so, unzip it to a temporary file and
1542   * send the uncompressed file.
1543   */
1544
1545   if (!strcmp(file + strlen(file) - 3, ".gz"))
1546   {
1547    /*
1548     * Yes, the file is compressed; uncompress to a temp file...
1549     */
1550
1551     if ((fd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
1552     {
1553       _cupsLangPrintf(stderr, NULL,
1554                       _("lpadmin: Unable to create temporary file: %s\n"),
1555                       strerror(errno));
1556       return (1);
1557     }
1558
1559     if ((gz = gzopen(file, "rb")) == NULL)
1560     {
1561       _cupsLangPrintf(stderr, NULL,
1562                       _("lpadmin: Unable to open file \"%s\": %s\n"),
1563                       file, strerror(errno));
1564       close(fd);
1565       unlink(tempfile);
1566       return (1);
1567     }
1568
1569     while ((bytes = gzread(gz, buffer, sizeof(buffer))) > 0)
1570       write(fd, buffer, bytes);
1571
1572     close(fd);
1573     gzclose(gz);
1574
1575     file = tempfile;
1576   }
1577 #endif /* HAVE_LIBZ */
1578
1579  /*
1580   * Build a CUPS_ADD_PRINTER request, which requires the following
1581   * attributes:
1582   *
1583   *    attributes-charset
1584   *    attributes-natural-language
1585   *    printer-uri
1586   */
1587
1588   httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
1589                    "/printers/%s", printer);
1590
1591   request = ippNew();
1592
1593   request->request.op.operation_id = CUPS_ADD_PRINTER;
1594   request->request.op.request_id   = 1;
1595
1596   language = cupsLangDefault();
1597
1598   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1599                "attributes-charset", NULL, cupsLangEncoding(language));
1600
1601   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1602                "attributes-natural-language", NULL, language->language);
1603
1604   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1605                "printer-uri", NULL, uri);
1606
1607  /*
1608   * Do the request and get back a response...
1609   */
1610
1611   if ((response = cupsDoFileRequest(http, request, "/admin/", file)) == NULL)
1612     status = cupsLastError();
1613   else
1614   {
1615     status = response->request.status.status_code;
1616     ippDelete(response);
1617   }
1618
1619 #ifdef HAVE_LIBZ
1620  /*
1621   * Remove the temporary file as needed...
1622   */
1623
1624   if (file == tempfile)
1625     unlink(tempfile);
1626 #endif /* HAVE_LIBZ */
1627
1628   if (status > IPP_OK_CONFLICT)
1629   {
1630     _cupsLangPrintf(stderr, NULL,
1631                     _("lpadmin: add-printer (set model) failed: %s\n"),
1632                     ippErrorString(status));
1633
1634     return (1);
1635   }
1636   else
1637     return (0);
1638 }
1639
1640
1641 /*
1642  * 'set_printer_info()' - Set the printer description string.
1643  */
1644
1645 static int                              /* O - 0 on success, 1 on fail */
1646 set_printer_info(http_t *http,          /* I - Server connection */
1647                  char   *printer,       /* I - Printer */
1648                  char   *info)          /* I - New description string */
1649 {
1650   ipp_t         *request,               /* IPP Request */
1651                 *response;              /* IPP Response */
1652   cups_lang_t   *language;              /* Default language */
1653   char          uri[HTTP_MAX_URI];      /* URI for printer/class */
1654
1655
1656   DEBUG_printf(("set_printer_info(%p, \"%s\", \"%s\")\n", http, printer,
1657                 info));
1658
1659  /*
1660   * Build a CUPS_ADD_PRINTER request, which requires the following
1661   * attributes:
1662   *
1663   *    attributes-charset
1664   *    attributes-natural-language
1665   *    printer-uri
1666   */
1667
1668   httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
1669                    "/printers/%s", printer);
1670
1671   request = ippNew();
1672
1673   request->request.op.operation_id = CUPS_ADD_PRINTER;
1674   request->request.op.request_id   = 1;
1675
1676   language = cupsLangDefault();
1677
1678   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1679                "attributes-charset", NULL, cupsLangEncoding(language));
1680
1681   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1682                "attributes-natural-language", NULL, language->language);
1683
1684   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1685                "printer-uri", NULL, uri);
1686
1687  /*
1688   * Add the info string...
1689   */
1690
1691   ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info", NULL,
1692                info);
1693
1694  /*
1695   * Do the request and get back a response...
1696   */
1697
1698   if ((response = cupsDoRequest(http, request, "/admin/")) == NULL)
1699   {
1700     _cupsLangPrintf(stderr, NULL,
1701                     _("lpadmin: add-printer (set description) failed: %s\n"),
1702                     ippErrorString(cupsLastError()));
1703     return (1);
1704   }
1705   else if (response->request.status.status_code > IPP_OK_CONFLICT)
1706   {
1707     _cupsLangPrintf(stderr, NULL,
1708                     _("lpadmin: add-printer (set description) failed: %s\n"),
1709                     ippErrorString(response->request.status.status_code));
1710
1711     ippDelete(response);
1712
1713     return (1);
1714   }
1715   else
1716   {
1717     ippDelete(response);
1718
1719     return (0);
1720   }
1721 }
1722
1723
1724 /*
1725  * 'set_printer_location()' - Set the printer location string.
1726  */
1727
1728 static int                              /* O - 0 on success, 1 on fail */
1729 set_printer_location(http_t *http,      /* I - Server connection */
1730                      char   *printer,   /* I - Printer */
1731                      char   *location)  /* I - New location string */
1732 {
1733   ipp_t         *request,               /* IPP Request */
1734                 *response;              /* IPP Response */
1735   cups_lang_t   *language;              /* Default language */
1736   char          uri[HTTP_MAX_URI];      /* URI for printer/class */
1737
1738
1739   DEBUG_printf(("set_printer_location(%p, \"%s\", \"%s\")\n", http, printer,
1740                 location));
1741
1742  /*
1743   * Build a CUPS_ADD_PRINTER request, which requires the following
1744   * attributes:
1745   *
1746   *    attributes-charset
1747   *    attributes-natural-language
1748   *    printer-uri
1749   */
1750
1751   httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
1752                    "/printers/%s", printer);
1753
1754   request = ippNew();
1755
1756   request->request.op.operation_id = CUPS_ADD_PRINTER;
1757   request->request.op.request_id   = 1;
1758
1759   language = cupsLangDefault();
1760
1761   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1762                "attributes-charset", NULL, cupsLangEncoding(language));
1763
1764   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1765                "attributes-natural-language", NULL, language->language);
1766
1767   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1768                "printer-uri", NULL, uri);
1769
1770  /*
1771   * Add the location string...
1772   */
1773
1774   ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location", NULL,
1775                location);
1776
1777  /*
1778   * Do the request and get back a response...
1779   */
1780
1781   if ((response = cupsDoRequest(http, request, "/admin/")) == NULL)
1782   {
1783     _cupsLangPrintf(stderr, NULL,
1784                     _("lpadmin: add-printer (set location) failed: %s\n"),
1785                     ippErrorString(cupsLastError()));
1786
1787     return (1);
1788   }
1789   else if (response->request.status.status_code > IPP_OK_CONFLICT)
1790   {
1791     _cupsLangPrintf(stderr, NULL,
1792                     _("lpadmin: add-printer (set location) failed: %s\n"),
1793                     ippErrorString(response->request.status.status_code));
1794
1795     ippDelete(response);
1796
1797     return (1);
1798   }
1799   else
1800   {
1801     ippDelete(response);
1802
1803     return (0);
1804   }
1805 }
1806
1807
1808 /*
1809  * 'set_printer_model()' - Set the driver model file.
1810  */
1811
1812 static int                              /* O - 0 on success, 1 on fail */
1813 set_printer_model(http_t *http,         /* I - Server connection */
1814                   char   *printer,      /* I - Printer */
1815                   char   *model)        /* I - Driver model file */
1816 {
1817   ipp_t         *request,               /* IPP Request */
1818                 *response;              /* IPP Response */
1819   cups_lang_t   *language;              /* Default language */
1820   char          uri[HTTP_MAX_URI];      /* URI for printer/class */
1821
1822
1823  /*
1824   * Build a CUPS_ADD_PRINTER request, which requires the following
1825   * attributes:
1826   *
1827   *    attributes-charset
1828   *    attributes-natural-language
1829   *    printer-uri
1830   *    ppd-name
1831   */
1832
1833   httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
1834                    "/printers/%s", printer);
1835
1836   request = ippNew();
1837
1838   request->request.op.operation_id = CUPS_ADD_PRINTER;
1839   request->request.op.request_id   = 1;
1840
1841   language = cupsLangDefault();
1842
1843   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1844                "attributes-charset", NULL, cupsLangEncoding(language));
1845
1846   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1847                "attributes-natural-language", NULL, language->language);
1848
1849   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1850                "printer-uri", NULL, uri);
1851
1852   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1853                "ppd-name", NULL, model);
1854
1855  /*
1856   * Do the request and get back a response...
1857   */
1858
1859   if ((response = cupsDoRequest(http, request, "/admin/")) == NULL)
1860   {
1861     _cupsLangPrintf(stderr, NULL,
1862                     _("lpadmin: add-printer (set model) failed: %s\n"),
1863                     ippErrorString(cupsLastError()));
1864
1865     return (1);
1866   }
1867   else if (response->request.status.status_code > IPP_OK_CONFLICT)
1868   {
1869     _cupsLangPrintf(stderr, NULL,
1870                     _("lpadmin: add-printer (set model) failed: %s\n"),
1871                     ippErrorString(response->request.status.status_code));
1872
1873     ippDelete(response);
1874
1875     return (1);
1876   }
1877   else
1878   {
1879     ippDelete(response);
1880
1881     return (0);
1882   }
1883 }
1884
1885
1886 /*
1887  * 'set_printer_options()' - Set the printer options.
1888  */
1889
1890 static int                              /* O - 0 on success, 1 on fail */
1891 set_printer_options(http_t        *http,/* I - Server connection */
1892                     char          *printer,
1893                                         /* I - Printer */
1894                     int           num_options,
1895                                         /* I - Number of options */
1896                     cups_option_t *options)
1897                                         /* I - Options */
1898 {
1899   ipp_t         *request,               /* IPP Request */
1900                 *response;              /* IPP Response */
1901   ipp_attribute_t *attr;                /* IPP attribute */
1902   cups_lang_t   *language;              /* Default language */
1903   ipp_op_t      op;                     /* Operation to perform */
1904   const char    *val,                   /* Option value */
1905                 *ppdfile;               /* PPD filename */
1906   char          uri[HTTP_MAX_URI],      /* URI for printer/class */
1907                 line[1024],             /* Line from PPD file */
1908                 keyword[1024],          /* Keyword from Default line */
1909                 *keyptr,                /* Pointer into keyword... */
1910                 tempfile[1024];         /* Temporary filename */
1911   FILE          *in,                    /* PPD file */
1912                 *out;                   /* Temporary file */
1913   int           outfd;                  /* Temporary file descriptor */
1914   const char    *protocol;              /* Protocol */
1915
1916
1917   DEBUG_printf(("set_printer_options(%p, \"%s\", %d, %p)\n", http, printer,
1918                 num_options, options));
1919
1920   language = cupsLangDefault();
1921
1922   httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
1923                    "/printers/%s", printer);
1924
1925  /*
1926   * Build a GET_PRINTER_ATTRIBUTES request, which requires the following
1927   * attributes:
1928   *
1929   *    attributes-charset
1930   *    attributes-natural-language
1931   *    printer-uri
1932   *    requested-attributes
1933   */
1934
1935   request = ippNew();
1936
1937   request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
1938   request->request.op.request_id   = 1;
1939
1940   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1941                "attributes-charset", NULL, cupsLangEncoding(language));
1942
1943   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1944                "attributes-natural-language", NULL, language->language);
1945
1946   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1947                "printer-uri", NULL, uri);
1948
1949   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1950                "requested-attributes", NULL, "printer-type");
1951
1952  /*
1953   * Do the request...
1954   */
1955
1956   op = CUPS_ADD_PRINTER;
1957
1958   if ((response = cupsDoRequest(http, request, "/")) != NULL)
1959   {
1960    /*
1961     * See what kind of printer or class it is...
1962     */
1963
1964     if ((attr = ippFindAttribute(response, "printer-type", IPP_TAG_ENUM)) != NULL)
1965     {
1966       if (attr->values[0].integer & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
1967       {
1968         op = CUPS_ADD_CLASS;
1969         httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0,
1970                          "/classes/%s", printer);
1971       }
1972     }
1973
1974     ippDelete(response);
1975   }
1976
1977  /*
1978   * Build a CUPS_ADD_PRINTER or CUPS_ADD_CLASS request, which requires
1979   * the following attributes:
1980   *
1981   *    attributes-charset
1982   *    attributes-natural-language
1983   *    printer-uri
1984   *    other options
1985   */
1986
1987   request = ippNew();
1988
1989   request->request.op.operation_id = op;
1990   request->request.op.request_id   = 1;
1991
1992   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1993                "attributes-charset", NULL, cupsLangEncoding(language));
1994
1995   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1996                "attributes-natural-language", NULL, language->language);
1997
1998   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1999                "printer-uri", NULL, uri);
2000
2001  /*
2002   * Add the options...
2003   */
2004
2005   cupsEncodeOptions(request, num_options, options);
2006
2007   if (op == CUPS_ADD_PRINTER)
2008     ppdfile = cupsGetPPD(printer);
2009   else
2010     ppdfile = NULL;
2011
2012   if (ppdfile != NULL)
2013   {
2014    /*
2015     * Set default options in the PPD file...
2016     */
2017
2018     if ((outfd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
2019     {
2020       _cupsLangPrintf(stderr, NULL,
2021                       _("lpadmin: Unable to create temporary file - %s\n"),
2022                       strerror(errno));
2023       ippDelete(request);
2024       unlink(ppdfile);
2025       return (1);
2026     }
2027
2028     if ((in = fopen(ppdfile, "rb")) == NULL)
2029     {
2030       _cupsLangPrintf(stderr, NULL,
2031                       _("lpadmin: Unable to open PPD file \"%s\" - %s\n"),
2032                       ppdfile, strerror(errno));
2033       ippDelete(request);
2034       unlink(ppdfile);
2035       close(outfd);
2036       unlink(tempfile);
2037       return (1);
2038     }
2039
2040     out      = fdopen(outfd, "wb");
2041     protocol = cupsGetOption("protocol", num_options, options);    
2042
2043     while (get_line(line, sizeof(line), in) != NULL)
2044     {
2045       if (!strncmp(line, "*cupsProtocol:", 14) && protocol)
2046       {
2047        /*
2048         * Set a new output protocol (BCP or TBCP) below...
2049         */
2050
2051         continue;
2052       }
2053       else if (strncmp(line, "*Default", 8))
2054         fprintf(out, "%s\n", line);
2055       else
2056       {
2057        /*
2058         * Get default option name...
2059         */
2060
2061         strlcpy(keyword, line + 8, sizeof(keyword));
2062
2063         for (keyptr = keyword; *keyptr; keyptr ++)
2064           if (*keyptr == ':' || isspace(*keyptr & 255))
2065             break;
2066
2067         *keyptr = '\0';
2068
2069         if (strcmp(keyword, "PageRegion") == 0)
2070           val = cupsGetOption("PageSize", num_options, options);
2071         else
2072           val = cupsGetOption(keyword, num_options, options);
2073
2074         if (val != NULL)
2075           fprintf(out, "*Default%s: %s\n", keyword, val);
2076         else
2077           fprintf(out, "%s\n", line);
2078       }
2079     }
2080
2081     if (protocol)
2082       fprintf(out, "*cupsProtocol: \"%s\"\n", protocol);
2083
2084     fclose(in);
2085     fclose(out);
2086     close(outfd);
2087
2088    /*
2089     * Do the request...
2090     */
2091
2092     response = cupsDoFileRequest(http, request, "/admin/", tempfile);
2093
2094    /*
2095     * Clean up temp files... (TODO: catch signals in case we CTRL-C during
2096     * lpadmin)
2097     */
2098
2099     unlink(ppdfile);
2100     unlink(tempfile);
2101   }
2102   else
2103   {
2104    /*
2105     * No PPD file - just set the options...
2106     */
2107
2108     response = cupsDoRequest(http, request, "/admin/");
2109   }
2110
2111  /*
2112   * Check the response...
2113   */
2114
2115   if (response == NULL)
2116   {
2117     _cupsLangPrintf(stderr, NULL, _("lpadmin: %s failed: %s\n"),
2118                     op == CUPS_ADD_PRINTER ? "add-printer" : "add-class",
2119                     ippErrorString(cupsLastError()));
2120
2121     return (1);
2122   }
2123   else if (response->request.status.status_code > IPP_OK_CONFLICT)
2124   {
2125     _cupsLangPrintf(stderr, NULL, _("lpadmin: %s failed: %s\n"),
2126                     op == CUPS_ADD_PRINTER ? "add-printer" : "add-class",
2127                     ippErrorString(response->request.status.status_code));
2128
2129     ippDelete(response);
2130
2131     return (1);
2132   }
2133   else
2134   {
2135     ippDelete(response);
2136
2137     return (0);
2138   }
2139 }
2140
2141
2142 /*
2143  * 'validate_name()' - Make sure the printer name only contains valid chars.
2144  */
2145
2146 static int                      /* O - 0 if name is no good, 1 if name is good */
2147 validate_name(const char *name) /* I - Name to check */
2148 {
2149   const char    *ptr;           /* Pointer into name */
2150
2151
2152  /*
2153   * Scan the whole name...
2154   */
2155
2156   for (ptr = name; *ptr; ptr ++)
2157     if (*ptr == '@')
2158       break;
2159     else if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' ||
2160              *ptr == '#')
2161       return (0);
2162
2163  /*
2164   * All the characters are good; validate the length, too...
2165   */
2166
2167   return ((ptr - name) < 128);
2168 }
2169
2170
2171 /*
2172  * End of "$Id: lpadmin.c 4906 2006-01-10 20:53:28Z mike $".
2173  */