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