]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/adminutil.c
Load cups into easysw/current.
[thirdparty/cups.git] / cups / adminutil.c
1 /*
2 * "$Id: adminutil.c 6378 2007-03-21 07:18:18Z mike $"
3 *
4 * Administration utility API definitions for the Common UNIX Printing
5 * System (CUPS).
6 *
7 * Copyright 2001-2007 by Easy Software Products.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Easy Software Products and are protected by Federal
11 * copyright law. Distribution and use rights are outlined in the file
12 * "LICENSE.txt" which should have been included with this file. If this
13 * file is missing or damaged please contact Easy Software Products
14 * at:
15 *
16 * Attn: CUPS Licensing Information
17 * Easy Software Products
18 * 44141 Airport View Drive, Suite 204
19 * Hollywood, Maryland 20636 USA
20 *
21 * Voice: (301) 373-9600
22 * EMail: cups-info@cups.org
23 * WWW: http://www.cups.org
24 *
25 * This file is subject to the Apple OS-Developed Software exception.
26 *
27 * Contents:
28 *
29 * cupsAdminCreateWindowsPPD() - Create the Windows PPD file for a printer.
30 * cupsAdminExportSamba() - Export a printer to Samba.
31 * cupsAdminGetServerSettings() - Get settings from the server.
32 * _cupsAdminGetServerSettings() - Get settings from the server (private).
33 * cupsAdminSetServerSettings() - Set settings on the server.
34 * _cupsAdminSetServerSettings() - Set settings on the server (private).
35 * do_samba_command() - Do a SAMBA command.
36 * get_cupsd_conf() - Get the current cupsd.conf file.
37 * invalidate_cupsd_cache() - Invalidate the cached cupsd.conf settings.
38 * write_option() - Write a CUPS option to a PPD file.
39 */
40
41 /*
42 * Include necessary headers...
43 */
44
45 #include "adminutil.h"
46 #include "globals.h"
47 #include "debug.h"
48 #include <errno.h>
49 #include <fcntl.h>
50 #include <sys/stat.h>
51 #ifdef WIN32
52 #else
53 # include <unistd.h>
54 # include <sys/wait.h>
55 #endif /* WIN32 */
56
57
58 /*
59 * Local functions...
60 */
61
62 extern int _cupsAdminGetServerSettings(http_t *http,
63 int *num_settings,
64 cups_option_t **settings);
65 extern int _cupsAdminSetServerSettings(http_t *http,
66 int num_settings,
67 cups_option_t *settings);
68 static int do_samba_command(const char *command,
69 const char *address,
70 const char *subcommand,
71 const char *authfile,
72 FILE *logfile);
73 static http_status_t get_cupsd_conf(http_t *http, _cups_globals_t *cg,
74 time_t last_update, char *name,
75 int namelen, int *remote);
76 static void invalidate_cupsd_cache(_cups_globals_t *cg);
77 static void write_option(cups_file_t *dstfp, int order,
78 const char *name, const char *text,
79 const char *attrname,
80 ipp_attribute_t *suppattr,
81 ipp_attribute_t *defattr, int defval,
82 int valcount);
83
84
85 /*
86 * 'cupsAdminCreateWindowsPPD()' - Create the Windows PPD file for a printer.
87 */
88
89 char * /* O - PPD file or NULL */
90 cupsAdminCreateWindowsPPD(
91 http_t *http, /* I - Connection to server */
92 const char *dest, /* I - Printer or class */
93 char *buffer, /* I - Filename buffer */
94 int bufsize) /* I - Size of filename buffer */
95 {
96 const char *src; /* Source PPD filename */
97 cups_file_t *srcfp, /* Source PPD file */
98 *dstfp; /* Destination PPD file */
99 ipp_t *request, /* IPP request */
100 *response; /* IPP response */
101 ipp_attribute_t *suppattr, /* IPP -supported attribute */
102 *defattr; /* IPP -default attribute */
103 cups_lang_t *language; /* Current language */
104 char line[256], /* Line from PPD file */
105 junk[256], /* Extra junk to throw away */
106 *ptr, /* Pointer into line */
107 uri[1024], /* Printer URI */
108 option[41], /* Option */
109 choice[41]; /* Choice */
110 int jcloption, /* In a JCL option? */
111 linenum; /* Current line number */
112 time_t curtime; /* Current time */
113 struct tm *curdate; /* Current date */
114 static const char * const pattrs[] = /* Printer attributes we want */
115 {
116 "job-hold-until-supported",
117 "job-hold-until-default",
118 "job-sheets-supported",
119 "job-sheets-default",
120 "job-priority-supported",
121 "job-priority-default"
122 };
123
124
125 /*
126 * Range check the input...
127 */
128
129 if (buffer)
130 *buffer = '\0';
131
132 if (!http || !dest || !buffer || bufsize < 2)
133 return (NULL);
134
135 /*
136 * Get the PPD file...
137 */
138
139 if ((src = cupsGetPPD2(http, dest)) == NULL)
140 return (NULL);
141
142 /*
143 * Get the supported banner pages, etc. for the printer...
144 */
145
146 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
147
148 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
149 "localhost", 0, "/printers/%s", dest);
150 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
151 "printer-uri", NULL, uri);
152
153 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
154 "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
155 NULL, pattrs);
156
157 /*
158 * Do the request and get back a response...
159 */
160
161 response = cupsDoRequest(http, request, "/");
162 if (!response || cupsLastError() > IPP_OK_CONFLICT)
163 {
164 unlink(src);
165 return (NULL);
166 }
167
168 /*
169 * Open the original PPD file...
170 */
171
172 if ((srcfp = cupsFileOpen(src, "rb")) == NULL)
173 return (NULL);
174
175 /*
176 * Create a temporary output file using the destination buffer...
177 */
178
179 if ((dstfp = cupsTempFile2(buffer, bufsize)) == NULL)
180 {
181 cupsFileClose(srcfp);
182
183 unlink(src);
184
185 return (NULL);
186 }
187
188 /*
189 * Write a new header explaining that this isn't the original PPD...
190 */
191
192 cupsFilePuts(dstfp, "*PPD-Adobe: \"4.3\"\n");
193
194 curtime = time(NULL);
195 curdate = gmtime(&curtime);
196
197 cupsFilePrintf(dstfp, "*%% Modified on %04d%02d%02d%02d%02d%02d+0000 "
198 "for CUPS Windows Driver\n",
199 curdate->tm_year + 1900, curdate->tm_mon + 1, curdate->tm_mday,
200 curdate->tm_hour, curdate->tm_min, curdate->tm_sec);
201
202 /*
203 * Read the existing PPD file, converting all PJL commands to CUPS
204 * job ticket comments...
205 */
206
207 jcloption = 0;
208 linenum = 0;
209 language = cupsLangDefault();
210
211 while (cupsFileGets(srcfp, line, sizeof(line)))
212 {
213 linenum ++;
214
215 if (!strncmp(line, "*PPD-Adobe:", 11))
216 {
217 /*
218 * Already wrote the PPD header...
219 */
220
221 continue;
222 }
223 else if (!strncmp(line, "*JCLBegin:", 10) ||
224 !strncmp(line, "*JCLToPSInterpreter:", 20) ||
225 !strncmp(line, "*JCLEnd:", 8) ||
226 !strncmp(line, "*Protocols:", 11))
227 {
228 /*
229 * Don't use existing JCL keywords; we'll create our own, below...
230 */
231
232 cupsFilePrintf(dstfp, "*%% Commented out for CUPS Windows Driver...\n"
233 "*%%%s\n", line + 1);
234 continue;
235 }
236 else if (!strncmp(line, "*JCLOpenUI", 10))
237 {
238 jcloption = 1;
239 cupsFilePrintf(dstfp, "%s\n", line);
240 }
241 else if (!strncmp(line, "*JCLCloseUI", 11))
242 {
243 jcloption = 0;
244 cupsFilePrintf(dstfp, "%s\n", line);
245 }
246 else if (jcloption &&
247 strncmp(line, "*End", 4) &&
248 strncmp(line, "*Default", 8) &&
249 strncmp(line, "*OrderDependency", 16))
250 {
251 if ((ptr = strchr(line, ':')) == NULL)
252 {
253 snprintf(line, sizeof(line),
254 _cupsLangString(language, _("Missing value on line %d!")),
255 linenum);
256 _cupsSetError(IPP_DOCUMENT_FORMAT_ERROR, line);
257
258 cupsFileClose(srcfp);
259 cupsFileClose(dstfp);
260
261 unlink(src);
262 unlink(buffer);
263
264 *buffer = '\0';
265
266 return (NULL);
267 }
268
269 if ((ptr = strchr(ptr, '\"')) == NULL)
270 {
271 snprintf(line, sizeof(line),
272 _cupsLangString(language,
273 _("Missing double quote on line %d!")),
274 linenum);
275 _cupsSetError(IPP_DOCUMENT_FORMAT_ERROR, line);
276
277 cupsFileClose(srcfp);
278 cupsFileClose(dstfp);
279
280 unlink(src);
281 unlink(buffer);
282
283 *buffer = '\0';
284
285 return (NULL);
286 }
287
288 if (sscanf(line, "*%40s%*[ \t]%40[^/]", option, choice) != 2)
289 {
290 snprintf(line, sizeof(line),
291 _cupsLangString(language,
292 _("Bad option + choice on line %d!")),
293 linenum);
294 _cupsSetError(IPP_DOCUMENT_FORMAT_ERROR, line);
295
296 cupsFileClose(srcfp);
297 cupsFileClose(dstfp);
298
299 unlink(src);
300 unlink(buffer);
301
302 *buffer = '\0';
303
304 return (NULL);
305 }
306
307 if (strchr(ptr + 1, '\"') == NULL)
308 {
309 /*
310 * Skip remaining...
311 */
312
313 while (cupsFileGets(srcfp, junk, sizeof(junk)) != NULL)
314 {
315 linenum ++;
316
317 if (!strncmp(junk, "*End", 4))
318 break;
319 }
320 }
321
322 snprintf(ptr + 1, sizeof(line) - (ptr - line + 1),
323 "%%cupsJobTicket: %s=%s\n\"\n*End", option, choice);
324
325 cupsFilePrintf(dstfp, "*%% Changed for CUPS Windows Driver...\n%s\n",
326 line);
327 }
328 else
329 cupsFilePrintf(dstfp, "%s\n", line);
330 }
331
332 cupsFileClose(srcfp);
333 unlink(src);
334
335 if (linenum == 0)
336 {
337 snprintf(line, sizeof(line),
338 _cupsLangString(language, _("Empty PPD file!")),
339 linenum);
340 _cupsSetError(IPP_DOCUMENT_FORMAT_ERROR, line);
341
342 cupsFileClose(dstfp);
343 unlink(buffer);
344
345 *buffer = '\0';
346
347 return (NULL);
348 }
349
350 /*
351 * Now add the CUPS-specific attributes and options...
352 */
353
354 cupsFilePuts(dstfp, "\n*% CUPS Job Ticket support and options...\n");
355 cupsFilePuts(dstfp, "*Protocols: PJL\n");
356 cupsFilePuts(dstfp, "*JCLBegin: \"%!PS-Adobe-3.0<0A>\"\n");
357 cupsFilePuts(dstfp, "*JCLToPSInterpreter: \"\"\n");
358 cupsFilePuts(dstfp, "*JCLEnd: \"\"\n");
359
360 cupsFilePuts(dstfp, "\n*OpenGroup: CUPS/CUPS Options\n\n");
361
362 if ((defattr = ippFindAttribute(response, "job-hold-until-default",
363 IPP_TAG_ZERO)) != NULL &&
364 (suppattr = ippFindAttribute(response, "job-hold-until-supported",
365 IPP_TAG_ZERO)) != NULL)
366 write_option(dstfp, 10, "cupsJobHoldUntil", "Hold Until", "job-hold-until",
367 suppattr, defattr, 0, 1);
368
369 if ((defattr = ippFindAttribute(response, "job-priority-default",
370 IPP_TAG_INTEGER)) != NULL &&
371 (suppattr = ippFindAttribute(response, "job-priority-supported",
372 IPP_TAG_RANGE)) != NULL)
373 write_option(dstfp, 11, "cupsJobPriority", "Priority", "job-priority",
374 suppattr, defattr, 0, 1);
375
376 if ((defattr = ippFindAttribute(response, "job-sheets-default",
377 IPP_TAG_ZERO)) != NULL &&
378 (suppattr = ippFindAttribute(response, "job-sheets-supported",
379 IPP_TAG_ZERO)) != NULL)
380 {
381 write_option(dstfp, 20, "cupsJobSheetsStart", "Start Banner",
382 "job-sheets", suppattr, defattr, 0, 2);
383 write_option(dstfp, 21, "cupsJobSheetsEnd", "End Banner",
384 "job-sheets", suppattr, defattr, 1, 2);
385 }
386
387 cupsFilePuts(dstfp, "*CloseGroup: CUPS\n");
388 cupsFileClose(dstfp);
389
390 ippDelete(response);
391
392 return (buffer);
393 }
394
395
396 /*
397 * 'cupsAdminExportSamba()' - Export a printer to Samba.
398 */
399
400 int /* O - 1 on success, 0 on failure */
401 cupsAdminExportSamba(
402 const char *dest, /* I - Destination to export */
403 const char *ppd, /* I - PPD file */
404 const char *samba_server, /* I - Samba server */
405 const char *samba_user, /* I - Samba username */
406 const char *samba_password, /* I - Samba password */
407 FILE *logfile) /* I - Log file, if any */
408 {
409 int status; /* Status of Samba commands */
410 int have_drivers; /* Have drivers? */
411 char file[1024], /* File to test for */
412 authfile[1024], /* Temporary authentication file */
413 address[1024], /* Address for command */
414 subcmd[1024], /* Sub-command */
415 message[1024]; /* Error message */
416 cups_file_t *fp; /* Authentication file */
417 cups_lang_t *language; /* Current language */
418 _cups_globals_t *cg = _cupsGlobals();
419 /* Global data */
420
421
422 /*
423 * Range check input...
424 */
425
426 if (!dest || !ppd || !samba_server || !samba_user || !samba_password)
427 {
428 _cupsSetError(IPP_INTERNAL_ERROR, NULL);
429 return (0);
430 }
431
432 /*
433 * Create a temporary authentication file for Samba...
434 */
435
436 if ((fp = cupsTempFile2(authfile, sizeof(authfile))) == NULL)
437 {
438 _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno));
439 return (0);
440 }
441
442 cupsFilePrintf(fp, "username = %s\n", samba_user);
443 cupsFilePrintf(fp, "password = %s\n", samba_password);
444 cupsFileClose(fp);
445
446 /*
447 * See which drivers are available; the new CUPS v6 and Adobe drivers
448 * depend on the Windows 2k PS driver, so copy that driver first:
449 *
450 * Files:
451 *
452 * ps5ui.dll
453 * pscript.hlp
454 * pscript.ntf
455 * pscript5.dll
456 */
457
458 have_drivers = 0;
459 language = cupsLangDefault();
460
461 snprintf(file, sizeof(file), "%s/drivers/pscript5.dll", cg->cups_datadir);
462 if (!access(file, 0))
463 {
464 have_drivers |= 1;
465
466 /*
467 * Windows 2k driver is installed; do the smbclient commands needed
468 * to copy the Win2k drivers over...
469 */
470
471 snprintf(address, sizeof(address), "//%s/print$", samba_server);
472
473 snprintf(subcmd, sizeof(subcmd),
474 "mkdir W32X86;"
475 "put %s W32X86/%s.ppd;"
476 "put %s/drivers/ps5ui.dll W32X86/ps5ui.dll;"
477 "put %s/drivers/pscript.hlp W32X86/pscript.hlp;"
478 "put %s/drivers/pscript.ntf W32X86/pscript.ntf;"
479 "put %s/drivers/pscript5.dll W32X86/pscript5.dll",
480 ppd, dest, cg->cups_datadir, cg->cups_datadir,
481 cg->cups_datadir, cg->cups_datadir);
482
483 if ((status = do_samba_command("smbclient", address, subcmd,
484 authfile, logfile)) != 0)
485 {
486 snprintf(message, sizeof(message),
487 _cupsLangString(language,
488 _("Unable to copy Windows 2000 printer "
489 "driver files (%d)!")), status);
490
491 _cupsSetError(IPP_INTERNAL_ERROR, message);
492
493 if (logfile)
494 _cupsLangPrintf(logfile, "%s\n", message);
495
496 unlink(authfile);
497
498 return (0);
499 }
500
501 /*
502 * See if we also have the CUPS driver files; if so, use them!
503 */
504
505 snprintf(file, sizeof(file), "%s/drivers/cupsps6.dll", cg->cups_datadir);
506 if (!access(file, 0))
507 {
508 /*
509 * Copy the CUPS driver files over...
510 */
511
512 snprintf(subcmd, sizeof(subcmd),
513 "put %s/drivers/cups6.ini W32X86/cups6.ini;"
514 "put %s/drivers/cupsps6.dll W32X86/cupsps6.dll;"
515 "put %s/drivers/cupsui6.dll W32X86/cupsui6.dll",
516 cg->cups_datadir, cg->cups_datadir, cg->cups_datadir);
517
518 if ((status = do_samba_command("smbclient", address, subcmd,
519 authfile, logfile)) != 0)
520 {
521 snprintf(message, sizeof(message),
522 _cupsLangString(language,
523 _("Unable to copy CUPS printer driver "
524 "files (%d)!")), status);
525
526 _cupsSetError(IPP_INTERNAL_ERROR, message);
527
528 if (logfile)
529 _cupsLangPrintf(logfile, "%s\n", message);
530
531 unlink(authfile);
532
533 return (0);
534 }
535
536 /*
537 * Do the rpcclient command needed for the CUPS drivers...
538 */
539
540 snprintf(subcmd, sizeof(subcmd),
541 "adddriver \"Windows NT x86\" \"%s:"
542 "pscript5.dll:%s.ppd:ps5ui.dll:pscript.hlp:NULL:RAW:"
543 "pscript5.dll,%s.ppd,ps5ui.dll,pscript.hlp,pscript.ntf,"
544 "cups6.ini,cupsps6.dll,cupsui6.dll\"",
545 dest, dest, dest);
546 }
547 else
548 {
549 /*
550 * Don't have the CUPS drivers, so just use the standard Windows
551 * drivers...
552 */
553
554 snprintf(subcmd, sizeof(subcmd),
555 "adddriver \"Windows NT x86\" \"%s:"
556 "pscript5.dll:%s.ppd:ps5ui.dll:pscript.hlp:NULL:RAW:"
557 "pscript5.dll,%s.ppd,ps5ui.dll,pscript.hlp,pscript.ntf\"",
558 dest, dest, dest);
559 }
560
561 if ((status = do_samba_command("rpcclient", samba_server, subcmd,
562 authfile, logfile)) != 0)
563 {
564 snprintf(message, sizeof(message),
565 _cupsLangString(language,
566 _("Unable to install Windows 2000 printer "
567 "driver files (%d)!")), status);
568
569 _cupsSetError(IPP_INTERNAL_ERROR, message);
570
571 if (logfile)
572 _cupsLangPrintf(logfile, "%s\n", message);
573
574 unlink(authfile);
575
576 return (0);
577 }
578 }
579
580 snprintf(file, sizeof(file), "%s/drivers/ADOBEPS4.DRV", cg->cups_datadir);
581 if (!access(file, 0))
582 {
583 have_drivers |= 2;
584
585 /*
586 * Do the smbclient commands needed for the Adobe Win9x drivers...
587 */
588
589 snprintf(address, sizeof(address), "//%s/print$", samba_server);
590
591 snprintf(subcmd, sizeof(subcmd),
592 "mkdir WIN40;"
593 "put %s WIN40/%s.PPD;"
594 "put %s/drivers/ADFONTS.MFM WIN40/ADFONTS.MFM;"
595 "put %s/drivers/ADOBEPS4.DRV WIN40/ADOBEPS4.DRV;"
596 "put %s/drivers/ADOBEPS4.HLP WIN40/ADOBEPS4.HLP;"
597 "put %s/drivers/ICONLIB.DLL WIN40/ICONLIB.DLL;"
598 "put %s/drivers/PSMON.DLL WIN40/PSMON.DLL;",
599 ppd, dest, cg->cups_datadir, cg->cups_datadir,
600 cg->cups_datadir, cg->cups_datadir, cg->cups_datadir);
601
602 if ((status = do_samba_command("smbclient", address, subcmd,
603 authfile, logfile)) != 0)
604 {
605 snprintf(message, sizeof(message),
606 _cupsLangString(language,
607 _("Unable to copy Windows 9x printer "
608 "driver files (%d)!")), status);
609
610 _cupsSetError(IPP_INTERNAL_ERROR, message);
611
612 if (logfile)
613 _cupsLangPrintf(logfile, "%s\n", message);
614
615 unlink(authfile);
616
617 return (0);
618 }
619
620 /*
621 * Do the rpcclient commands needed for the Adobe Win9x drivers...
622 */
623
624 snprintf(subcmd, sizeof(subcmd),
625 "adddriver \"Windows 4.0\" \"%s:ADOBEPS4.DRV:%s.PPD:NULL:"
626 "ADOBEPS4.HLP:PSMON.DLL:RAW:"
627 "ADOBEPS4.DRV,%s.PPD,ADOBEPS4.HLP,PSMON.DLL,ADFONTS.MFM,"
628 "ICONLIB.DLL\"",
629 dest, dest, dest);
630
631 if ((status = do_samba_command("rpcclient", samba_server, subcmd,
632 authfile, logfile)) != 0)
633 {
634 snprintf(message, sizeof(message),
635 _cupsLangString(language,
636 _("Unable to install Windows 9x printer "
637 "driver files (%d)!")), status);
638
639 _cupsSetError(IPP_INTERNAL_ERROR, message);
640
641 if (logfile)
642 _cupsLangPrintf(logfile, "%s\n", message);
643
644 unlink(authfile);
645
646 return (0);
647 }
648 }
649
650 if (logfile && !(have_drivers & 1))
651 {
652 if (!have_drivers)
653 strlcpy(message,
654 _cupsLangString(language,
655 _("No Windows printer drivers are installed!")),
656 sizeof(message));
657 else
658 strlcpy(message,
659 _cupsLangString(language,
660 _("Warning, no Windows 2000 printer drivers "
661 "are installed!")),
662 sizeof(message));
663
664 _cupsSetError(IPP_INTERNAL_ERROR, message);
665 _cupsLangPrintf(logfile, "%s\n", message);
666 }
667
668 if (have_drivers == 0)
669 return (0);
670
671 /*
672 * Finally, associate the drivers we just added with the queue...
673 */
674
675 snprintf(subcmd, sizeof(subcmd), "setdriver %s %s", dest, dest);
676
677 if ((status = do_samba_command("rpcclient", samba_server, subcmd,
678 authfile, logfile)) != 0)
679 {
680 snprintf(message, sizeof(message),
681 _cupsLangString(language,
682 _("Unable to set Windows printer driver (%d)!")),
683 status);
684
685 _cupsSetError(IPP_INTERNAL_ERROR, message);
686
687 if (logfile)
688 _cupsLangPrintf(logfile, "%s\n", message);
689
690 unlink(authfile);
691
692 return (0);
693 }
694
695 unlink(authfile);
696
697 return (1);
698 }
699
700
701 /*
702 * 'cupsAdminGetServerSettings()' - Get settings from the server.
703 *
704 * The returned settings should be freed with cupsFreeOptions() when
705 * you are done with them.
706 *
707 * @since CUPS 1.3@
708 */
709
710 int /* O - 1 on success, 0 on failure */
711 cupsAdminGetServerSettings(
712 http_t *http, /* I - Connection to server */
713 int *num_settings, /* O - Number of settings */
714 cups_option_t **settings) /* O - Settings */
715 {
716 return (_cupsAdminGetServerSettings(http, num_settings, settings));
717 }
718
719
720 /*
721 * '_cupsAdminGetServerSettings()' - Get settings from the server.
722 *
723 * The returned settings should be freed with cupsFreeOptions() when
724 * you are done with them.
725 *
726 * @since CUPS 1.2@
727 */
728
729 int /* O - 1 on success, 0 on failure */
730 _cupsAdminGetServerSettings(
731 http_t *http, /* I - Connection to server */
732 int *num_settings, /* O - Number of settings */
733 cups_option_t **settings) /* O - Settings */
734 {
735 int i; /* Looping var */
736 cups_file_t *cupsd; /* cupsd.conf file */
737 char cupsdconf[1024]; /* cupsd.conf filename */
738 int remote; /* Remote cupsd.conf file? */
739 http_status_t status; /* Status of getting cupsd.conf */
740 char line[1024], /* Line from cupsd.conf file */
741 *value; /* Value on line */
742 cups_option_t *setting; /* Current setting */
743 _cups_globals_t *cg = _cupsGlobals(); /* Global data */
744
745
746 /*
747 * Range check input...
748 */
749
750 if (!http || !num_settings || !settings)
751 {
752 _cupsSetError(IPP_INTERNAL_ERROR, NULL);
753
754 if (num_settings)
755 *num_settings = 0;
756
757 if (settings)
758 *settings = NULL;
759
760 return (0);
761 }
762
763 *num_settings = 0;
764 *settings = NULL;
765
766 /*
767 * Get the cupsd.conf file...
768 */
769
770 if ((status = get_cupsd_conf(http, cg, cg->cupsd_update, cupsdconf,
771 sizeof(cupsdconf), &remote)) == HTTP_OK)
772 {
773 if ((cupsd = cupsFileOpen(cupsdconf, "r")) == NULL)
774 {
775 char message[1024]; /* Message string */
776
777
778 snprintf(message, sizeof(message),
779 _cupsLangString(cupsLangDefault(), _("open of %s failed: %s")),
780 cupsdconf, strerror(errno));
781 _cupsSetError(IPP_INTERNAL_ERROR, message);
782 }
783 }
784 else
785 cupsd = NULL;
786
787 if (cupsd)
788 {
789 /*
790 * Read the file, keeping track of what settings are enabled...
791 */
792
793 int remote_access = 0, /* Remote access allowed? */
794 remote_admin = 0, /* Remote administration allowed? */
795 remote_any = 0, /* Remote access from anywhere allowed? */
796 browsing = 1, /* Browsing enabled? */
797 browse_allow = 1, /* Browse address set? */
798 browse_address = 0, /* Browse address set? */
799 cancel_policy = 1, /* Cancel-job policy set? */
800 debug_logging = 0; /* LogLevel debug set? */
801 int linenum = 0, /* Line number in file */
802 in_location = 0, /* In a location section? */
803 in_policy = 0, /* In a policy section? */
804 in_cancel_job = 0, /* In a cancel-job section? */
805 in_admin_location = 0; /* In the /admin location? */
806
807
808 invalidate_cupsd_cache(cg);
809
810 cg->cupsd_update = time(NULL);
811 httpGetHostname(http, cg->cupsd_hostname, sizeof(cg->cupsd_hostname));
812
813 while (cupsFileGetConf(cupsd, line, sizeof(line), &value, &linenum))
814 {
815 if (!value)
816 continue;
817
818 if (!strcasecmp(line, "Port") || !strcasecmp(line, "Listen"))
819 {
820 char *port; /* Pointer to port number, if any */
821
822
823 if ((port = strrchr(value, ':')) != NULL)
824 *port = '\0';
825 else if (isdigit(*value & 255))
826 {
827 /*
828 * Listen on a port number implies remote access...
829 */
830
831 remote_access = 1;
832 continue;
833 }
834
835 if (strcasecmp(value, "localhost") && strcmp(value, "127.0.0.1")
836 #ifdef AF_LOCAL
837 && *value != '/'
838 #endif /* AF_LOCAL */
839 #ifdef AF_INET6
840 && strcmp(value, "::1")
841 #endif /* AF_INET6 */
842 )
843 remote_access = 1;
844 }
845 else if (!strcasecmp(line, "Browsing"))
846 {
847 browsing = !strcasecmp(value, "yes") || !strcasecmp(value, "on") ||
848 !strcasecmp(value, "true");
849 }
850 else if (!strcasecmp(line, "BrowseAddress"))
851 {
852 browse_address = 1;
853 }
854 else if (!strcasecmp(line, "BrowseAllow"))
855 {
856 browse_allow = 1;
857 }
858 else if (!strcasecmp(line, "BrowseOrder"))
859 {
860 browse_allow = !strncasecmp(value, "deny,", 5);
861 }
862 else if (!strcasecmp(line, "LogLevel"))
863 {
864 debug_logging = !strncasecmp(value, "debug", 5);
865 }
866 else if (!strcasecmp(line, "<Policy") && !strcasecmp(value, "default"))
867 {
868 in_policy = 1;
869 }
870 else if (!strcasecmp(line, "</Policy>"))
871 {
872 in_policy = 0;
873 }
874 else if (!strcasecmp(line, "<Limit") && in_policy)
875 {
876 /*
877 * See if the policy limit is for the Cancel-Job operation...
878 */
879
880 char *valptr; /* Pointer into value */
881
882
883 while (*value)
884 {
885 for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++);
886
887 if (*valptr)
888 *valptr++ = '\0';
889
890 if (!strcasecmp(value, "cancel-job") || !strcasecmp(value, "all"))
891 {
892 in_cancel_job = 1;
893 break;
894 }
895
896 for (value = valptr; isspace(*value & 255); value ++);
897 }
898 }
899 else if (!strcasecmp(line, "</Limit>"))
900 {
901 in_cancel_job = 0;
902 }
903 else if (!strcasecmp(line, "Require") && in_cancel_job)
904 {
905 cancel_policy = 0;
906 }
907 else if (!strcasecmp(line, "<Location"))
908 {
909 in_admin_location = !strcasecmp(value, "/admin");
910 in_location = 1;
911 }
912 else if (!strcasecmp(line, "</Location>"))
913 {
914 in_admin_location = 0;
915 in_location = 0;
916 }
917 else if (!strcasecmp(line, "Allow") && in_admin_location &&
918 strcasecmp(value, "localhost") && strcasecmp(value, "127.0.0.1")
919 #ifdef AF_LOCAL
920 && *value != '/'
921 #endif /* AF_LOCAL */
922 #ifdef AF_INET6
923 && strcmp(value, "::1")
924 #endif /* AF_INET6 */
925 )
926 {
927 remote_admin = 1;
928
929 if (!strcasecmp(value, "all"))
930 remote_any = 1;
931 }
932 else if (line[0] != '<' && !in_location && !in_policy)
933 cg->cupsd_num_settings = cupsAddOption(line, value,
934 cg->cupsd_num_settings,
935 &(cg->cupsd_settings));
936 }
937
938 cupsFileClose(cupsd);
939
940 cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING,
941 debug_logging ? "1" : "0",
942 cg->cupsd_num_settings,
943 &(cg->cupsd_settings));
944
945 cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN,
946 (remote_access && remote_admin) ?
947 "1" : "0",
948 cg->cupsd_num_settings,
949 &(cg->cupsd_settings));
950
951 cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY,
952 remote_any ? "1" : "0",
953 cg->cupsd_num_settings,
954 &(cg->cupsd_settings));
955
956 cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS,
957 (browsing && browse_allow) ?
958 "1" : "0",
959 cg->cupsd_num_settings,
960 &(cg->cupsd_settings));
961
962 cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS,
963 (remote_access && browsing &&
964 browse_address) ? "1" : "0",
965 cg->cupsd_num_settings,
966 &(cg->cupsd_settings));
967
968 cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY,
969 cancel_policy ? "1" : "0",
970 cg->cupsd_num_settings,
971 &(cg->cupsd_settings));
972 }
973 else if (status != HTTP_NOT_MODIFIED)
974 invalidate_cupsd_cache(cg);
975
976 /*
977 * Remove any temporary files and copy the settings array...
978 */
979
980 if (remote)
981 unlink(cupsdconf);
982
983 for (i = cg->cupsd_num_settings, setting = cg->cupsd_settings;
984 i > 0;
985 i --, setting ++)
986 *num_settings = cupsAddOption(setting->name, setting->value,
987 *num_settings, settings);
988
989 return (cg->cupsd_num_settings > 0);
990 }
991
992
993 /*
994 * 'cupsAdminSetServerSettings()' - Set settings on the server.
995 *
996 * @since CUPS 1.3@
997 */
998
999 int /* O - 1 on success, 0 on failure */
1000 cupsAdminSetServerSettings(
1001 http_t *http, /* I - Connection to server */
1002 int num_settings, /* I - Number of settings */
1003 cups_option_t *settings) /* I - Settings */
1004 {
1005 return (_cupsAdminSetServerSettings(http, num_settings, settings));
1006 }
1007
1008
1009 /*
1010 * '_cupsAdminSetServerSettings()' - Set settings on the server.
1011 *
1012 * @since CUPS 1.2@
1013 */
1014
1015 int /* O - 1 on success, 0 on failure */
1016 _cupsAdminSetServerSettings(
1017 http_t *http, /* I - Connection to server */
1018 int num_settings, /* I - Number of settings */
1019 cups_option_t *settings) /* I - Settings */
1020 {
1021 int i; /* Looping var */
1022 http_status_t status; /* GET/PUT status */
1023 const char *server_port_env; /* SERVER_PORT env var */
1024 int server_port; /* IPP port for server */
1025 cups_file_t *cupsd; /* cupsd.conf file */
1026 char cupsdconf[1024]; /* cupsd.conf filename */
1027 int remote; /* Remote cupsd.conf file? */
1028 char tempfile[1024]; /* Temporary new cupsd.conf */
1029 cups_file_t *temp; /* Temporary file */
1030 char line[1024], /* Line from cupsd.conf file */
1031 *value; /* Value on line */
1032 int linenum, /* Line number in file */
1033 in_location, /* In a location section? */
1034 in_policy, /* In a policy section? */
1035 in_default_policy, /* In the default policy section? */
1036 in_cancel_job, /* In a cancel-job section? */
1037 in_admin_location, /* In the /admin location? */
1038 in_conf_location, /* In the /admin/conf location? */
1039 in_root_location; /* In the / location? */
1040 const char *val; /* Setting value */
1041 int remote_printers, /* Show remote printers */
1042 share_printers, /* Share local printers */
1043 remote_admin, /* Remote administration allowed? */
1044 remote_any, /* Remote access from anywhere? */
1045 user_cancel_any, /* Cancel-job policy set? */
1046 debug_logging; /* LogLevel debug set? */
1047 int wrote_port_listen, /* Wrote the port/listen lines? */
1048 wrote_browsing, /* Wrote the browsing lines? */
1049 wrote_policy, /* Wrote the policy? */
1050 wrote_loglevel, /* Wrote the LogLevel line? */
1051 wrote_admin_location, /* Wrote the /admin location? */
1052 wrote_conf_location, /* Wrote the /admin/conf location? */
1053 wrote_root_location; /* Wrote the / location? */
1054 int indent; /* Indentation */
1055 int cupsd_num_settings; /* New number of settings */
1056 int old_remote_printers, /* Show remote printers */
1057 old_share_printers, /* Share local printers */
1058 old_remote_admin, /* Remote administration allowed? */
1059 old_user_cancel_any, /* Cancel-job policy set? */
1060 old_debug_logging; /* LogLevel debug set? */
1061 cups_option_t *cupsd_settings, /* New settings */
1062 *setting; /* Current setting */
1063 _cups_globals_t *cg = _cupsGlobals(); /* Global data */
1064
1065
1066 /*
1067 * Range check input...
1068 */
1069
1070 if (!http || !num_settings || !settings)
1071 {
1072 _cupsSetError(IPP_INTERNAL_ERROR, NULL);
1073
1074 return (0);
1075 }
1076
1077 /*
1078 * Get the cupsd.conf file...
1079 */
1080
1081 if ((status = get_cupsd_conf(http, cg, 0, cupsdconf, sizeof(cupsdconf),
1082 &remote)) == HTTP_OK)
1083 {
1084 if ((cupsd = cupsFileOpen(cupsdconf, "r")) == NULL)
1085 {
1086 _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno));
1087 return (0);
1088 }
1089 }
1090 else
1091 return (0);
1092
1093 /*
1094 * Get current settings...
1095 */
1096
1097 if (!_cupsAdminGetServerSettings(http, &cupsd_num_settings,
1098 &cupsd_settings))
1099 return (0);
1100
1101 if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, cupsd_num_settings,
1102 cupsd_settings)) != NULL)
1103 old_debug_logging = atoi(val);
1104 else
1105 old_debug_logging = 0;
1106
1107 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, cupsd_num_settings,
1108 cupsd_settings)) != NULL)
1109 old_remote_admin = atoi(val);
1110 else
1111 old_remote_admin = 0;
1112
1113 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, cupsd_num_settings,
1114 cupsd_settings)) != NULL)
1115 remote_any = atoi(val);
1116 else
1117 remote_any = 0;
1118
1119 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS, cupsd_num_settings,
1120 cupsd_settings)) != NULL)
1121 old_remote_printers = atoi(val);
1122 else
1123 old_remote_printers = 1;
1124
1125 if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, cupsd_num_settings,
1126 cupsd_settings)) != NULL)
1127 old_share_printers = atoi(val);
1128 else
1129 old_share_printers = 0;
1130
1131 if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, cupsd_num_settings,
1132 cupsd_settings)) != NULL)
1133 old_user_cancel_any = atoi(val);
1134 else
1135 old_user_cancel_any = 0;
1136
1137 cupsFreeOptions(cupsd_num_settings, cupsd_settings);
1138
1139 /*
1140 * Get basic settings...
1141 */
1142
1143 if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, num_settings,
1144 settings)) != NULL)
1145 {
1146 debug_logging = atoi(val);
1147
1148 if (debug_logging == old_debug_logging)
1149 {
1150 /*
1151 * No change to this setting...
1152 */
1153
1154 debug_logging = -1;
1155 }
1156 }
1157 else
1158 debug_logging = -1;
1159
1160 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, num_settings,
1161 settings)) != NULL)
1162 remote_any = atoi(val);
1163
1164 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, num_settings,
1165 settings)) != NULL)
1166 {
1167 remote_admin = atoi(val);
1168
1169 if (remote_admin == old_remote_admin && remote_any < 0)
1170 {
1171 /*
1172 * No change to this setting...
1173 */
1174
1175 remote_admin = -1;
1176 }
1177 }
1178 else
1179 remote_admin = -1;
1180
1181 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS, num_settings,
1182 settings)) != NULL)
1183 {
1184 remote_printers = atoi(val);
1185
1186 if (remote_printers == old_remote_printers)
1187 {
1188 /*
1189 * No change to this setting...
1190 */
1191
1192 remote_printers = -1;
1193 }
1194 }
1195 else
1196 remote_printers = -1;
1197
1198 if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, num_settings,
1199 settings)) != NULL)
1200 {
1201 share_printers = atoi(val);
1202
1203 if (share_printers == old_share_printers && remote_any < 0)
1204 {
1205 /*
1206 * No change to this setting...
1207 */
1208
1209 share_printers = -1;
1210 }
1211 }
1212 else
1213 share_printers = -1;
1214
1215 if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, num_settings,
1216 settings)) != NULL)
1217 {
1218 user_cancel_any = atoi(val);
1219
1220 if (user_cancel_any == old_user_cancel_any)
1221 {
1222 /*
1223 * No change to this setting...
1224 */
1225
1226 user_cancel_any = -1;
1227 }
1228 }
1229 else
1230 user_cancel_any = -1;
1231
1232 /*
1233 * Create a temporary file for the new cupsd.conf file...
1234 */
1235
1236 if ((temp = cupsTempFile2(tempfile, sizeof(tempfile))) == NULL)
1237 {
1238 cupsFileClose(cupsd);
1239
1240 if (remote)
1241 unlink(cupsdconf);
1242
1243 _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno));
1244 return (0);
1245 }
1246
1247 /*
1248 * Copy the old file to the new, making changes along the way...
1249 */
1250
1251 cupsd_num_settings = 0;
1252 in_admin_location = 0;
1253 in_cancel_job = 0;
1254 in_conf_location = 0;
1255 in_default_policy = 0;
1256 in_location = 0;
1257 in_policy = 0;
1258 in_root_location = 0;
1259 linenum = 0;
1260 wrote_admin_location = 0;
1261 wrote_browsing = 0;
1262 wrote_conf_location = 0;
1263 wrote_loglevel = 0;
1264 wrote_policy = 0;
1265 wrote_port_listen = 0;
1266 wrote_root_location = 0;
1267 indent = 0;
1268
1269 if ((server_port_env = getenv("SERVER_PORT")) != NULL)
1270 {
1271 if ((server_port = atoi(server_port_env)) <= 0)
1272 server_port = ippPort();
1273 }
1274 else
1275 server_port = ippPort();
1276
1277 if (server_port <= 0)
1278 server_port = IPP_PORT;
1279
1280 while (cupsFileGetConf(cupsd, line, sizeof(line), &value, &linenum))
1281 {
1282 if ((!strcasecmp(line, "Port") || !strcasecmp(line, "Listen")) &&
1283 (share_printers >= 0 || remote_admin >= 0))
1284 {
1285 if (!wrote_port_listen)
1286 {
1287 wrote_port_listen = 1;
1288
1289 if (share_printers > 0 || remote_admin > 0)
1290 {
1291 cupsFilePuts(temp, "# Allow remote access\n");
1292 cupsFilePrintf(temp, "Port %d\n", server_port);
1293 }
1294 else
1295 {
1296 cupsFilePuts(temp, "# Only listen for connections from the local "
1297 "machine.\n");
1298 cupsFilePrintf(temp, "Listen localhost:%d\n", server_port);
1299 }
1300
1301 #ifdef CUPS_DEFAULT_DOMAINSOCKET
1302 if ((!value || strcmp(CUPS_DEFAULT_DOMAINSOCKET, value)) &&
1303 !access(CUPS_DEFAULT_DOMAINSOCKET, 0))
1304 cupsFilePuts(temp, "Listen " CUPS_DEFAULT_DOMAINSOCKET "\n");
1305 #endif /* CUPS_DEFAULT_DOMAINSOCKET */
1306 }
1307 else if (value && value[0] == '/'
1308 #ifdef CUPS_DEFAULT_DOMAINSOCKET
1309 && strcmp(CUPS_DEFAULT_DOMAINSOCKET, value)
1310 #endif /* CUPS_DEFAULT_DOMAINSOCKET */
1311 )
1312 cupsFilePrintf(temp, "Listen %s\n", value);
1313 }
1314 else if ((!strcasecmp(line, "Browsing") ||
1315 !strcasecmp(line, "BrowseAddress") ||
1316 !strcasecmp(line, "BrowseAllow") ||
1317 !strcasecmp(line, "BrowseDeny") ||
1318 !strcasecmp(line, "BrowseOrder")) &&
1319 (remote_printers >= 0 || share_printers >= 0))
1320 {
1321 if (!wrote_browsing)
1322 {
1323 wrote_browsing = 1;
1324
1325 if (remote_printers > 0 || share_printers > 0)
1326 {
1327 if (remote_printers > 0 && share_printers > 0)
1328 cupsFilePuts(temp,
1329 "# Enable printer sharing and shared printers.\n");
1330 else if (remote_printers > 0)
1331 cupsFilePuts(temp,
1332 "# Show shared printers on the local network.\n");
1333 else
1334 cupsFilePuts(temp,
1335 "# Share local printers on the local network.\n");
1336
1337 cupsFilePuts(temp, "Browsing On\n");
1338 cupsFilePuts(temp, "BrowseOrder allow,deny\n");
1339
1340 if (remote_printers > 0)
1341 cupsFilePuts(temp, "BrowseAllow all\n");
1342
1343 if (share_printers > 0)
1344 cupsFilePuts(temp, "BrowseAddress @LOCAL\n");
1345 }
1346 else
1347 {
1348 cupsFilePuts(temp,
1349 "# Disable printer sharing and shared printers.\n");
1350 cupsFilePuts(temp, "Browsing Off\n");
1351 }
1352 }
1353 }
1354 else if (!strcasecmp(line, "LogLevel") && debug_logging >= 0)
1355 {
1356 wrote_loglevel = 1;
1357
1358 if (debug_logging)
1359 {
1360 cupsFilePuts(temp,
1361 "# Show troubleshooting information in error_log.\n");
1362 cupsFilePuts(temp, "LogLevel debug\n");
1363 }
1364 else
1365 {
1366 cupsFilePuts(temp, "# Show general information in error_log.\n");
1367 cupsFilePuts(temp, "LogLevel info\n");
1368 }
1369 }
1370 else if (!strcasecmp(line, "<Policy"))
1371 {
1372 in_default_policy = !strcasecmp(value, "default");
1373 in_policy = 1;
1374
1375 cupsFilePrintf(temp, "%s %s>\n", line, value);
1376 indent += 2;
1377 }
1378 else if (!strcasecmp(line, "</Policy>"))
1379 {
1380 indent -= 2;
1381 if (!wrote_policy && in_default_policy)
1382 {
1383 wrote_policy = 1;
1384
1385 if (!user_cancel_any)
1386 cupsFilePuts(temp, " # Only the owner or an administrator can "
1387 "cancel a job...\n"
1388 " <Limit Cancel-Job>\n"
1389 " Order deny,allow\n"
1390 " Allow @SYSTEM\n"
1391 " Allow @OWNER\n"
1392 " </Limit>\n");
1393 }
1394
1395 in_policy = 0;
1396 in_default_policy = 0;
1397
1398 cupsFilePuts(temp, "</Policy>\n");
1399 }
1400 else if (!strcasecmp(line, "<Location"))
1401 {
1402 in_location = 1;
1403 indent += 2;
1404 if (!strcmp(value, "/admin"))
1405 in_admin_location = 1;
1406 if (!strcmp(value, "/admin/conf"))
1407 in_conf_location = 1;
1408 else if (!strcmp(value, "/"))
1409 in_root_location = 1;
1410
1411 cupsFilePrintf(temp, "%s %s>\n", line, value);
1412 }
1413 else if (!strcasecmp(line, "</Location>"))
1414 {
1415 in_location = 0;
1416 indent -= 2;
1417 if (in_admin_location && remote_admin >= 0)
1418 {
1419 wrote_admin_location = 1;
1420
1421 if (remote_admin)
1422 cupsFilePuts(temp, " # Allow remote administration...\n");
1423 else if (remote_admin == 0)
1424 cupsFilePuts(temp, " # Restrict access to the admin pages...\n");
1425
1426 cupsFilePuts(temp, " Order allow,deny\n");
1427
1428 if (remote_admin)
1429 cupsFilePrintf(temp, " Allow %s\n",
1430 remote_any > 0 ? "all" : "@LOCAL");
1431 else
1432 cupsFilePuts(temp, " Allow localhost\n");
1433 }
1434 else if (in_conf_location && remote_admin >= 0)
1435 {
1436 wrote_conf_location = 1;
1437
1438 if (remote_admin)
1439 cupsFilePuts(temp, " # Allow remote access to the configuration "
1440 "files...\n");
1441 else
1442 cupsFilePuts(temp, " # Restrict access to the configuration "
1443 "files...\n");
1444
1445 cupsFilePuts(temp, " Order allow,deny\n");
1446
1447 if (remote_admin)
1448 cupsFilePrintf(temp, " Allow %s\n",
1449 remote_any > 0 ? "all" : "@LOCAL");
1450 else
1451 cupsFilePuts(temp, " Allow localhost\n");
1452 }
1453 else if (in_root_location && (remote_admin >= 0 || share_printers >= 0))
1454 {
1455 wrote_root_location = 1;
1456
1457 if (remote_admin > 0 && share_printers > 0)
1458 cupsFilePuts(temp, " # Allow shared printing and remote "
1459 "administration...\n");
1460 else if (remote_admin > 0)
1461 cupsFilePuts(temp, " # Allow remote administration...\n");
1462 else if (share_printers > 0)
1463 cupsFilePuts(temp, " # Allow shared printing...\n");
1464 else
1465 cupsFilePuts(temp, " # Restrict access to the server...\n");
1466
1467 cupsFilePuts(temp, " Order allow,deny\n");
1468
1469 if (remote_admin > 0 || share_printers > 0)
1470 cupsFilePrintf(temp, " Allow %s\n",
1471 remote_any > 0 ? "all" : "@LOCAL");
1472 else
1473 cupsFilePuts(temp, " Allow localhost\n");
1474 }
1475
1476 in_admin_location = 0;
1477 in_conf_location = 0;
1478 in_root_location = 0;
1479
1480 cupsFilePuts(temp, "</Location>\n");
1481 }
1482 else if (!strcasecmp(line, "<Limit") && in_default_policy)
1483 {
1484 /*
1485 * See if the policy limit is for the Cancel-Job operation...
1486 */
1487
1488 char *valptr; /* Pointer into value */
1489
1490
1491 indent += 2;
1492
1493 if (!strcasecmp(value, "cancel-job") && user_cancel_any >= 0)
1494 {
1495 /*
1496 * Don't write anything for this limit section...
1497 */
1498
1499 in_cancel_job = 2;
1500 }
1501 else
1502 {
1503 cupsFilePrintf(temp, " %s", line);
1504
1505 while (*value)
1506 {
1507 for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++);
1508
1509 if (*valptr)
1510 *valptr++ = '\0';
1511
1512 if (!strcasecmp(value, "cancel-job") && user_cancel_any >= 0)
1513 {
1514 /*
1515 * Write everything except for this definition...
1516 */
1517
1518 in_cancel_job = 1;
1519 }
1520 else
1521 cupsFilePrintf(temp, " %s", value);
1522
1523 for (value = valptr; isspace(*value & 255); value ++);
1524 }
1525
1526 cupsFilePuts(temp, ">\n");
1527 }
1528 }
1529 else if (!strcasecmp(line, "</Limit>") && in_cancel_job)
1530 {
1531 indent -= 2;
1532
1533 if (in_cancel_job == 1)
1534 cupsFilePuts(temp, " </Limit>\n");
1535
1536 wrote_policy = 1;
1537
1538 if (!user_cancel_any)
1539 cupsFilePuts(temp, " # Only the owner or an administrator can cancel "
1540 "a job...\n"
1541 " <Limit Cancel-Job>\n"
1542 " Order deny,allow\n"
1543 " Require user @OWNER @SYSTEM\n"
1544 " </Limit>\n");
1545
1546 in_cancel_job = 0;
1547 }
1548 else if ((((in_admin_location || in_conf_location || in_root_location) &&
1549 remote_admin >= 0) ||
1550 (in_root_location && share_printers >= 0)) &&
1551 (!strcasecmp(line, "Allow") || !strcasecmp(line, "Deny") ||
1552 !strcasecmp(line, "Order")))
1553 continue;
1554 else if (in_cancel_job == 2)
1555 continue;
1556 else if (!strcasecmp(line, "<Limit") && value)
1557 cupsFilePrintf(temp, " %s %s>\n", line, value);
1558 else if (line[0] == '<')
1559 {
1560 if (value)
1561 {
1562 cupsFilePrintf(temp, "%*s%s %s>\n", indent, "", line, value);
1563 indent += 2;
1564 }
1565 else
1566 {
1567 if (line[1] == '/')
1568 indent -= 2;
1569
1570 cupsFilePrintf(temp, "%*s%s\n", indent, "", line);
1571 }
1572 }
1573 else if (!in_policy && !in_location &&
1574 (val = cupsGetOption(line, num_settings, settings)) != NULL)
1575 {
1576 /*
1577 * Replace this directive's value with the new one...
1578 */
1579
1580 cupsd_num_settings = cupsAddOption(line, val, cupsd_num_settings,
1581 &cupsd_settings);
1582
1583 /*
1584 * Write the new value in its place, without indentation since we
1585 * only support setting root directives, not in sections...
1586 */
1587
1588 cupsFilePrintf(temp, "%s %s\n", line, val);
1589 }
1590 else if (value)
1591 {
1592 if (!in_policy && !in_location)
1593 {
1594 /*
1595 * Record the non-policy, non-location directives that we find
1596 * in the server settings, since we cache this info and record it
1597 * in _cupsAdminGetServerSettings()...
1598 */
1599
1600 cupsd_num_settings = cupsAddOption(line, value, cupsd_num_settings,
1601 &cupsd_settings);
1602 }
1603
1604 cupsFilePrintf(temp, "%*s%s %s\n", indent, "", line, value);
1605 }
1606 else
1607 cupsFilePrintf(temp, "%*s%s\n", indent, "", line);
1608 }
1609
1610 /*
1611 * Write any missing info...
1612 */
1613
1614 if (!wrote_browsing && (remote_printers >= 0 || share_printers >= 0))
1615 {
1616 if (remote_printers > 0 || share_printers > 0)
1617 {
1618 if (remote_printers > 0 && share_printers > 0)
1619 cupsFilePuts(temp, "# Enable printer sharing and shared printers.\n");
1620 else if (remote_printers > 0)
1621 cupsFilePuts(temp, "# Show shared printers on the local network.\n");
1622 else
1623 cupsFilePuts(temp, "# Share local printers on the local network.\n");
1624
1625 cupsFilePuts(temp, "Browsing On\n");
1626 cupsFilePuts(temp, "BrowseOrder allow,deny\n");
1627
1628 if (remote_printers > 0)
1629 cupsFilePuts(temp, "BrowseAllow all\n");
1630
1631 if (share_printers > 0)
1632 cupsFilePuts(temp, "BrowseAddress @LOCAL\n");
1633 }
1634 else
1635 {
1636 cupsFilePuts(temp, "# Disable printer sharing and shared printers.\n");
1637 cupsFilePuts(temp, "Browsing Off\n");
1638 }
1639 }
1640
1641 if (!wrote_loglevel && debug_logging >= 0)
1642 {
1643 if (debug_logging)
1644 {
1645 cupsFilePuts(temp, "# Show troubleshooting information in error_log.\n");
1646 cupsFilePuts(temp, "LogLevel debug\n");
1647 }
1648 else
1649 {
1650 cupsFilePuts(temp, "# Show general information in error_log.\n");
1651 cupsFilePuts(temp, "LogLevel info\n");
1652 }
1653 }
1654
1655 if (!wrote_port_listen && (share_printers >= 0 || remote_admin >= 0))
1656 {
1657 if (share_printers > 0 || remote_admin > 0)
1658 {
1659 cupsFilePuts(temp, "# Allow remote access\n");
1660 cupsFilePrintf(temp, "Port %d\n", ippPort());
1661 }
1662 else
1663 {
1664 cupsFilePuts(temp,
1665 "# Only listen for connections from the local machine.\n");
1666 cupsFilePrintf(temp, "Listen localhost:%d\n", ippPort());
1667 }
1668
1669 #ifdef CUPS_DEFAULT_DOMAINSOCKET
1670 if (!access(CUPS_DEFAULT_DOMAINSOCKET, 0))
1671 cupsFilePuts(temp, "Listen " CUPS_DEFAULT_DOMAINSOCKET "\n");
1672 #endif /* CUPS_DEFAULT_DOMAINSOCKET */
1673 }
1674
1675 if (!wrote_root_location && (remote_admin >= 0 || share_printers >= 0))
1676 {
1677 if (remote_admin > 0 && share_printers > 0)
1678 cupsFilePuts(temp,
1679 "# Allow shared printing and remote administration...\n");
1680 else if (remote_admin > 0)
1681 cupsFilePuts(temp, "# Allow remote administration...\n");
1682 else if (share_printers > 0)
1683 cupsFilePuts(temp, "# Allow shared printing...\n");
1684 else
1685 cupsFilePuts(temp, "# Restrict access to the server...\n");
1686
1687 cupsFilePuts(temp, "<Location />\n"
1688 " Order allow,deny\n");
1689
1690 if (remote_admin > 0 || share_printers > 0)
1691 cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL");
1692 else
1693 cupsFilePuts(temp, " Allow localhost\n");
1694
1695 cupsFilePuts(temp, "</Location>\n");
1696 }
1697
1698 if (!wrote_admin_location && remote_admin >= 0)
1699 {
1700 if (remote_admin)
1701 cupsFilePuts(temp, "# Allow remote administration...\n");
1702 else
1703 cupsFilePuts(temp, "# Restrict access to the admin pages...\n");
1704
1705 cupsFilePuts(temp, "<Location /admin>\n"
1706 " Order allow,deny\n");
1707
1708 if (remote_admin)
1709 cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL");
1710 else
1711 cupsFilePuts(temp, " Allow localhost\n");
1712
1713 cupsFilePuts(temp, "</Location>\n");
1714 }
1715
1716 if (!wrote_conf_location && remote_admin >= 0)
1717 {
1718 if (remote_admin)
1719 cupsFilePuts(temp,
1720 "# Allow remote access to the configuration files...\n");
1721 else
1722 cupsFilePuts(temp, "# Restrict access to the configuration files...\n");
1723
1724 cupsFilePuts(temp, "<Location /admin/conf>\n"
1725 " AuthType Basic\n"
1726 " Require user @SYSTEM\n"
1727 " Order allow,deny\n");
1728
1729 if (remote_admin)
1730 cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL");
1731 else
1732 cupsFilePuts(temp, " Allow localhost\n");
1733
1734 cupsFilePuts(temp, "</Location>\n");
1735 }
1736
1737 if (!wrote_policy && user_cancel_any >= 0)
1738 {
1739 cupsFilePuts(temp, "<Policy default>\n"
1740 " # Job-related operations must be done by the owner "
1741 "or an adminstrator...\n"
1742 " <Limit Send-Document Send-URI Hold-Job Release-Job "
1743 "Restart-Job Purge-Jobs Set-Job-Attributes "
1744 "Create-Job-Subscription Renew-Subscription "
1745 "Cancel-Subscription Get-Notifications Reprocess-Job "
1746 "Cancel-Current-Job Suspend-Current-Job Resume-Job "
1747 "CUPS-Move-Job>\n"
1748 " Require user @OWNER @SYSTEM\n"
1749 " Order deny,allow\n"
1750 " </Limit>\n"
1751 " # All administration operations require an "
1752 "adminstrator to authenticate...\n"
1753 " <Limit Pause-Printer Resume-Printer "
1754 "Set-Printer-Attributes Enable-Printer "
1755 "Disable-Printer Pause-Printer-After-Current-Job "
1756 "Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer "
1757 "Activate-Printer Restart-Printer Shutdown-Printer "
1758 "Startup-Printer Promote-Job Schedule-Job-After "
1759 "CUPS-Add-Printer CUPS-Delete-Printer "
1760 "CUPS-Add-Class CUPS-Delete-Class "
1761 "CUPS-Accept-Jobs CUPS-Reject-Jobs "
1762 "CUPS-Set-Default CUPS-Add-Device CUPS-Delete-Device>\n"
1763 " AuthType Basic\n"
1764 " Require user @SYSTEM\n"
1765 " Order deny,allow\n"
1766 "</Limit>\n");
1767
1768 if (!user_cancel_any)
1769 cupsFilePuts(temp, " # Only the owner or an administrator can cancel "
1770 "a job...\n"
1771 " <Limit Cancel-Job>\n"
1772 " Require user @OWNER @SYSTEM\n"
1773 " Order deny,allow\n"
1774 " </Limit>\n");
1775
1776 cupsFilePuts(temp, " <Limit All>\n"
1777 " Order deny,allow\n"
1778 " </Limit>\n"
1779 "</Policy>\n");
1780 }
1781
1782 for (i = num_settings, setting = settings; i > 0; i --, setting ++)
1783 if (setting->name[0] != '_' &&
1784 !cupsGetOption(setting->name, cupsd_num_settings, cupsd_settings))
1785 {
1786 /*
1787 * Add this directive to the list of directives we have written...
1788 */
1789
1790 cupsd_num_settings = cupsAddOption(setting->name, setting->value,
1791 cupsd_num_settings, &cupsd_settings);
1792
1793 /*
1794 * Write the new value, without indentation since we only support
1795 * setting root directives, not in sections...
1796 */
1797
1798 cupsFilePrintf(temp, "%s %s\n", setting->name, setting->value);
1799 }
1800
1801 cupsFileClose(cupsd);
1802 cupsFileClose(temp);
1803
1804 /*
1805 * Upload the configuration file to the server...
1806 */
1807
1808 status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile);
1809
1810 if (status == HTTP_CREATED)
1811 {
1812 /*
1813 * Updated OK, add the basic settings...
1814 */
1815
1816 if (debug_logging >= 0)
1817 cupsd_num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING,
1818 debug_logging ? "1" : "0",
1819 cupsd_num_settings, &cupsd_settings);
1820 else
1821 cupsd_num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING,
1822 old_debug_logging ? "1" : "0",
1823 cupsd_num_settings, &cupsd_settings);
1824
1825 if (remote_admin >= 0)
1826 cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN,
1827 remote_admin ? "1" : "0",
1828 cupsd_num_settings, &cupsd_settings);
1829 else
1830 cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN,
1831 old_remote_admin ? "1" : "0",
1832 cupsd_num_settings, &cupsd_settings);
1833
1834 cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY,
1835 remote_any ? "1" : "0",
1836 cupsd_num_settings, &cupsd_settings);
1837
1838 if (remote_printers >= 0)
1839 cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS,
1840 remote_printers ? "1" : "0",
1841 cupsd_num_settings, &cupsd_settings);
1842 else
1843 cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS,
1844 old_remote_printers ? "1" : "0",
1845 cupsd_num_settings, &cupsd_settings);
1846
1847 if (share_printers >= 0)
1848 cupsd_num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS,
1849 share_printers ? "1" : "0",
1850 cupsd_num_settings, &cupsd_settings);
1851 else
1852 cupsd_num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS,
1853 old_share_printers ? "1" : "0",
1854 cupsd_num_settings, &cupsd_settings);
1855
1856 if (user_cancel_any >= 0)
1857 cupsd_num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY,
1858 user_cancel_any ? "1" : "0",
1859 cupsd_num_settings, &cupsd_settings);
1860 else
1861 cupsd_num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY,
1862 old_user_cancel_any ? "1" : "0",
1863 cupsd_num_settings, &cupsd_settings);
1864
1865 /*
1866 * Save the new values...
1867 */
1868
1869 invalidate_cupsd_cache(cg);
1870
1871 cg->cupsd_num_settings = cupsd_num_settings;
1872 cg->cupsd_settings = cupsd_settings;
1873 cg->cupsd_update = time(NULL);
1874
1875 httpGetHostname(http, cg->cupsd_hostname, sizeof(cg->cupsd_hostname));
1876 }
1877 else
1878 cupsFreeOptions(cupsd_num_settings, cupsd_settings);
1879
1880 /*
1881 * Remote our temp files and return...
1882 */
1883
1884 if (remote)
1885 unlink(cupsdconf);
1886
1887 unlink(tempfile);
1888
1889 return (status == HTTP_CREATED);
1890 }
1891
1892
1893 /*
1894 * 'do_samba_command()' - Do a SAMBA command.
1895 */
1896
1897 static int /* O - Status of command */
1898 do_samba_command(const char *command, /* I - Command to run */
1899 const char *address, /* I - Address for command */
1900 const char *subcmd, /* I - Sub-command */
1901 const char *authfile, /* I - Samba authentication file */
1902 FILE *logfile) /* I - Optional log file */
1903 {
1904 #ifdef WIN32
1905 return (1); /* Always fail on Windows... */
1906
1907 #else
1908 int status; /* Status of command */
1909 int pid; /* Process ID of child */
1910
1911
1912 if (logfile)
1913 _cupsLangPrintf(logfile,
1914 _("Running command: %s %s -N -A %s -c \'%s\'\n"),
1915 command, address, authfile, subcmd);
1916
1917 if ((pid = fork()) == 0)
1918 {
1919 /*
1920 * Child goes here, redirect stdin/out/err and execute the command...
1921 */
1922
1923 close(0);
1924 open("/dev/null", O_RDONLY);
1925
1926 close(1);
1927
1928 if (logfile)
1929 dup(fileno(logfile));
1930 else
1931 open("/dev/null", O_WRONLY);
1932
1933 close(2);
1934 dup(1);
1935
1936 execlp(command, command, address, "-N", "-A", authfile, "-c", subcmd,
1937 (char *)0);
1938 exit(errno);
1939 }
1940 else if (pid < 0)
1941 {
1942 status = -1;
1943
1944 if (logfile)
1945 _cupsLangPrintf(logfile, _("Unable to run \"%s\": %s\n"),
1946 command, strerror(errno));
1947 }
1948 else
1949 {
1950 /*
1951 * Wait for the process to complete...
1952 */
1953
1954 while (wait(&status) != pid);
1955 }
1956
1957 if (logfile)
1958 _cupsLangPuts(logfile, "\n");
1959
1960 DEBUG_printf(("status=%d\n", status));
1961
1962 if (WIFEXITED(status))
1963 return (WEXITSTATUS(status));
1964 else
1965 return (-WTERMSIG(status));
1966 #endif /* WIN32 */
1967 }
1968
1969
1970 /*
1971 * 'get_cupsd_conf()' - Get the current cupsd.conf file.
1972 */
1973
1974 static http_status_t /* O - Status of request */
1975 get_cupsd_conf(
1976 http_t *http, /* I - Connection to server */
1977 _cups_globals_t *cg, /* I - Global data */
1978 time_t last_update, /* I - Last update time for file */
1979 char *name, /* I - Filename buffer */
1980 int namesize, /* I - Size of filename buffer */
1981 int *remote) /* O - Remote file? */
1982 {
1983 int fd; /* Temporary file descriptor */
1984 #ifndef WIN32
1985 struct stat info; /* cupsd.conf file information */
1986 #endif /* WIN32 */
1987 http_status_t status; /* Status of getting cupsd.conf */
1988 char host[HTTP_MAX_HOST]; /* Hostname for connection */
1989
1990
1991 /*
1992 * See if we already have the data we need...
1993 */
1994
1995 httpGetHostname(http, host, sizeof(host));
1996
1997 if (strcasecmp(cg->cupsd_hostname, host))
1998 invalidate_cupsd_cache(cg);
1999
2000 snprintf(name, namesize, "%s/cupsd.conf", cg->cups_serverroot);
2001 *remote = 0;
2002
2003 #ifndef WIN32
2004 if (!strcasecmp(host, "localhost") && !access(name, R_OK))
2005 {
2006 /*
2007 * Read the local file rather than using HTTP...
2008 */
2009
2010 if (stat(name, &info))
2011 {
2012 char message[1024]; /* Message string */
2013
2014
2015 snprintf(message, sizeof(message),
2016 _cupsLangString(cupsLangDefault(), _("stat of %s failed: %s")),
2017 name, strerror(errno));
2018 _cupsSetError(IPP_INTERNAL_ERROR, message);
2019
2020 *name = '\0';
2021
2022 return (HTTP_SERVER_ERROR);
2023 }
2024 else if (last_update && info.st_mtime <= last_update)
2025 status = HTTP_NOT_MODIFIED;
2026 else
2027 status = HTTP_OK;
2028 }
2029 else
2030 #endif /* !WIN32 */
2031 {
2032 /*
2033 * Read cupsd.conf via a HTTP GET request...
2034 */
2035
2036 if ((fd = cupsTempFd(name, namesize)) < 0)
2037 {
2038 *name = '\0';
2039
2040 _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno));
2041
2042 invalidate_cupsd_cache(cg);
2043
2044 return (HTTP_SERVER_ERROR);
2045 }
2046
2047 *remote = 1;
2048
2049 httpClearFields(http);
2050
2051 if (last_update)
2052 httpSetField(http, HTTP_FIELD_IF_MODIFIED_SINCE,
2053 httpGetDateString(last_update));
2054
2055 status = cupsGetFd(http, "/admin/conf/cupsd.conf", fd);
2056
2057 close(fd);
2058
2059 if (status != HTTP_OK)
2060 {
2061 unlink(name);
2062 *name = '\0';
2063 }
2064 }
2065
2066 return (status);
2067 }
2068
2069
2070 /*
2071 * 'invalidate_cupsd_cache()' - Invalidate the cached cupsd.conf settings.
2072 */
2073
2074 static void
2075 invalidate_cupsd_cache(
2076 _cups_globals_t *cg) /* I - Global data */
2077 {
2078 cupsFreeOptions(cg->cupsd_num_settings, cg->cupsd_settings);
2079
2080 cg->cupsd_hostname[0] = '\0';
2081 cg->cupsd_update = 0;
2082 cg->cupsd_num_settings = 0;
2083 cg->cupsd_settings = NULL;
2084 }
2085
2086
2087 /*
2088 * 'write_option()' - Write a CUPS option to a PPD file.
2089 */
2090
2091 static void
2092 write_option(cups_file_t *dstfp, /* I - PPD file */
2093 int order, /* I - Order dependency */
2094 const char *name, /* I - Option name */
2095 const char *text, /* I - Option text */
2096 const char *attrname, /* I - Attribute name */
2097 ipp_attribute_t *suppattr, /* I - IPP -supported attribute */
2098 ipp_attribute_t *defattr, /* I - IPP -default attribute */
2099 int defval, /* I - Default value number */
2100 int valcount) /* I - Number of values */
2101 {
2102 int i; /* Looping var */
2103
2104
2105 cupsFilePrintf(dstfp, "*JCLOpenUI *%s/%s: PickOne\n"
2106 "*OrderDependency: %d JCLSetup *%s\n",
2107 name, text, order, name);
2108
2109 if (defattr->value_tag == IPP_TAG_INTEGER)
2110 {
2111 /*
2112 * Do numeric options with a range or list...
2113 */
2114
2115 cupsFilePrintf(dstfp, "*Default%s: %d\n", name,
2116 defattr->values[defval].integer);
2117
2118 if (suppattr->value_tag == IPP_TAG_RANGE)
2119 {
2120 /*
2121 * List each number in the range...
2122 */
2123
2124 for (i = suppattr->values[0].range.lower;
2125 i <= suppattr->values[0].range.upper;
2126 i ++)
2127 {
2128 cupsFilePrintf(dstfp, "*%s %d: \"", name, i);
2129
2130 if (valcount == 1)
2131 cupsFilePrintf(dstfp, "%%cupsJobTicket: %s=%d\n\"\n*End\n",
2132 attrname, i);
2133 else if (defval == 0)
2134 cupsFilePrintf(dstfp, "%%cupsJobTicket: %s=%d\"\n", attrname, i);
2135 else if (defval < (valcount - 1))
2136 cupsFilePrintf(dstfp, ",%d\"\n", i);
2137 else
2138 cupsFilePrintf(dstfp, ",%d\n\"\n*End\n", i);
2139 }
2140 }
2141 else
2142 {
2143 /*
2144 * List explicit numbers...
2145 */
2146
2147 for (i = 0; i < suppattr->num_values; i ++)
2148 {
2149 cupsFilePrintf(dstfp, "*%s %d: \"", name, suppattr->values[i].integer);
2150
2151 if (valcount == 1)
2152 cupsFilePrintf(dstfp, "%%cupsJobTicket: %s=%d\n\"\n*End\n", attrname,
2153 suppattr->values[i].integer);
2154 else if (defval == 0)
2155 cupsFilePrintf(dstfp, "%%cupsJobTicket: %s=%d\"\n", attrname,
2156 suppattr->values[i].integer);
2157 else if (defval < (valcount - 1))
2158 cupsFilePrintf(dstfp, ",%d\"\n", suppattr->values[i].integer);
2159 else
2160 cupsFilePrintf(dstfp, ",%d\n\"\n*End\n", suppattr->values[i].integer);
2161 }
2162 }
2163 }
2164 else
2165 {
2166 /*
2167 * Do text options with a list...
2168 */
2169
2170 cupsFilePrintf(dstfp, "*Default%s: %s\n", name,
2171 defattr->values[defval].string.text);
2172
2173 for (i = 0; i < suppattr->num_values; i ++)
2174 {
2175 cupsFilePrintf(dstfp, "*%s %s: \"", name,
2176 suppattr->values[i].string.text);
2177
2178 if (valcount == 1)
2179 cupsFilePrintf(dstfp, "%%cupsJobTicket: %s=%s\n\"\n*End\n", attrname,
2180 suppattr->values[i].string.text);
2181 else if (defval == 0)
2182 cupsFilePrintf(dstfp, "%%cupsJobTicket: %s=%s\"\n", attrname,
2183 suppattr->values[i].string.text);
2184 else if (defval < (valcount - 1))
2185 cupsFilePrintf(dstfp, ",%s\"\n", suppattr->values[i].string.text);
2186 else
2187 cupsFilePrintf(dstfp, ",%s\n\"\n*End\n",
2188 suppattr->values[i].string.text);
2189 }
2190 }
2191
2192 cupsFilePrintf(dstfp, "*JCLCloseUI: *%s\n\n", name);
2193 }
2194
2195
2196 /*
2197 * End of "$Id: adminutil.c 6378 2007-03-21 07:18:18Z mike $".
2198 */