Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
srohatgi01
GitHub Repository: srohatgi01/cups
Path: blob/master/cgi-bin/admin.c
1090 views
1
/*
2
* Administration CGI for CUPS.
3
*
4
* Copyright © 2021-2022 by OpenPrinting
5
* Copyright © 2007-2021 by Apple Inc.
6
* Copyright © 1997-2007 by Easy Software Products.
7
*
8
* Licensed under Apache License v2.0. See the file "LICENSE" for more
9
* information.
10
*/
11
12
/*
13
* Include necessary headers...
14
*/
15
16
#include "cgi-private.h"
17
#include <cups/http-private.h>
18
#include <cups/ppd-private.h>
19
#include <cups/adminutil.h>
20
#include <cups/ppd.h>
21
#include <errno.h>
22
#include <unistd.h>
23
#include <fcntl.h>
24
#include <sys/wait.h>
25
#include <limits.h>
26
27
28
/*
29
* Local globals...
30
*/
31
32
static int current_device = 0; /* Current device shown */
33
34
35
/*
36
* Local functions...
37
*/
38
39
static void choose_device_cb(const char *device_class, const char *device_id, const char *device_info, const char *device_make_and_model, const char *device_uri, const char *device_location, const char *title);
40
static void do_am_class(http_t *http, int modify);
41
static void do_am_printer(http_t *http, int modify);
42
static void do_config_server(http_t *http);
43
static void do_delete_class(http_t *http);
44
static void do_delete_printer(http_t *http);
45
static void do_list_printers(http_t *http);
46
static void do_menu(http_t *http);
47
static void do_set_allowed_users(http_t *http);
48
static void do_set_default(http_t *http);
49
static void do_set_options(http_t *http, int is_class);
50
static void do_set_sharing(http_t *http);
51
static char *get_option_value(ppd_file_t *ppd, const char *name,
52
char *buffer, size_t bufsize);
53
static double get_points(double number, const char *uval);
54
55
56
/*
57
* 'main()' - Main entry for CGI.
58
*/
59
60
int /* O - Exit status */
61
main(void)
62
{
63
http_t *http; /* Connection to the server */
64
const char *op; /* Operation name */
65
66
67
/*
68
* Connect to the HTTP server...
69
*/
70
71
fputs("DEBUG: admin.cgi started...\n", stderr);
72
73
http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
74
75
if (!http)
76
{
77
perror("ERROR: Unable to connect to cupsd");
78
fprintf(stderr, "DEBUG: cupsServer()=\"%s\"\n",
79
cupsServer() ? cupsServer() : "(null)");
80
fprintf(stderr, "DEBUG: ippPort()=%d\n", ippPort());
81
fprintf(stderr, "DEBUG: cupsEncryption()=%d\n", cupsEncryption());
82
exit(1);
83
}
84
85
fprintf(stderr, "DEBUG: http=%p\n", http);
86
87
/*
88
* Set the web interface section...
89
*/
90
91
cgiSetVariable("SECTION", "admin");
92
cgiSetVariable("REFRESH_PAGE", "");
93
94
/*
95
* See if we have form data...
96
*/
97
98
if (!cgiInitialize() || !cgiGetVariable("OP"))
99
{
100
/*
101
* Nope, send the administration menu...
102
*/
103
104
fputs("DEBUG: No form data, showing main menu...\n", stderr);
105
106
do_menu(http);
107
}
108
else if ((op = cgiGetVariable("OP")) != NULL && cgiIsPOST())
109
{
110
/*
111
* Do the operation...
112
*/
113
114
fprintf(stderr, "DEBUG: op=\"%s\"...\n", op);
115
116
if (!*op)
117
{
118
const char *printer = getenv("PRINTER_NAME"),
119
/* Printer or class name */
120
*server_port = getenv("SERVER_PORT");
121
/* Port number string */
122
int port = server_port ? atoi(server_port) : 0;
123
/* Port number */
124
char uri[1024]; /* URL */
125
126
if (printer)
127
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri),
128
getenv("HTTPS") ? "https" : "http", NULL,
129
getenv("SERVER_NAME"), port, "/%s/%s",
130
cgiGetVariable("IS_CLASS") ? "classes" : "printers",
131
printer);
132
else
133
httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri),
134
getenv("HTTPS") ? "https" : "http", NULL,
135
getenv("SERVER_NAME"), port, "/admin");
136
137
printf("Location: %s\n\n", uri);
138
}
139
else if (!strcmp(op, "set-allowed-users"))
140
do_set_allowed_users(http);
141
else if (!strcmp(op, "set-as-default"))
142
do_set_default(http);
143
else if (!strcmp(op, "set-sharing"))
144
do_set_sharing(http);
145
else if (!strcmp(op, "find-new-printers") ||
146
!strcmp(op, "list-available-printers"))
147
do_list_printers(http);
148
else if (!strcmp(op, "add-class"))
149
do_am_class(http, 0);
150
else if (!strcmp(op, "add-printer"))
151
do_am_printer(http, 0);
152
else if (!strcmp(op, "modify-class"))
153
do_am_class(http, 1);
154
else if (!strcmp(op, "modify-printer"))
155
do_am_printer(http, 1);
156
else if (!strcmp(op, "delete-class"))
157
do_delete_class(http);
158
else if (!strcmp(op, "delete-printer"))
159
do_delete_printer(http);
160
else if (!strcmp(op, "set-class-options"))
161
do_set_options(http, 1);
162
else if (!strcmp(op, "set-printer-options"))
163
do_set_options(http, 0);
164
else if (!strcmp(op, "config-server"))
165
do_config_server(http);
166
else
167
{
168
/*
169
* Bad operation code - display an error...
170
*/
171
172
cgiStartHTML(cgiText(_("Administration")));
173
cgiCopyTemplateLang("error-op.tmpl");
174
cgiEndHTML();
175
}
176
}
177
else if (op && !strcmp(op, "redirect"))
178
{
179
const char *url; /* Redirection URL... */
180
char prefix[1024]; /* URL prefix */
181
182
183
if (getenv("HTTPS"))
184
snprintf(prefix, sizeof(prefix), "https://%s:%s",
185
getenv("SERVER_NAME"), getenv("SERVER_PORT"));
186
else
187
snprintf(prefix, sizeof(prefix), "http://%s:%s",
188
getenv("SERVER_NAME"), getenv("SERVER_PORT"));
189
190
fprintf(stderr, "DEBUG: redirecting with prefix %s!\n", prefix);
191
192
if ((url = cgiGetVariable("URL")) != NULL)
193
{
194
char encoded[1024], /* Encoded URL string */
195
*ptr; /* Pointer into encoded string */
196
197
198
ptr = encoded;
199
if (*url != '/')
200
*ptr++ = '/';
201
202
for (; *url && ptr < (encoded + sizeof(encoded) - 4); url ++)
203
{
204
if (strchr("%@&+ <>#=", *url) || *url < ' ' || *url & 128)
205
{
206
/*
207
* Percent-encode this character; safe because we have at least 4
208
* bytes left in the array...
209
*/
210
211
snprintf(ptr, sizeof(encoded) - (size_t)(ptr - encoded), "%%%02X", *url & 255);
212
ptr += 3;
213
}
214
else
215
*ptr++ = *url;
216
}
217
218
*ptr = '\0';
219
220
if (*url)
221
{
222
/*
223
* URL was too long, just redirect to the admin page...
224
*/
225
226
printf("Location: %s/admin\n\n", prefix);
227
}
228
else
229
{
230
/*
231
* URL is OK, redirect there...
232
*/
233
234
printf("Location: %s%s\n\n", prefix, encoded);
235
}
236
}
237
else
238
printf("Location: %s/admin\n\n", prefix);
239
}
240
else
241
{
242
/*
243
* Form data but no operation code - display an error...
244
*/
245
246
cgiStartHTML(cgiText(_("Administration")));
247
cgiCopyTemplateLang("error-op.tmpl");
248
cgiEndHTML();
249
}
250
251
/*
252
* Close the HTTP server connection...
253
*/
254
255
httpClose(http);
256
257
/*
258
* Return with no errors...
259
*/
260
261
return (0);
262
}
263
264
265
/*
266
* 'choose_device_cb()' - Add a device to the device selection page.
267
*/
268
269
static void
270
choose_device_cb(
271
const char *device_class, /* I - Class */
272
const char *device_id, /* I - 1284 device ID */
273
const char *device_info, /* I - Description */
274
const char *device_make_and_model, /* I - Make and model */
275
const char *device_uri, /* I - Device URI */
276
const char *device_location, /* I - Location */
277
const char *title) /* I - Page title */
278
{
279
/*
280
* For modern browsers, start a multi-part page so we can show that something
281
* is happening. Non-modern browsers just get everything at the end...
282
*/
283
284
if (current_device == 0 && cgiSupportsMultipart())
285
{
286
cgiStartMultipart();
287
cgiStartHTML(title);
288
cgiCopyTemplateLang("choose-device.tmpl");
289
cgiEndHTML();
290
fflush(stdout);
291
}
292
293
294
/*
295
* Add the device to the array...
296
*/
297
298
cgiSetArray("device_class", current_device, device_class);
299
cgiSetArray("device_id", current_device, device_id);
300
cgiSetArray("device_info", current_device, device_info);
301
cgiSetArray("device_make_and_model", current_device, device_make_and_model);
302
cgiSetArray("device_uri", current_device, device_uri);
303
cgiSetArray("device_location", current_device, device_location);
304
305
current_device ++;
306
}
307
308
309
/*
310
* 'do_am_class()' - Add or modify a class.
311
*/
312
313
static void
314
do_am_class(http_t *http, /* I - HTTP connection */
315
int modify) /* I - Modify the printer? */
316
{
317
int i, j; /* Looping vars */
318
int element; /* Element number */
319
int num_printers; /* Number of printers */
320
ipp_t *request, /* IPP request */
321
*response; /* IPP response */
322
ipp_attribute_t *attr; /* member-uris attribute */
323
char uri[HTTP_MAX_URI]; /* Device or printer URI */
324
const char *name, /* Pointer to class name */
325
*op, /* Operation name */
326
*ptr; /* Pointer to CGI variable */
327
const char *title; /* Title of page */
328
static const char * const pattrs[] = /* Requested printer attributes */
329
{
330
"member-names",
331
"printer-info",
332
"printer-location"
333
};
334
335
336
title = cgiText(modify ? _("Modify Class") : _("Add Class"));
337
op = cgiGetVariable("OP");
338
name = cgiGetVariable("PRINTER_NAME");
339
340
if (cgiGetVariable("PRINTER_LOCATION") == NULL)
341
{
342
/*
343
* Build a CUPS_GET_PRINTERS request, which requires the
344
* following attributes:
345
*
346
* attributes-charset
347
* attributes-natural-language
348
*/
349
350
request = ippNewRequest(CUPS_GET_PRINTERS);
351
352
ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type",
353
CUPS_PRINTER_LOCAL);
354
ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type-mask",
355
CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE);
356
357
/*
358
* Do the request and get back a response...
359
*/
360
361
cgiClearVariables();
362
if (op)
363
cgiSetVariable("OP", op);
364
if (name)
365
cgiSetVariable("PRINTER_NAME", name);
366
367
if ((response = cupsDoRequest(http, request, "/")) != NULL)
368
{
369
/*
370
* Create MEMBER_URIS and MEMBER_NAMES arrays...
371
*/
372
373
for (element = 0, attr = response->attrs;
374
attr != NULL;
375
attr = attr->next)
376
if (attr->name && !strcmp(attr->name, "printer-uri-supported"))
377
{
378
if ((ptr = strrchr(attr->values[0].string.text, '/')) != NULL &&
379
(!name || _cups_strcasecmp(name, ptr + 1)))
380
{
381
/*
382
* Don't show the current class...
383
*/
384
385
cgiSetArray("MEMBER_URIS", element, attr->values[0].string.text);
386
element ++;
387
}
388
}
389
390
for (element = 0, attr = response->attrs;
391
attr != NULL;
392
attr = attr->next)
393
if (attr->name && !strcmp(attr->name, "printer-name"))
394
{
395
if (!name || _cups_strcasecmp(name, attr->values[0].string.text))
396
{
397
/*
398
* Don't show the current class...
399
*/
400
401
cgiSetArray("MEMBER_NAMES", element, attr->values[0].string.text);
402
element ++;
403
}
404
}
405
406
num_printers = cgiGetSize("MEMBER_URIS");
407
408
ippDelete(response);
409
}
410
else
411
num_printers = 0;
412
413
if (modify)
414
{
415
/*
416
* Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
417
* following attributes:
418
*
419
* attributes-charset
420
* attributes-natural-language
421
* printer-uri
422
*/
423
424
request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
425
426
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
427
"localhost", 0, "/classes/%s", name);
428
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
429
NULL, uri);
430
431
ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
432
"requested-attributes",
433
(int)(sizeof(pattrs) / sizeof(pattrs[0])),
434
NULL, pattrs);
435
436
/*
437
* Do the request and get back a response...
438
*/
439
440
if ((response = cupsDoRequest(http, request, "/")) != NULL)
441
{
442
if ((attr = ippFindAttribute(response, "member-names",
443
IPP_TAG_NAME)) != NULL)
444
{
445
/*
446
* Mark any current members in the class...
447
*/
448
449
for (j = 0; j < num_printers; j ++)
450
cgiSetArray("MEMBER_SELECTED", j, "");
451
452
for (i = 0; i < attr->num_values; i ++)
453
{
454
for (j = 0; j < num_printers; j ++)
455
{
456
if (!_cups_strcasecmp(attr->values[i].string.text,
457
cgiGetArray("MEMBER_NAMES", j)))
458
{
459
cgiSetArray("MEMBER_SELECTED", j, "SELECTED");
460
break;
461
}
462
}
463
}
464
}
465
466
if ((attr = ippFindAttribute(response, "printer-info",
467
IPP_TAG_TEXT)) != NULL)
468
cgiSetVariable("PRINTER_INFO", attr->values[0].string.text);
469
470
if ((attr = ippFindAttribute(response, "printer-location",
471
IPP_TAG_TEXT)) != NULL)
472
cgiSetVariable("PRINTER_LOCATION", attr->values[0].string.text);
473
474
ippDelete(response);
475
}
476
477
/*
478
* Update the location and description of an existing printer...
479
*/
480
481
cgiStartHTML(title);
482
cgiCopyTemplateLang("modify-class.tmpl");
483
}
484
else
485
{
486
/*
487
* Get the name, location, and description for a new printer...
488
*/
489
490
cgiStartHTML(title);
491
cgiCopyTemplateLang("add-class.tmpl");
492
}
493
494
cgiEndHTML();
495
496
return;
497
}
498
499
if (!name)
500
{
501
cgiStartHTML(title);
502
cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
503
cgiCopyTemplateLang("error.tmpl");
504
cgiEndHTML();
505
return;
506
}
507
508
for (ptr = name; *ptr; ptr ++)
509
if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#')
510
break;
511
512
if (*ptr || ptr == name || strlen(name) > 127)
513
{
514
cgiSetVariable("ERROR",
515
cgiText(_("The class name may only contain up to "
516
"127 printable characters and may not "
517
"contain spaces, slashes (/), or the "
518
"pound sign (#).")));
519
cgiStartHTML(title);
520
cgiCopyTemplateLang("error.tmpl");
521
cgiEndHTML();
522
return;
523
}
524
525
/*
526
* Build a CUPS_ADD_CLASS request, which requires the following
527
* attributes:
528
*
529
* attributes-charset
530
* attributes-natural-language
531
* printer-uri
532
* printer-location
533
* printer-info
534
* printer-is-accepting-jobs
535
* printer-state
536
* member-uris
537
*/
538
539
request = ippNewRequest(CUPS_ADD_CLASS);
540
541
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
542
"localhost", 0, "/classes/%s", name);
543
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
544
NULL, uri);
545
546
ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
547
NULL, cgiGetVariable("PRINTER_LOCATION"));
548
549
ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
550
NULL, cgiGetVariable("PRINTER_INFO"));
551
552
ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
553
554
ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
555
IPP_PRINTER_IDLE);
556
557
if ((num_printers = cgiGetSize("MEMBER_URIS")) > 0)
558
{
559
attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI, "member-uris",
560
num_printers, NULL, NULL);
561
for (i = 0; i < num_printers; i ++)
562
ippSetString(request, &attr, i, cgiGetArray("MEMBER_URIS", i));
563
}
564
565
/*
566
* Do the request and get back a response...
567
*/
568
569
ippDelete(cupsDoRequest(http, request, "/admin/"));
570
571
if (cupsLastError() == IPP_NOT_AUTHORIZED)
572
{
573
puts("Status: 401\n");
574
exit(0);
575
}
576
else if (cupsLastError() > IPP_OK_CONFLICT)
577
{
578
cgiStartHTML(title);
579
cgiShowIPPError(modify ? _("Unable to modify class") :
580
_("Unable to add class"));
581
}
582
else
583
{
584
/*
585
* Redirect successful updates back to the class page...
586
*/
587
588
char refresh[1024]; /* Refresh URL */
589
590
cgiFormEncode(uri, name, sizeof(uri));
591
snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=/classes/%s",
592
uri);
593
cgiSetVariable("refresh_page", refresh);
594
595
cgiStartHTML(title);
596
597
if (modify)
598
cgiCopyTemplateLang("class-modified.tmpl");
599
else
600
cgiCopyTemplateLang("class-added.tmpl");
601
}
602
603
cgiEndHTML();
604
}
605
606
607
/*
608
* 'do_am_printer()' - Add or modify a printer.
609
*/
610
611
static void
612
do_am_printer(http_t *http, /* I - HTTP connection */
613
int modify) /* I - Modify the printer? */
614
{
615
int i; /* Looping var */
616
ipp_attribute_t *attr; /* Current attribute */
617
ipp_t *request, /* IPP request */
618
*response, /* IPP response */
619
*oldinfo; /* Old printer information */
620
const cgi_file_t *file; /* Uploaded file, if any */
621
const char *var; /* CGI variable */
622
char *ppd_name = NULL; /* Pointer to PPD name */
623
char uri[HTTP_MAX_URI], /* Device or printer URI */
624
*uriptr, /* Pointer into URI */
625
evefile[1024] = ""; /* IPP Everywhere PPD file */
626
int maxrate; /* Maximum baud rate */
627
char baudrate[255]; /* Baud rate string */
628
const char *name, /* Pointer to class name */
629
*ptr; /* Pointer to CGI variable */
630
const char *title; /* Title of page */
631
static int baudrates[] = /* Baud rates */
632
{
633
1200,
634
2400,
635
4800,
636
9600,
637
19200,
638
38400,
639
57600,
640
115200,
641
230400,
642
460800
643
};
644
645
646
ptr = cgiGetVariable("DEVICE_URI");
647
fprintf(stderr, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
648
ptr ? ptr : "(null)");
649
650
title = cgiText(modify ? _("Modify Printer") : _("Add Printer"));
651
652
if (modify)
653
{
654
/*
655
* Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
656
* following attributes:
657
*
658
* attributes-charset
659
* attributes-natural-language
660
* printer-uri
661
*/
662
663
request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
664
665
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
666
"localhost", 0, "/printers/%s",
667
cgiGetVariable("PRINTER_NAME"));
668
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
669
NULL, uri);
670
671
/*
672
* Do the request and get back a response...
673
*/
674
675
oldinfo = cupsDoRequest(http, request, "/");
676
}
677
else
678
oldinfo = NULL;
679
680
file = cgiGetFile();
681
682
if (file)
683
{
684
fprintf(stderr, "DEBUG: file->tempfile=%s\n", file->tempfile);
685
fprintf(stderr, "DEBUG: file->name=%s\n", file->name);
686
fprintf(stderr, "DEBUG: file->filename=%s\n", file->filename);
687
fprintf(stderr, "DEBUG: file->mimetype=%s\n", file->mimetype);
688
}
689
690
if ((name = cgiGetVariable("PRINTER_NAME")) != NULL)
691
{
692
for (ptr = name; *ptr; ptr ++)
693
if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '\\' || *ptr == '?' || *ptr == '\'' || *ptr == '\"' || *ptr == '#')
694
break;
695
696
if (*ptr || ptr == name || strlen(name) > 127)
697
{
698
cgiSetVariable("ERROR",
699
cgiText(_("The printer name may only contain up to 127 printable characters and may not contain spaces, slashes (/ \\), quotes (' \"), question mark (?), or the pound sign (#).")));
700
cgiStartHTML(title);
701
cgiCopyTemplateLang("error.tmpl");
702
cgiEndHTML();
703
return;
704
}
705
}
706
707
if ((var = cgiGetVariable("DEVICE_URI")) != NULL)
708
{
709
if ((uriptr = strrchr(var, '|')) != NULL)
710
{
711
/*
712
* Extract make and make/model from device URI string...
713
*/
714
715
char make[1024], /* Make string */
716
*makeptr; /* Pointer into make */
717
718
719
*uriptr++ = '\0';
720
721
strlcpy(make, uriptr, sizeof(make));
722
723
if ((makeptr = strchr(make, ' ')) != NULL)
724
*makeptr = '\0';
725
else if ((makeptr = strchr(make, '-')) != NULL)
726
*makeptr = '\0';
727
else if (!_cups_strncasecmp(make, "laserjet", 8) ||
728
!_cups_strncasecmp(make, "deskjet", 7) ||
729
!_cups_strncasecmp(make, "designjet", 9))
730
strlcpy(make, "HP", sizeof(make));
731
else if (!_cups_strncasecmp(make, "phaser", 6))
732
strlcpy(make, "Xerox", sizeof(make));
733
else if (!_cups_strncasecmp(make, "stylus", 6))
734
strlcpy(make, "Epson", sizeof(make));
735
else
736
strlcpy(make, "Generic", sizeof(make));
737
738
if (!cgiGetVariable("CURRENT_MAKE"))
739
cgiSetVariable("CURRENT_MAKE", make);
740
741
if (!cgiGetVariable("CURRENT_MAKE_AND_MODEL"))
742
cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr);
743
744
if (!modify)
745
{
746
char template[128], /* Template name */
747
*tptr; /* Pointer into template name */
748
749
cgiSetVariable("PRINTER_INFO", uriptr);
750
751
for (tptr = template;
752
tptr < (template + sizeof(template) - 1) && *uriptr;
753
uriptr ++)
754
if (isalnum(*uriptr & 255) || *uriptr == '_' || *uriptr == '-' ||
755
*uriptr == '.')
756
*tptr++ = *uriptr;
757
else if ((*uriptr == ' ' || *uriptr == '/') && tptr > template &&
758
tptr[-1] != '_')
759
*tptr++ = '_';
760
else if (*uriptr == '?' || *uriptr == '(')
761
break;
762
763
*tptr = '\0';
764
765
cgiSetVariable("TEMPLATE_NAME", template);
766
}
767
768
/*
769
* Set DEVICE_URI to the actual device uri, without make and model from
770
* html form.
771
*/
772
773
cgiSetVariable("DEVICE_URI", var);
774
}
775
}
776
777
if (!var)
778
{
779
/*
780
* Look for devices so the user can pick something...
781
*/
782
783
if ((attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL)
784
{
785
strlcpy(uri, attr->values[0].string.text, sizeof(uri));
786
if ((uriptr = strchr(uri, ':')) != NULL && strncmp(uriptr, "://", 3) == 0)
787
*uriptr = '\0';
788
789
cgiSetVariable("CURRENT_DEVICE_URI", attr->values[0].string.text);
790
cgiSetVariable("CURRENT_DEVICE_SCHEME", uri);
791
}
792
793
/*
794
* Scan for devices for up to 30 seconds...
795
*/
796
797
fputs("DEBUG: Getting list of devices...\n", stderr);
798
799
current_device = 0;
800
if (cupsGetDevices(http, 5, CUPS_INCLUDE_ALL, CUPS_EXCLUDE_NONE,
801
(cups_device_cb_t)choose_device_cb,
802
(void *)title) == IPP_OK)
803
{
804
fputs("DEBUG: Got device list!\n", stderr);
805
806
if (cgiSupportsMultipart())
807
cgiStartMultipart();
808
809
cgiSetVariable("CUPS_GET_DEVICES_DONE", "1");
810
cgiStartHTML(title);
811
cgiCopyTemplateLang("choose-device.tmpl");
812
cgiEndHTML();
813
814
if (cgiSupportsMultipart())
815
cgiEndMultipart();
816
}
817
else
818
{
819
fprintf(stderr,
820
"ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
821
cupsLastError(), cupsLastErrorString());
822
if (cupsLastError() == IPP_NOT_AUTHORIZED)
823
{
824
puts("Status: 401\n");
825
exit(0);
826
}
827
else
828
{
829
cgiStartHTML(title);
830
cgiShowIPPError(modify ? _("Unable to modify printer") :
831
_("Unable to add printer"));
832
cgiEndHTML();
833
return;
834
}
835
}
836
}
837
else if (!strchr(var, '/') ||
838
(!strncmp(var, "lpd://", 6) && !strchr(var + 6, '/')))
839
{
840
if ((attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL)
841
{
842
/*
843
* Set the current device URI for the form to the old one...
844
*/
845
846
if (strncmp(attr->values[0].string.text, var, strlen(var)) == 0)
847
cgiSetVariable("CURRENT_DEVICE_URI", attr->values[0].string.text);
848
}
849
850
/*
851
* User needs to set the full URI...
852
*/
853
854
cgiStartHTML(title);
855
cgiCopyTemplateLang("choose-uri.tmpl");
856
cgiEndHTML();
857
}
858
else if (!strncmp(var, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
859
{
860
/*
861
* Need baud rate, parity, etc.
862
*/
863
864
if ((var = strchr(var, '?')) != NULL &&
865
strncmp(var, "?baud=", 6) == 0)
866
maxrate = atoi(var + 6);
867
else
868
maxrate = 19200;
869
870
for (i = 0; i < (int)(sizeof(baudrates)/sizeof(baudrates[0])); i ++)
871
if (baudrates[i] > maxrate)
872
break;
873
else
874
{
875
snprintf(baudrate, sizeof(baudrate), "%d", baudrates[i]);
876
cgiSetArray("BAUDRATES", i, baudrate);
877
}
878
879
cgiStartHTML(title);
880
cgiCopyTemplateLang("choose-serial.tmpl");
881
cgiEndHTML();
882
}
883
else if (!name || !cgiGetVariable("PRINTER_LOCATION"))
884
{
885
cgiStartHTML(title);
886
887
if (modify)
888
{
889
/*
890
* Update the location and description of an existing printer...
891
*/
892
893
if (oldinfo)
894
{
895
if ((attr = ippFindAttribute(oldinfo, "printer-info",
896
IPP_TAG_TEXT)) != NULL)
897
cgiSetVariable("PRINTER_INFO", attr->values[0].string.text);
898
899
if ((attr = ippFindAttribute(oldinfo, "printer-location",
900
IPP_TAG_TEXT)) != NULL)
901
cgiSetVariable("PRINTER_LOCATION", attr->values[0].string.text);
902
903
if ((attr = ippFindAttribute(oldinfo, "printer-is-shared",
904
IPP_TAG_BOOLEAN)) != NULL)
905
cgiSetVariable("PRINTER_IS_SHARED",
906
attr->values[0].boolean ? "1" : "0");
907
}
908
909
cgiCopyTemplateLang("modify-printer.tmpl");
910
}
911
else
912
{
913
/*
914
* Get the name, location, and description for a new printer...
915
*/
916
917
#ifdef __APPLE__
918
if (!strncmp(var, "usb:", 4))
919
cgiSetVariable("printer_is_shared", "1");
920
else
921
#endif /* __APPLE__ */
922
cgiSetVariable("printer_is_shared", "0");
923
924
cgiCopyTemplateLang("add-printer.tmpl");
925
}
926
927
cgiEndHTML();
928
929
if (oldinfo)
930
ippDelete(oldinfo);
931
932
return;
933
}
934
else if (!file &&
935
(!cgiGetVariable("PPD_NAME") || cgiGetVariable("SELECT_MAKE")))
936
{
937
int ipp_everywhere = !strncmp(var, "ipp://", 6) || !strncmp(var, "ipps://", 7) || (!strncmp(var, "dnssd://", 8) && (strstr(var, "_ipp._tcp") || strstr(var, "_ipps._tcp")));
938
939
if (modify && !cgiGetVariable("SELECT_MAKE"))
940
{
941
/*
942
* Get the PPD file...
943
*/
944
945
int fd; /* PPD file */
946
char filename[1024]; /* PPD filename */
947
ppd_file_t *ppd; /* PPD information */
948
char buffer[1024]; /* Buffer */
949
ssize_t bytes; /* Number of bytes */
950
http_status_t get_status; /* Status of GET */
951
952
953
/* TODO: Use cupsGetFile() API... */
954
snprintf(uri, sizeof(uri), "/printers/%s.ppd", name);
955
956
if (httpGet(http, uri))
957
httpGet(http, uri);
958
959
while ((get_status = httpUpdate(http)) == HTTP_CONTINUE);
960
961
if (get_status != HTTP_OK)
962
{
963
httpFlush(http);
964
965
fprintf(stderr, "ERROR: Unable to get PPD file %s: %d - %s\n",
966
uri, get_status, httpStatus(get_status));
967
}
968
else if ((fd = cupsTempFd(filename, sizeof(filename))) >= 0)
969
{
970
while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0)
971
write(fd, buffer, (size_t)bytes);
972
973
close(fd);
974
975
if ((ppd = ppdOpenFile(filename)) != NULL)
976
{
977
if (ppd->manufacturer)
978
cgiSetVariable("CURRENT_MAKE", ppd->manufacturer);
979
980
if (ppd->nickname)
981
cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd->nickname);
982
983
ppdClose(ppd);
984
unlink(filename);
985
}
986
else
987
{
988
int linenum; /* Line number */
989
990
fprintf(stderr, "ERROR: Unable to open PPD file %s: %s\n",
991
filename, ppdErrorString(ppdLastError(&linenum)));
992
}
993
}
994
else
995
{
996
httpFlush(http);
997
998
fprintf(stderr,
999
"ERROR: Unable to create temporary file for PPD file: %s\n",
1000
strerror(errno));
1001
}
1002
}
1003
1004
/*
1005
* Build a CUPS_GET_PPDS request, which requires the following
1006
* attributes:
1007
*
1008
* attributes-charset
1009
* attributes-natural-language
1010
* printer-uri
1011
*/
1012
1013
request = ippNewRequest(CUPS_GET_PPDS);
1014
1015
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1016
NULL, "ipp://localhost/printers/");
1017
1018
if ((var = cgiGetVariable("PPD_MAKE")) == NULL)
1019
var = cgiGetVariable("CURRENT_MAKE");
1020
if (var && !cgiGetVariable("SELECT_MAKE"))
1021
{
1022
const char *make_model; /* Make and model */
1023
1024
1025
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT,
1026
"ppd-make", NULL, var);
1027
1028
if ((make_model = cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL)
1029
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT,
1030
"ppd-make-and-model", NULL, make_model);
1031
}
1032
else
1033
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1034
"requested-attributes", NULL, "ppd-make");
1035
1036
/*
1037
* Do the request and get back a response...
1038
*/
1039
1040
if ((response = cupsDoRequest(http, request, "/")) != NULL)
1041
{
1042
/*
1043
* Got the list of PPDs, see if the user has selected a make...
1044
*/
1045
1046
if (cgiSetIPPVars(response, NULL, NULL, NULL, 0) == 0 && !modify)
1047
{
1048
/*
1049
* No PPD files with this make, try again with all makes...
1050
*/
1051
1052
ippDelete(response);
1053
1054
request = ippNewRequest(CUPS_GET_PPDS);
1055
1056
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1057
NULL, "ipp://localhost/printers/");
1058
1059
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1060
"requested-attributes", NULL, "ppd-make");
1061
1062
if ((response = cupsDoRequest(http, request, "/")) != NULL)
1063
cgiSetIPPVars(response, NULL, NULL, NULL, 0);
1064
1065
cgiStartHTML(title);
1066
cgiCopyTemplateLang("choose-make.tmpl");
1067
cgiEndHTML();
1068
}
1069
else if (!var || cgiGetVariable("SELECT_MAKE"))
1070
{
1071
cgiStartHTML(title);
1072
cgiCopyTemplateLang("choose-make.tmpl");
1073
cgiEndHTML();
1074
}
1075
else
1076
{
1077
/*
1078
* Let the user choose a model...
1079
*/
1080
1081
cgiStartHTML(title);
1082
if (!cgiGetVariable("PPD_MAKE"))
1083
cgiSetVariable("PPD_MAKE", cgiGetVariable("CURRENT_MAKE"));
1084
if (ipp_everywhere)
1085
cgiSetVariable("SHOW_IPP_EVERYWHERE", "1");
1086
cgiCopyTemplateLang("choose-model.tmpl");
1087
cgiEndHTML();
1088
}
1089
1090
ippDelete(response);
1091
}
1092
else
1093
{
1094
cgiStartHTML(title);
1095
cgiShowIPPError(_("Unable to get list of printer drivers"));
1096
cgiCopyTemplateLang("error.tmpl");
1097
cgiEndHTML();
1098
}
1099
}
1100
else
1101
{
1102
/*
1103
* Build a CUPS_ADD_PRINTER request, which requires the following
1104
* attributes:
1105
*
1106
* attributes-charset
1107
* attributes-natural-language
1108
* printer-uri
1109
* printer-location
1110
* printer-info
1111
* ppd-name
1112
* device-uri
1113
* printer-is-accepting-jobs
1114
* printer-is-shared
1115
* printer-state
1116
*/
1117
1118
request = ippNewRequest(CUPS_ADD_PRINTER);
1119
1120
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
1121
"localhost", 0, "/printers/%s",
1122
cgiGetVariable("PRINTER_NAME"));
1123
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1124
NULL, uri);
1125
1126
if (!file)
1127
{
1128
ppd_name = cgiGetVariable("PPD_NAME");
1129
if (strcmp(ppd_name, "__no_change__"))
1130
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name",
1131
NULL, ppd_name);
1132
}
1133
1134
ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
1135
NULL, cgiGetVariable("PRINTER_LOCATION"));
1136
1137
ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
1138
NULL, cgiGetVariable("PRINTER_INFO"));
1139
1140
strlcpy(uri, cgiGetVariable("DEVICE_URI"), sizeof(uri));
1141
1142
/*
1143
* Strip make and model from URI...
1144
*/
1145
1146
if ((uriptr = strrchr(uri, '|')) != NULL)
1147
*uriptr = '\0';
1148
1149
if (!strncmp(uri, "serial:", 7))
1150
{
1151
/*
1152
* Update serial port URI to include baud rate, etc.
1153
*/
1154
1155
if ((uriptr = strchr(uri, '?')) == NULL)
1156
uriptr = uri + strlen(uri);
1157
1158
snprintf(uriptr, sizeof(uri) - (size_t)(uriptr - uri),
1159
"?baud=%s+bits=%s+parity=%s+flow=%s",
1160
cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1161
cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1162
}
1163
1164
ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri",
1165
NULL, uri);
1166
1167
ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
1168
1169
var = cgiGetVariable("printer_is_shared");
1170
ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-shared",
1171
var && (!strcmp(var, "1") || !strcmp(var, "on")));
1172
1173
ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
1174
IPP_PRINTER_IDLE);
1175
1176
/*
1177
* Do the request and get back a response...
1178
*/
1179
1180
if (file)
1181
ippDelete(cupsDoFileRequest(http, request, "/admin/", file->tempfile));
1182
else if (evefile[0])
1183
{
1184
ippDelete(cupsDoFileRequest(http, request, "/admin/", evefile));
1185
unlink(evefile);
1186
}
1187
else
1188
ippDelete(cupsDoRequest(http, request, "/admin/"));
1189
1190
if (cupsLastError() == IPP_NOT_AUTHORIZED)
1191
{
1192
puts("Status: 401\n");
1193
exit(0);
1194
}
1195
else if (cupsLastError() > IPP_OK_CONFLICT)
1196
{
1197
cgiStartHTML(title);
1198
cgiShowIPPError(modify ? _("Unable to modify printer") :
1199
_("Unable to add printer"));
1200
}
1201
else if (modify)
1202
{
1203
/*
1204
* Redirect successful updates back to the printer page...
1205
*/
1206
1207
char refresh[1024]; /* Refresh URL */
1208
1209
1210
cgiFormEncode(uri, name, sizeof(uri));
1211
1212
snprintf(refresh, sizeof(refresh),
1213
"5;/admin/?OP=redirect&URL=/printers/%s", uri);
1214
1215
cgiSetVariable("refresh_page", refresh);
1216
1217
cgiStartHTML(title);
1218
1219
cgiCopyTemplateLang("printer-modified.tmpl");
1220
}
1221
else if (ppd_name && (strcmp(ppd_name, "everywhere") == 0 || strstr(ppd_name, "driverless")))
1222
{
1223
/*
1224
* Set the printer options...
1225
*/
1226
1227
cgiSetVariable("OP", "set-printer-options");
1228
do_set_options(http, 0);
1229
return;
1230
}
1231
else
1232
{
1233
/*
1234
* If we don't have an everywhere model, show printer-added
1235
* template with warning about drivers going away...
1236
*/
1237
1238
cgiStartHTML(title);
1239
cgiCopyTemplateLang("printer-added.tmpl");
1240
}
1241
1242
cgiEndHTML();
1243
}
1244
1245
if (oldinfo)
1246
ippDelete(oldinfo);
1247
}
1248
1249
1250
/*
1251
* 'do_config_server()' - Configure server settings.
1252
*/
1253
1254
static void
1255
do_config_server(http_t *http) /* I - HTTP connection */
1256
{
1257
if (cgiGetVariable("CHANGESETTINGS"))
1258
{
1259
/*
1260
* Save basic setting changes...
1261
*/
1262
1263
int num_settings; /* Number of server settings */
1264
cups_option_t *settings; /* Server settings */
1265
int advanced, /* Advanced settings shown? */
1266
changed; /* Have settings changed? */
1267
const char *debug_logging, /* DEBUG_LOGGING value */
1268
*preserve_jobs = NULL,
1269
/* PRESERVE_JOBS value */
1270
*remote_admin, /* REMOTE_ADMIN value */
1271
*remote_any, /* REMOTE_ANY value */
1272
*share_printers,/* SHARE_PRINTERS value */
1273
*user_cancel_any,
1274
/* USER_CANCEL_ANY value */
1275
*browse_web_if = NULL,
1276
/* BrowseWebIF value */
1277
*preserve_job_history = NULL,
1278
/* PreserveJobHistory value */
1279
*preserve_job_files = NULL,
1280
/* PreserveJobFiles value */
1281
*max_clients = NULL,
1282
/* MaxClients value */
1283
*max_jobs = NULL,
1284
/* MaxJobs value */
1285
*max_log_size = NULL;
1286
/* MaxLogSize value */
1287
const char *current_browse_web_if,
1288
/* BrowseWebIF value */
1289
*current_preserve_job_history,
1290
/* PreserveJobHistory value */
1291
*current_preserve_job_files,
1292
/* PreserveJobFiles value */
1293
*current_max_clients,
1294
/* MaxClients value */
1295
*current_max_jobs,
1296
/* MaxJobs value */
1297
*current_max_log_size;
1298
/* MaxLogSize value */
1299
#ifdef HAVE_GSSAPI
1300
char default_auth_type[255];
1301
/* DefaultAuthType value */
1302
const char *val; /* Setting value */
1303
#endif /* HAVE_GSSAPI */
1304
1305
1306
/*
1307
* Get the checkbox values from the form...
1308
*/
1309
1310
debug_logging = cgiGetVariable("DEBUG_LOGGING") ? "1" : "0";
1311
remote_admin = cgiGetVariable("REMOTE_ADMIN") ? "1" : "0";
1312
remote_any = cgiGetVariable("REMOTE_ANY") ? "1" : "0";
1313
share_printers = cgiGetVariable("SHARE_PRINTERS") ? "1" : "0";
1314
user_cancel_any = cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0";
1315
1316
advanced = cgiGetVariable("ADVANCEDSETTINGS") != NULL;
1317
if (advanced)
1318
{
1319
/*
1320
* Get advanced settings...
1321
*/
1322
1323
browse_web_if = cgiGetVariable("BROWSE_WEB_IF") ? "Yes" : "No";
1324
max_clients = cgiGetVariable("MAX_CLIENTS");
1325
max_log_size = cgiGetVariable("MAX_LOG_SIZE");
1326
preserve_jobs = cgiGetVariable("PRESERVE_JOBS");
1327
1328
if (preserve_jobs)
1329
{
1330
max_jobs = cgiGetVariable("MAX_JOBS");
1331
preserve_job_history = cgiGetVariable("PRESERVE_JOB_HISTORY");
1332
preserve_job_files = cgiGetVariable("PRESERVE_JOB_FILES");
1333
1334
if (!max_jobs || atoi(max_jobs) < 0)
1335
max_jobs = "500";
1336
1337
if (!preserve_job_history)
1338
preserve_job_history = "On";
1339
1340
if (!preserve_job_files)
1341
preserve_job_files = "1d";
1342
}
1343
else
1344
{
1345
max_jobs = "0";
1346
preserve_job_history = "No";
1347
preserve_job_files = "No";
1348
}
1349
1350
if (!max_clients || atoi(max_clients) <= 0)
1351
max_clients = "100";
1352
1353
if (!max_log_size || atoi(max_log_size) <= 0.0)
1354
max_log_size = "1m";
1355
}
1356
1357
/*
1358
* Get the current server settings...
1359
*/
1360
1361
if (!cupsAdminGetServerSettings(http, &num_settings, &settings))
1362
{
1363
cgiStartHTML(cgiText(_("Change Settings")));
1364
cgiSetVariable("MESSAGE",
1365
cgiText(_("Unable to change server settings")));
1366
cgiSetVariable("ERROR", cupsLastErrorString());
1367
cgiCopyTemplateLang("error.tmpl");
1368
cgiEndHTML();
1369
return;
1370
}
1371
1372
#ifdef HAVE_GSSAPI
1373
/*
1374
* Get authentication settings...
1375
*/
1376
1377
if (cgiGetVariable("KERBEROS"))
1378
strlcpy(default_auth_type, "Negotiate", sizeof(default_auth_type));
1379
else
1380
{
1381
val = cupsGetOption("DefaultAuthType", num_settings, settings);
1382
1383
if (!val || !_cups_strcasecmp(val, "Negotiate"))
1384
strlcpy(default_auth_type, "Basic", sizeof(default_auth_type));
1385
else
1386
strlcpy(default_auth_type, val, sizeof(default_auth_type));
1387
}
1388
1389
fprintf(stderr, "DEBUG: DefaultAuthType %s\n", default_auth_type);
1390
#endif /* HAVE_GSSAPI */
1391
1392
if ((current_browse_web_if = cupsGetOption("BrowseWebIF", num_settings,
1393
settings)) == NULL)
1394
current_browse_web_if = "No";
1395
1396
if ((current_preserve_job_history = cupsGetOption("PreserveJobHistory",
1397
num_settings,
1398
settings)) == NULL)
1399
current_preserve_job_history = "Yes";
1400
1401
if ((current_preserve_job_files = cupsGetOption("PreserveJobFiles",
1402
num_settings,
1403
settings)) == NULL)
1404
current_preserve_job_files = "1d";
1405
1406
if ((current_max_clients = cupsGetOption("MaxClients", num_settings,
1407
settings)) == NULL)
1408
current_max_clients = "100";
1409
1410
if ((current_max_jobs = cupsGetOption("MaxJobs", num_settings,
1411
settings)) == NULL)
1412
current_max_jobs = "500";
1413
1414
if ((current_max_log_size = cupsGetOption("MaxLogSize", num_settings,
1415
settings)) == NULL)
1416
current_max_log_size = "1m";
1417
1418
/*
1419
* See if the settings have changed...
1420
*/
1421
1422
changed = strcmp(debug_logging, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING,
1423
num_settings, settings)) ||
1424
strcmp(remote_admin, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN,
1425
num_settings, settings)) ||
1426
strcmp(remote_any, cupsGetOption(CUPS_SERVER_REMOTE_ANY,
1427
num_settings, settings)) ||
1428
strcmp(share_printers, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS,
1429
num_settings, settings)) ||
1430
#ifdef HAVE_GSSAPI
1431
!cupsGetOption("DefaultAuthType", num_settings, settings) ||
1432
strcmp(default_auth_type, cupsGetOption("DefaultAuthType",
1433
num_settings, settings)) ||
1434
#endif /* HAVE_GSSAPI */
1435
strcmp(user_cancel_any, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY,
1436
num_settings, settings));
1437
1438
if (advanced && !changed)
1439
changed = _cups_strcasecmp(browse_web_if, current_browse_web_if) ||
1440
_cups_strcasecmp(preserve_job_history, current_preserve_job_history) ||
1441
_cups_strcasecmp(preserve_job_files, current_preserve_job_files) ||
1442
_cups_strcasecmp(max_clients, current_max_clients) ||
1443
_cups_strcasecmp(max_jobs, current_max_jobs) ||
1444
_cups_strcasecmp(max_log_size, current_max_log_size);
1445
1446
if (changed)
1447
{
1448
/*
1449
* Settings *have* changed, so save the changes...
1450
*/
1451
1452
int num_newsettings;/* New number of server settings */
1453
cups_option_t *newsettings; /* New server settings */
1454
1455
num_newsettings = 0;
1456
num_newsettings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING, debug_logging, num_newsettings, &newsettings);
1457
num_newsettings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN, remote_admin, num_newsettings, &newsettings);
1458
num_newsettings = cupsAddOption(CUPS_SERVER_REMOTE_ANY, remote_any, num_newsettings, &newsettings);
1459
num_newsettings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS, share_printers, num_newsettings, &newsettings);
1460
num_newsettings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY, user_cancel_any, num_newsettings, &newsettings);
1461
#ifdef HAVE_GSSAPI
1462
num_newsettings = cupsAddOption("DefaultAuthType", default_auth_type, num_newsettings, &newsettings);
1463
#endif /* HAVE_GSSAPI */
1464
1465
if (advanced)
1466
{
1467
/*
1468
* Add advanced newsettings...
1469
*/
1470
1471
if (_cups_strcasecmp(browse_web_if, current_browse_web_if))
1472
num_newsettings = cupsAddOption("BrowseWebIF", browse_web_if, num_newsettings, &newsettings);
1473
if (_cups_strcasecmp(preserve_job_history, current_preserve_job_history))
1474
num_newsettings = cupsAddOption("PreserveJobHistory", preserve_job_history, num_newsettings, &newsettings);
1475
if (_cups_strcasecmp(preserve_job_files, current_preserve_job_files))
1476
num_newsettings = cupsAddOption("PreserveJobFiles", preserve_job_files, num_newsettings, &newsettings);
1477
if (_cups_strcasecmp(max_clients, current_max_clients))
1478
num_newsettings = cupsAddOption("MaxClients", max_clients, num_newsettings, &newsettings);
1479
if (_cups_strcasecmp(max_jobs, current_max_jobs))
1480
num_newsettings = cupsAddOption("MaxJobs", max_jobs, num_newsettings, &newsettings);
1481
if (_cups_strcasecmp(max_log_size, current_max_log_size))
1482
num_newsettings = cupsAddOption("MaxLogSize", max_log_size, num_newsettings, &newsettings);
1483
}
1484
1485
if (!cupsAdminSetServerSettings(http, num_newsettings, newsettings))
1486
{
1487
if (cupsLastError() == IPP_NOT_AUTHORIZED)
1488
{
1489
puts("Status: 401\n");
1490
exit(0);
1491
}
1492
1493
cgiStartHTML(cgiText(_("Change Settings")));
1494
cgiSetVariable("MESSAGE",
1495
cgiText(_("Unable to change server settings")));
1496
cgiSetVariable("ERROR", cupsLastErrorString());
1497
cgiCopyTemplateLang("error.tmpl");
1498
}
1499
else
1500
{
1501
if (advanced)
1502
cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&"
1503
"URL=/admin/?ADVANCEDSETTINGS=YES");
1504
else
1505
cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1506
cgiStartHTML(cgiText(_("Change Settings")));
1507
cgiCopyTemplateLang("restart.tmpl");
1508
}
1509
1510
cupsFreeOptions(num_newsettings, newsettings);
1511
}
1512
else
1513
{
1514
/*
1515
* No changes...
1516
*/
1517
1518
cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1519
cgiStartHTML(cgiText(_("Change Settings")));
1520
cgiCopyTemplateLang("norestart.tmpl");
1521
}
1522
1523
cupsFreeOptions(num_settings, settings);
1524
1525
cgiEndHTML();
1526
}
1527
else if (cgiGetVariable("SAVECHANGES") && cgiGetVariable("CUPSDCONF"))
1528
{
1529
/*
1530
* Save hand-edited config file...
1531
*/
1532
1533
http_status_t status; /* PUT status */
1534
char tempfile[1024]; /* Temporary new cupsd.conf */
1535
int tempfd; /* Temporary file descriptor */
1536
cups_file_t *temp; /* Temporary file */
1537
const char *start, /* Start of line */
1538
*end; /* End of line */
1539
1540
1541
/*
1542
* Create a temporary file for the new cupsd.conf file...
1543
*/
1544
1545
if ((tempfd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
1546
{
1547
cgiStartHTML(cgiText(_("Edit Configuration File")));
1548
cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file")));
1549
cgiSetVariable("ERROR", strerror(errno));
1550
cgiCopyTemplateLang("error.tmpl");
1551
cgiEndHTML();
1552
1553
perror(tempfile);
1554
return;
1555
}
1556
1557
if ((temp = cupsFileOpenFd(tempfd, "w")) == NULL)
1558
{
1559
cgiStartHTML(cgiText(_("Edit Configuration File")));
1560
cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file")));
1561
cgiSetVariable("ERROR", strerror(errno));
1562
cgiCopyTemplateLang("error.tmpl");
1563
cgiEndHTML();
1564
1565
perror(tempfile);
1566
close(tempfd);
1567
unlink(tempfile);
1568
return;
1569
}
1570
1571
/*
1572
* Copy the cupsd.conf text from the form variable...
1573
*/
1574
1575
start = cgiGetVariable("CUPSDCONF");
1576
while (start)
1577
{
1578
if ((end = strstr(start, "\r\n")) == NULL)
1579
if ((end = strstr(start, "\n")) == NULL)
1580
end = start + strlen(start);
1581
1582
cupsFileWrite(temp, start, (size_t)(end - start));
1583
cupsFilePutChar(temp, '\n');
1584
1585
if (*end == '\r')
1586
start = end + 2;
1587
else if (*end == '\n')
1588
start = end + 1;
1589
else
1590
start = NULL;
1591
}
1592
1593
cupsFileClose(temp);
1594
1595
/*
1596
* Upload the configuration file to the server...
1597
*/
1598
1599
status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile);
1600
1601
if (status == HTTP_UNAUTHORIZED)
1602
{
1603
puts("Status: 401\n");
1604
unlink(tempfile);
1605
exit(0);
1606
}
1607
else if (status != HTTP_CREATED)
1608
{
1609
cgiSetVariable("MESSAGE",
1610
cgiText(_("Unable to upload cupsd.conf file")));
1611
cgiSetVariable("ERROR", httpStatus(status));
1612
1613
cgiStartHTML(cgiText(_("Edit Configuration File")));
1614
cgiCopyTemplateLang("error.tmpl");
1615
}
1616
else
1617
{
1618
cgiSetVariable("refresh_page", "5;URL=/admin/");
1619
1620
cgiStartHTML(cgiText(_("Edit Configuration File")));
1621
cgiCopyTemplateLang("restart.tmpl");
1622
}
1623
1624
cgiEndHTML();
1625
1626
unlink(tempfile);
1627
}
1628
else
1629
{
1630
struct stat info; /* cupsd.conf information */
1631
cups_file_t *cupsd; /* cupsd.conf file */
1632
char *buffer, /* Buffer for entire file */
1633
*bufptr, /* Pointer into buffer */
1634
*bufend; /* End of buffer */
1635
int ch; /* Character from file */
1636
char filename[1024]; /* Filename */
1637
const char *server_root; /* Location of config files */
1638
1639
1640
/*
1641
* Locate the cupsd.conf file...
1642
*/
1643
1644
if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
1645
server_root = CUPS_SERVERROOT;
1646
1647
snprintf(filename, sizeof(filename), "%s/cupsd.conf", server_root);
1648
1649
/*
1650
* Figure out the size...
1651
*/
1652
1653
if (stat(filename, &info))
1654
{
1655
cgiStartHTML(cgiText(_("Edit Configuration File")));
1656
cgiSetVariable("MESSAGE",
1657
cgiText(_("Unable to access cupsd.conf file")));
1658
cgiSetVariable("ERROR", strerror(errno));
1659
cgiCopyTemplateLang("error.tmpl");
1660
cgiEndHTML();
1661
1662
perror(filename);
1663
return;
1664
}
1665
1666
if (info.st_size > (1024 * 1024))
1667
{
1668
cgiStartHTML(cgiText(_("Edit Configuration File")));
1669
cgiSetVariable("MESSAGE",
1670
cgiText(_("Unable to access cupsd.conf file")));
1671
cgiSetVariable("ERROR",
1672
cgiText(_("Unable to edit cupsd.conf files larger than "
1673
"1MB")));
1674
cgiCopyTemplateLang("error.tmpl");
1675
cgiEndHTML();
1676
1677
fprintf(stderr, "ERROR: \"%s\" too large (%ld) to edit!\n", filename,
1678
(long)info.st_size);
1679
return;
1680
}
1681
1682
/*
1683
* Open the cupsd.conf file...
1684
*/
1685
1686
if ((cupsd = cupsFileOpen(filename, "r")) == NULL)
1687
{
1688
/*
1689
* Unable to open - log an error...
1690
*/
1691
1692
cgiStartHTML(cgiText(_("Edit Configuration File")));
1693
cgiSetVariable("MESSAGE",
1694
cgiText(_("Unable to access cupsd.conf file")));
1695
cgiSetVariable("ERROR", strerror(errno));
1696
cgiCopyTemplateLang("error.tmpl");
1697
cgiEndHTML();
1698
1699
perror(filename);
1700
return;
1701
}
1702
1703
/*
1704
* Allocate memory and load the file into a string buffer...
1705
*/
1706
1707
if ((buffer = calloc(1, (size_t)info.st_size + 1)) != NULL)
1708
{
1709
cupsFileRead(cupsd, buffer, (size_t)info.st_size);
1710
cgiSetVariable("CUPSDCONF", buffer);
1711
free(buffer);
1712
}
1713
1714
cupsFileClose(cupsd);
1715
1716
/*
1717
* Then get the default cupsd.conf file and put that into a string as
1718
* well...
1719
*/
1720
1721
strlcat(filename, ".default", sizeof(filename));
1722
1723
if (!stat(filename, &info) && info.st_size < (1024 * 1024) &&
1724
(cupsd = cupsFileOpen(filename, "r")) != NULL)
1725
{
1726
if ((buffer = calloc(1, 2 * (size_t)info.st_size + 1)) != NULL)
1727
{
1728
bufend = buffer + 2 * info.st_size - 1;
1729
1730
for (bufptr = buffer;
1731
bufptr < bufend && (ch = cupsFileGetChar(cupsd)) != EOF;)
1732
{
1733
if (ch == '\\' || ch == '\"')
1734
{
1735
*bufptr++ = '\\';
1736
*bufptr++ = (char)ch;
1737
}
1738
else if (ch == '\n')
1739
{
1740
*bufptr++ = '\\';
1741
*bufptr++ = 'n';
1742
}
1743
else if (ch == '\t')
1744
{
1745
*bufptr++ = '\\';
1746
*bufptr++ = 't';
1747
}
1748
else if (ch >= ' ')
1749
*bufptr++ = (char)ch;
1750
}
1751
1752
*bufptr = '\0';
1753
1754
cgiSetVariable("CUPSDCONF_DEFAULT", buffer);
1755
free(buffer);
1756
}
1757
1758
cupsFileClose(cupsd);
1759
}
1760
1761
/*
1762
* Show the current config file...
1763
*/
1764
1765
cgiStartHTML(cgiText(_("Edit Configuration File")));
1766
1767
cgiCopyTemplateLang("edit-config.tmpl");
1768
1769
cgiEndHTML();
1770
}
1771
}
1772
1773
1774
/*
1775
* 'do_delete_class()' - Delete a class.
1776
*/
1777
1778
static void
1779
do_delete_class(http_t *http) /* I - HTTP connection */
1780
{
1781
ipp_t *request; /* IPP request */
1782
char uri[HTTP_MAX_URI]; /* Job URI */
1783
const char *pclass; /* Printer class name */
1784
1785
1786
/*
1787
* Get form variables...
1788
*/
1789
1790
if (cgiGetVariable("CONFIRM") == NULL)
1791
{
1792
cgiStartHTML(cgiText(_("Delete Class")));
1793
cgiCopyTemplateLang("class-confirm.tmpl");
1794
cgiEndHTML();
1795
return;
1796
}
1797
1798
if ((pclass = cgiGetVariable("PRINTER_NAME")) != NULL)
1799
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
1800
"localhost", 0, "/classes/%s", pclass);
1801
else
1802
{
1803
cgiStartHTML(cgiText(_("Delete Class")));
1804
cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
1805
cgiCopyTemplateLang("error.tmpl");
1806
cgiEndHTML();
1807
return;
1808
}
1809
1810
/*
1811
* Build a CUPS_DELETE_CLASS request, which requires the following
1812
* attributes:
1813
*
1814
* attributes-charset
1815
* attributes-natural-language
1816
* printer-uri
1817
*/
1818
1819
request = ippNewRequest(CUPS_DELETE_CLASS);
1820
1821
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1822
NULL, uri);
1823
1824
/*
1825
* Do the request and get back a response...
1826
*/
1827
1828
ippDelete(cupsDoRequest(http, request, "/admin/"));
1829
1830
/*
1831
* Show the results...
1832
*/
1833
1834
if (cupsLastError() == IPP_NOT_AUTHORIZED)
1835
{
1836
puts("Status: 401\n");
1837
exit(0);
1838
}
1839
else if (cupsLastError() <= IPP_OK_CONFLICT)
1840
{
1841
/*
1842
* Redirect successful updates back to the classes page...
1843
*/
1844
1845
cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
1846
}
1847
1848
cgiStartHTML(cgiText(_("Delete Class")));
1849
1850
if (cupsLastError() > IPP_OK_CONFLICT)
1851
cgiShowIPPError(_("Unable to delete class"));
1852
else
1853
cgiCopyTemplateLang("class-deleted.tmpl");
1854
1855
cgiEndHTML();
1856
}
1857
1858
1859
/*
1860
* 'do_delete_printer()' - Delete a printer.
1861
*/
1862
1863
static void
1864
do_delete_printer(http_t *http) /* I - HTTP connection */
1865
{
1866
ipp_t *request; /* IPP request */
1867
char uri[HTTP_MAX_URI]; /* Job URI */
1868
const char *printer; /* Printer printer name */
1869
1870
1871
/*
1872
* Get form variables...
1873
*/
1874
1875
if (cgiGetVariable("CONFIRM") == NULL)
1876
{
1877
cgiStartHTML(cgiText(_("Delete Printer")));
1878
cgiCopyTemplateLang("printer-confirm.tmpl");
1879
cgiEndHTML();
1880
return;
1881
}
1882
1883
if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
1884
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
1885
"localhost", 0, "/printers/%s", printer);
1886
else
1887
{
1888
cgiStartHTML(cgiText(_("Delete Printer")));
1889
cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
1890
cgiCopyTemplateLang("error.tmpl");
1891
cgiEndHTML();
1892
return;
1893
}
1894
1895
/*
1896
* Build a CUPS_DELETE_PRINTER request, which requires the following
1897
* attributes:
1898
*
1899
* attributes-charset
1900
* attributes-natural-language
1901
* printer-uri
1902
*/
1903
1904
request = ippNewRequest(CUPS_DELETE_PRINTER);
1905
1906
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1907
NULL, uri);
1908
1909
/*
1910
* Do the request and get back a response...
1911
*/
1912
1913
ippDelete(cupsDoRequest(http, request, "/admin/"));
1914
1915
/*
1916
* Show the results...
1917
*/
1918
1919
if (cupsLastError() == IPP_NOT_AUTHORIZED)
1920
{
1921
puts("Status: 401\n");
1922
exit(0);
1923
}
1924
else if (cupsLastError() <= IPP_OK_CONFLICT)
1925
{
1926
/*
1927
* Redirect successful updates back to the printers page...
1928
*/
1929
1930
cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
1931
}
1932
1933
cgiStartHTML(cgiText(_("Delete Printer")));
1934
1935
if (cupsLastError() > IPP_OK_CONFLICT)
1936
cgiShowIPPError(_("Unable to delete printer"));
1937
else
1938
cgiCopyTemplateLang("printer-deleted.tmpl");
1939
1940
cgiEndHTML();
1941
}
1942
1943
1944
/*
1945
* 'do_list_printers()' - List available printers.
1946
*/
1947
1948
static void
1949
do_list_printers(http_t *http) /* I - HTTP connection */
1950
{
1951
ipp_t *request, /* IPP request */
1952
*response; /* IPP response */
1953
ipp_attribute_t *attr; /* IPP attribute */
1954
1955
1956
cgiStartHTML(cgiText(_("List Available Printers")));
1957
fflush(stdout);
1958
1959
/*
1960
* Get the list of printers and their devices...
1961
*/
1962
1963
request = ippNewRequest(CUPS_GET_PRINTERS);
1964
1965
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1966
"requested-attributes", NULL, "device-uri");
1967
1968
ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type",
1969
CUPS_PRINTER_LOCAL);
1970
ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type-mask",
1971
CUPS_PRINTER_LOCAL);
1972
1973
if ((response = cupsDoRequest(http, request, "/")) != NULL)
1974
{
1975
/*
1976
* Got the printer list, now load the devices...
1977
*/
1978
1979
int i; /* Looping var */
1980
cups_array_t *printer_devices; /* Printer devices for local printers */
1981
char *printer_device; /* Current printer device */
1982
1983
1984
/*
1985
* Allocate an array and copy the device strings...
1986
*/
1987
1988
printer_devices = cupsArrayNew((cups_array_func_t)strcmp, NULL);
1989
1990
for (attr = ippFindAttribute(response, "device-uri", IPP_TAG_URI);
1991
attr;
1992
attr = ippFindNextAttribute(response, "device-uri", IPP_TAG_URI))
1993
{
1994
cupsArrayAdd(printer_devices, strdup(attr->values[0].string.text));
1995
}
1996
1997
/*
1998
* Free the printer list and get the device list...
1999
*/
2000
2001
ippDelete(response);
2002
2003
request = ippNewRequest(CUPS_GET_DEVICES);
2004
2005
if ((response = cupsDoRequest(http, request, "/")) != NULL)
2006
{
2007
/*
2008
* Got the device list, let's parse it...
2009
*/
2010
2011
const char *device_uri, /* device-uri attribute value */
2012
*device_make_and_model, /* device-make-and-model value */
2013
*device_info; /* device-info value */
2014
2015
2016
for (i = 0, attr = response->attrs; attr; attr = attr->next)
2017
{
2018
/*
2019
* Skip leading attributes until we hit a device...
2020
*/
2021
2022
while (attr && attr->group_tag != IPP_TAG_PRINTER)
2023
attr = attr->next;
2024
2025
if (!attr)
2026
break;
2027
2028
/*
2029
* Pull the needed attributes from this device...
2030
*/
2031
2032
device_info = NULL;
2033
device_make_and_model = NULL;
2034
device_uri = NULL;
2035
2036
while (attr && attr->group_tag == IPP_TAG_PRINTER)
2037
{
2038
if (!strcmp(attr->name, "device-info") &&
2039
attr->value_tag == IPP_TAG_TEXT)
2040
device_info = attr->values[0].string.text;
2041
2042
if (!strcmp(attr->name, "device-make-and-model") &&
2043
attr->value_tag == IPP_TAG_TEXT)
2044
device_make_and_model = attr->values[0].string.text;
2045
2046
if (!strcmp(attr->name, "device-uri") &&
2047
attr->value_tag == IPP_TAG_URI)
2048
device_uri = attr->values[0].string.text;
2049
2050
attr = attr->next;
2051
}
2052
2053
/*
2054
* See if we have everything needed...
2055
*/
2056
2057
if (device_info && device_make_and_model && device_uri &&
2058
_cups_strcasecmp(device_make_and_model, "unknown") &&
2059
strchr(device_uri, ':'))
2060
{
2061
/*
2062
* Yes, now see if there is already a printer for this
2063
* device...
2064
*/
2065
2066
if (!cupsArrayFind(printer_devices, (void *)device_uri))
2067
{
2068
/*
2069
* Not found, so it must be a new printer...
2070
*/
2071
2072
char option[1024], /* Form variables for this device */
2073
*option_ptr; /* Pointer into string */
2074
const char *ptr; /* Pointer into device string */
2075
2076
2077
/*
2078
* Format the printer name variable for this device...
2079
*
2080
* We use the device-info string first, then device-uri,
2081
* and finally device-make-and-model to come up with a
2082
* suitable name.
2083
*/
2084
2085
if (_cups_strncasecmp(device_info, "unknown", 7))
2086
ptr = device_info;
2087
else if ((ptr = strstr(device_uri, "://")) != NULL)
2088
ptr += 3;
2089
else
2090
ptr = device_make_and_model;
2091
2092
for (option_ptr = option;
2093
option_ptr < (option + sizeof(option) - 1) && *ptr;
2094
ptr ++)
2095
if (isalnum(*ptr & 255) || *ptr == '_' || *ptr == '-' ||
2096
*ptr == '.')
2097
*option_ptr++ = *ptr;
2098
else if ((*ptr == ' ' || *ptr == '/') && option_ptr > option &&
2099
option_ptr[-1] != '_')
2100
*option_ptr++ = '_';
2101
else if (*ptr == '?' || *ptr == '(')
2102
break;
2103
2104
*option_ptr = '\0';
2105
2106
cgiSetArray("TEMPLATE_NAME", i, option);
2107
2108
/*
2109
* Finally, set the form variables for this printer...
2110
*/
2111
2112
cgiSetArray("device_info", i, device_info);
2113
cgiSetArray("device_make_and_model", i, device_make_and_model);
2114
cgiSetArray("device_uri", i, device_uri);
2115
i ++;
2116
}
2117
}
2118
2119
if (!attr)
2120
break;
2121
}
2122
2123
ippDelete(response);
2124
2125
/*
2126
* Free the device list...
2127
*/
2128
2129
for (printer_device = (char *)cupsArrayFirst(printer_devices);
2130
printer_device;
2131
printer_device = (char *)cupsArrayNext(printer_devices))
2132
free(printer_device);
2133
2134
cupsArrayDelete(printer_devices);
2135
}
2136
}
2137
2138
/*
2139
* Finally, show the printer list...
2140
*/
2141
2142
cgiCopyTemplateLang("list-available-printers.tmpl");
2143
2144
cgiEndHTML();
2145
}
2146
2147
2148
/*
2149
* 'do_menu()' - Show the main menu.
2150
*/
2151
2152
static void
2153
do_menu(http_t *http) /* I - HTTP connection */
2154
{
2155
int num_settings; /* Number of server settings */
2156
cups_option_t *settings; /* Server settings */
2157
const char *val; /* Setting value */
2158
2159
2160
/*
2161
* Get the current server settings...
2162
*/
2163
2164
if (!cupsAdminGetServerSettings(http, &num_settings, &settings))
2165
{
2166
cgiSetVariable("SETTINGS_MESSAGE",
2167
cgiText(_("Unable to open cupsd.conf file:")));
2168
cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
2169
}
2170
2171
if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, num_settings,
2172
settings)) != NULL && atoi(val))
2173
cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2174
2175
if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, num_settings,
2176
settings)) != NULL && atoi(val))
2177
cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2178
2179
if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, num_settings,
2180
settings)) != NULL && atoi(val))
2181
cgiSetVariable("REMOTE_ANY", "CHECKED");
2182
2183
if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, num_settings,
2184
settings)) != NULL && atoi(val))
2185
cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2186
2187
if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, num_settings,
2188
settings)) != NULL && atoi(val))
2189
cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2190
2191
#ifdef HAVE_GSSAPI
2192
cgiSetVariable("HAVE_GSSAPI", "1");
2193
2194
if ((val = cupsGetOption("DefaultAuthType", num_settings,
2195
settings)) != NULL && !_cups_strcasecmp(val, "Negotiate"))
2196
cgiSetVariable("KERBEROS", "CHECKED");
2197
else
2198
#endif /* HAVE_GSSAPI */
2199
cgiSetVariable("KERBEROS", "");
2200
2201
if ((val = cupsGetOption("BrowseWebIF", num_settings,
2202
settings)) == NULL)
2203
val = "No";
2204
2205
if (!_cups_strcasecmp(val, "yes") || !_cups_strcasecmp(val, "on") ||
2206
!_cups_strcasecmp(val, "true"))
2207
cgiSetVariable("BROWSE_WEB_IF", "CHECKED");
2208
2209
if ((val = cupsGetOption("PreserveJobHistory", num_settings,
2210
settings)) == NULL)
2211
val = "Yes";
2212
2213
if (val &&
2214
(!_cups_strcasecmp(val, "0") || !_cups_strcasecmp(val, "no") ||
2215
!_cups_strcasecmp(val, "off") || !_cups_strcasecmp(val, "false") ||
2216
!_cups_strcasecmp(val, "disabled")))
2217
{
2218
cgiSetVariable("PRESERVE_JOB_HISTORY", "0");
2219
cgiSetVariable("PRESERVE_JOB_FILES", "0");
2220
}
2221
else
2222
{
2223
cgiSetVariable("PRESERVE_JOBS", "CHECKED");
2224
cgiSetVariable("PRESERVE_JOB_HISTORY", val);
2225
2226
if ((val = cupsGetOption("PreserveJobFiles", num_settings,
2227
settings)) == NULL)
2228
val = "1d";
2229
2230
cgiSetVariable("PRESERVE_JOB_FILES", val);
2231
2232
}
2233
2234
if ((val = cupsGetOption("MaxClients", num_settings, settings)) == NULL)
2235
val = "100";
2236
2237
cgiSetVariable("MAX_CLIENTS", val);
2238
2239
if ((val = cupsGetOption("MaxJobs", num_settings, settings)) == NULL)
2240
val = "500";
2241
2242
cgiSetVariable("MAX_JOBS", val);
2243
2244
if ((val = cupsGetOption("MaxLogSize", num_settings, settings)) == NULL)
2245
val = "1m";
2246
2247
cgiSetVariable("MAX_LOG_SIZE", val);
2248
2249
cupsFreeOptions(num_settings, settings);
2250
2251
/*
2252
* Finally, show the main menu template...
2253
*/
2254
2255
cgiStartHTML(cgiText(_("Administration")));
2256
2257
cgiCopyTemplateLang("admin.tmpl");
2258
2259
cgiEndHTML();
2260
}
2261
2262
2263
/*
2264
* 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2265
*/
2266
2267
static void
2268
do_set_allowed_users(http_t *http) /* I - HTTP connection */
2269
{
2270
int i; /* Looping var */
2271
ipp_t *request, /* IPP request */
2272
*response; /* IPP response */
2273
char uri[HTTP_MAX_URI]; /* Printer URI */
2274
const char *printer, /* Printer name */
2275
*is_class, /* Is a class? */
2276
*users, /* List of users or groups */
2277
*type; /* Allow/deny type */
2278
int num_users; /* Number of users */
2279
char *ptr, /* Pointer into users string */
2280
*end, /* Pointer to end of users string */
2281
quote; /* Quote character */
2282
ipp_attribute_t *attr; /* Attribute */
2283
static const char * const attrs[] = /* Requested attributes */
2284
{
2285
"requesting-user-name-allowed",
2286
"requesting-user-name-denied"
2287
};
2288
2289
2290
is_class = cgiGetVariable("IS_CLASS");
2291
printer = cgiGetVariable("PRINTER_NAME");
2292
2293
if (!printer)
2294
{
2295
cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2296
cgiStartHTML(cgiText(_("Set Allowed Users")));
2297
cgiCopyTemplateLang("error.tmpl");
2298
cgiEndHTML();
2299
return;
2300
}
2301
2302
users = cgiGetVariable("users");
2303
type = cgiGetVariable("type");
2304
2305
if (!users || !type ||
2306
(strcmp(type, "requesting-user-name-allowed") &&
2307
strcmp(type, "requesting-user-name-denied")))
2308
{
2309
/*
2310
* Build a Get-Printer-Attributes request, which requires the following
2311
* attributes:
2312
*
2313
* attributes-charset
2314
* attributes-natural-language
2315
* printer-uri
2316
* requested-attributes
2317
*/
2318
2319
request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
2320
2321
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2322
"localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2323
printer);
2324
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2325
NULL, uri);
2326
2327
ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
2328
"requested-attributes",
2329
(int)(sizeof(attrs) / sizeof(attrs[0])), NULL, attrs);
2330
2331
/*
2332
* Do the request and get back a response...
2333
*/
2334
2335
if ((response = cupsDoRequest(http, request, "/")) != NULL)
2336
{
2337
cgiSetIPPVars(response, NULL, NULL, NULL, 0);
2338
2339
ippDelete(response);
2340
}
2341
2342
cgiStartHTML(cgiText(_("Set Allowed Users")));
2343
2344
if (cupsLastError() == IPP_NOT_AUTHORIZED)
2345
{
2346
puts("Status: 401\n");
2347
exit(0);
2348
}
2349
else if (cupsLastError() > IPP_OK_CONFLICT)
2350
cgiShowIPPError(_("Unable to get printer attributes"));
2351
else
2352
cgiCopyTemplateLang("users.tmpl");
2353
2354
cgiEndHTML();
2355
}
2356
else
2357
{
2358
/*
2359
* Save the changes...
2360
*/
2361
2362
for (num_users = 0, ptr = (char *)users; *ptr; num_users ++)
2363
{
2364
/*
2365
* Skip whitespace and commas...
2366
*/
2367
2368
while (*ptr == ',' || isspace(*ptr & 255))
2369
ptr ++;
2370
2371
if (!*ptr)
2372
break;
2373
2374
if (*ptr == '\'' || *ptr == '\"')
2375
{
2376
/*
2377
* Scan quoted name...
2378
*/
2379
2380
quote = *ptr++;
2381
2382
for (end = ptr; *end; end ++)
2383
if (*end == quote)
2384
break;
2385
}
2386
else
2387
{
2388
/*
2389
* Scan space or comma-delimited name...
2390
*/
2391
2392
for (end = ptr; *end; end ++)
2393
if (isspace(*end & 255) || *end == ',')
2394
break;
2395
}
2396
2397
/*
2398
* Advance to the next name...
2399
*/
2400
2401
ptr = end;
2402
}
2403
2404
/*
2405
* Build a CUPS-Add-Printer/Class request, which requires the following
2406
* attributes:
2407
*
2408
* attributes-charset
2409
* attributes-natural-language
2410
* printer-uri
2411
* requesting-user-name-{allowed,denied}
2412
*/
2413
2414
request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER);
2415
2416
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2417
"localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2418
printer);
2419
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2420
NULL, uri);
2421
2422
if (num_users == 0)
2423
ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
2424
"requesting-user-name-allowed", NULL, "all");
2425
else
2426
{
2427
attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
2428
type, num_users, NULL, NULL);
2429
2430
for (i = 0, ptr = (char *)users; *ptr; i ++)
2431
{
2432
/*
2433
* Skip whitespace and commas...
2434
*/
2435
2436
while (*ptr == ',' || isspace(*ptr & 255))
2437
ptr ++;
2438
2439
if (!*ptr)
2440
break;
2441
2442
if (*ptr == '\'' || *ptr == '\"')
2443
{
2444
/*
2445
* Scan quoted name...
2446
*/
2447
2448
quote = *ptr++;
2449
2450
for (end = ptr; *end; end ++)
2451
if (*end == quote)
2452
break;
2453
}
2454
else
2455
{
2456
/*
2457
* Scan space or comma-delimited name...
2458
*/
2459
2460
for (end = ptr; *end; end ++)
2461
if (isspace(*end & 255) || *end == ',')
2462
break;
2463
}
2464
2465
/*
2466
* Terminate the name...
2467
*/
2468
2469
if (*end)
2470
*end++ = '\0';
2471
2472
/*
2473
* Add the name...
2474
*/
2475
2476
ippSetString(request, &attr, i, ptr);
2477
2478
/*
2479
* Advance to the next name...
2480
*/
2481
2482
ptr = end;
2483
}
2484
}
2485
2486
/*
2487
* Do the request and get back a response...
2488
*/
2489
2490
ippDelete(cupsDoRequest(http, request, "/admin/"));
2491
2492
if (cupsLastError() == IPP_NOT_AUTHORIZED)
2493
{
2494
puts("Status: 401\n");
2495
exit(0);
2496
}
2497
else if (cupsLastError() > IPP_OK_CONFLICT)
2498
{
2499
cgiStartHTML(cgiText(_("Set Allowed Users")));
2500
cgiShowIPPError(_("Unable to change printer"));
2501
}
2502
else
2503
{
2504
/*
2505
* Redirect successful updates back to the printer page...
2506
*/
2507
2508
char url[1024], /* Printer/class URL */
2509
refresh[1024]; /* Refresh URL */
2510
2511
2512
cgiRewriteURL(uri, url, sizeof(url), NULL);
2513
cgiFormEncode(uri, url, sizeof(uri));
2514
snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s",
2515
uri);
2516
cgiSetVariable("refresh_page", refresh);
2517
2518
cgiStartHTML(cgiText(_("Set Allowed Users")));
2519
2520
cgiCopyTemplateLang(is_class ? "class-modified.tmpl" :
2521
"printer-modified.tmpl");
2522
}
2523
2524
cgiEndHTML();
2525
}
2526
}
2527
2528
2529
/*
2530
* 'do_set_default()' - Set the server default printer/class.
2531
*/
2532
2533
static void
2534
do_set_default(http_t *http) /* I - HTTP connection */
2535
{
2536
const char *title; /* Page title */
2537
ipp_t *request; /* IPP request */
2538
char uri[HTTP_MAX_URI]; /* Printer URI */
2539
const char *printer, /* Printer name */
2540
*is_class; /* Is a class? */
2541
2542
2543
is_class = cgiGetVariable("IS_CLASS");
2544
printer = cgiGetVariable("PRINTER_NAME");
2545
title = cgiText(_("Set As Server Default"));
2546
2547
if (!printer)
2548
{
2549
cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2550
cgiStartHTML(title);
2551
cgiCopyTemplateLang("error.tmpl");
2552
cgiEndHTML();
2553
return;
2554
}
2555
2556
/*
2557
* Build a printer request, which requires the following
2558
* attributes:
2559
*
2560
* attributes-charset
2561
* attributes-natural-language
2562
* printer-uri
2563
*/
2564
2565
request = ippNewRequest(CUPS_SET_DEFAULT);
2566
2567
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2568
"localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2569
printer);
2570
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2571
NULL, uri);
2572
2573
/*
2574
* Do the request and get back a response...
2575
*/
2576
2577
ippDelete(cupsDoRequest(http, request, "/admin/"));
2578
2579
if (cupsLastError() == IPP_NOT_AUTHORIZED)
2580
{
2581
puts("Status: 401\n");
2582
exit(0);
2583
}
2584
else if (cupsLastError() > IPP_OK_CONFLICT)
2585
{
2586
cgiStartHTML(title);
2587
cgiShowIPPError(_("Unable to set server default"));
2588
}
2589
else
2590
{
2591
/*
2592
* Redirect successful updates back to the printer page...
2593
*/
2594
2595
char url[1024], /* Printer/class URL */
2596
refresh[1024]; /* Refresh URL */
2597
2598
2599
cgiRewriteURL(uri, url, sizeof(url), NULL);
2600
cgiFormEncode(uri, url, sizeof(uri));
2601
snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri);
2602
cgiSetVariable("refresh_page", refresh);
2603
2604
cgiStartHTML(title);
2605
cgiCopyTemplateLang("printer-default.tmpl");
2606
}
2607
2608
cgiEndHTML();
2609
}
2610
2611
2612
/*
2613
* 'do_set_options()' - Configure the default options for a queue.
2614
*/
2615
2616
static void
2617
do_set_options(http_t *http, /* I - HTTP connection */
2618
int is_class) /* I - Set options for class? */
2619
{
2620
int i, j, k, m; /* Looping vars */
2621
int have_options; /* Have options? */
2622
ipp_t *request, /* IPP request */
2623
*response; /* IPP response */
2624
ipp_attribute_t *attr; /* IPP attribute */
2625
char uri[HTTP_MAX_URI]; /* Job URI */
2626
const char *var; /* Variable value */
2627
const char *printer; /* Printer printer name */
2628
const char *filename; /* PPD filename */
2629
char tempfile[1024]; /* Temporary filename */
2630
cups_file_t *in, /* Input file */
2631
*out; /* Output file */
2632
char line[1024], /* Line from PPD file */
2633
value[1024], /* Option value */
2634
keyword[1024], /* Keyword from Default line */
2635
*keyptr; /* Pointer into keyword... */
2636
ppd_file_t *ppd; /* PPD file */
2637
ppd_group_t *group; /* Option group */
2638
ppd_option_t *option; /* Option */
2639
ppd_coption_t *coption; /* Custom option */
2640
ppd_cparam_t *cparam; /* Custom parameter */
2641
ppd_attr_t *ppdattr; /* PPD attribute */
2642
const char *title; /* Page title */
2643
2644
2645
title = cgiText(is_class ? _("Set Class Options") : _("Set Printer Options"));
2646
2647
fprintf(stderr, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http,
2648
is_class);
2649
2650
/*
2651
* Get the printer name...
2652
*/
2653
2654
if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
2655
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2656
"localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2657
printer);
2658
else
2659
{
2660
cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2661
cgiStartHTML(title);
2662
cgiCopyTemplateLang("error.tmpl");
2663
cgiEndHTML();
2664
return;
2665
}
2666
2667
fprintf(stderr, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer, uri);
2668
2669
/*
2670
* If the user clicks on the Auto-Configure button, send an AutoConfigure
2671
* command file to the printer...
2672
*/
2673
2674
if (cgiGetVariable("AUTOCONFIGURE"))
2675
{
2676
cgiPrintCommand(http, printer, "AutoConfigure", "Set Default Options");
2677
return;
2678
}
2679
2680
/*
2681
* Get the PPD file...
2682
*/
2683
2684
if (is_class)
2685
filename = NULL;
2686
else
2687
filename = cupsGetPPD2(http, printer);
2688
2689
if (filename)
2690
{
2691
fprintf(stderr, "DEBUG: Got PPD file: \"%s\"\n", filename);
2692
2693
if ((ppd = ppdOpenFile(filename)) == NULL)
2694
{
2695
cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i)));
2696
cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file")));
2697
cgiStartHTML(title);
2698
cgiCopyTemplateLang("error.tmpl");
2699
cgiEndHTML();
2700
return;
2701
}
2702
}
2703
else
2704
{
2705
fputs("DEBUG: No PPD file\n", stderr);
2706
ppd = NULL;
2707
}
2708
2709
if (cgiGetVariable("job_sheets_start") != NULL ||
2710
cgiGetVariable("job_sheets_end") != NULL)
2711
have_options = 1;
2712
else
2713
have_options = 0;
2714
2715
if (ppd)
2716
{
2717
ppdMarkDefaults(ppd);
2718
2719
for (option = ppdFirstOption(ppd);
2720
option;
2721
option = ppdNextOption(ppd))
2722
{
2723
if ((var = cgiGetVariable(option->keyword)) != NULL)
2724
{
2725
have_options = 1;
2726
ppdMarkOption(ppd, option->keyword, var);
2727
fprintf(stderr, "DEBUG: Set %s to %s...\n", option->keyword, var);
2728
}
2729
else
2730
fprintf(stderr, "DEBUG: Didn't find %s...\n", option->keyword);
2731
}
2732
}
2733
2734
if (!have_options || ppdConflicts(ppd))
2735
{
2736
/*
2737
* Show the options to the user...
2738
*/
2739
2740
fputs("DEBUG: Showing options...\n", stderr);
2741
2742
/*
2743
* Show auto-configure button if supported...
2744
*/
2745
2746
if (ppd)
2747
{
2748
if (ppd->num_filters == 0 ||
2749
((ppdattr = ppdFindAttr(ppd, "cupsCommands", NULL)) != NULL &&
2750
ppdattr->value && strstr(ppdattr->value, "AutoConfigure")))
2751
cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
2752
else
2753
{
2754
for (i = 0; i < ppd->num_filters; i ++)
2755
if (!strncmp(ppd->filters[i], "application/vnd.cups-postscript", 31))
2756
{
2757
cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
2758
break;
2759
}
2760
}
2761
}
2762
2763
/*
2764
* Get the printer attributes...
2765
*/
2766
2767
request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
2768
2769
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2770
"localhost", 0, "/printers/%s", printer);
2771
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2772
NULL, uri);
2773
2774
response = cupsDoRequest(http, request, "/");
2775
2776
/*
2777
* List the groups used as "tabs"...
2778
*/
2779
2780
i = 0;
2781
2782
if (ppd)
2783
{
2784
for (group = ppd->groups;
2785
i < ppd->num_groups;
2786
i ++, group ++)
2787
{
2788
cgiSetArray("GROUP_ID", i, group->name);
2789
2790
if (!strcmp(group->name, "InstallableOptions"))
2791
cgiSetArray("GROUP", i, cgiText(_("Options Installed")));
2792
else
2793
cgiSetArray("GROUP", i, group->text);
2794
}
2795
}
2796
2797
if (ippFindAttribute(response, "job-sheets-supported", IPP_TAG_ZERO))
2798
{
2799
cgiSetArray("GROUP_ID", i, "CUPS_BANNERS");
2800
cgiSetArray("GROUP", i ++, cgiText(_("Banners")));
2801
}
2802
2803
if (ippFindAttribute(response, "printer-error-policy-supported",
2804
IPP_TAG_ZERO) ||
2805
ippFindAttribute(response, "printer-op-policy-supported",
2806
IPP_TAG_ZERO))
2807
{
2808
cgiSetArray("GROUP_ID", i, "CUPS_POLICIES");
2809
cgiSetArray("GROUP", i ++, cgiText(_("Policies")));
2810
}
2811
2812
if ((attr = ippFindAttribute(response, "port-monitor-supported",
2813
IPP_TAG_NAME)) != NULL && attr->num_values > 1)
2814
{
2815
cgiSetArray("GROUP_ID", i, "CUPS_PORT_MONITOR");
2816
cgiSetArray("GROUP", i, cgiText(_("Port Monitor")));
2817
}
2818
2819
cgiStartHTML(cgiText(_("Set Printer Options")));
2820
cgiCopyTemplateLang("set-printer-options-header.tmpl");
2821
2822
if (ppd)
2823
{
2824
ppdLocalize(ppd);
2825
2826
if (ppdConflicts(ppd))
2827
{
2828
for (i = ppd->num_groups, k = 0, group = ppd->groups;
2829
i > 0;
2830
i --, group ++)
2831
for (j = group->num_options, option = group->options;
2832
j > 0;
2833
j --, option ++)
2834
if (option->conflicted)
2835
{
2836
cgiSetArray("ckeyword", k, option->keyword);
2837
cgiSetArray("ckeytext", k, option->text);
2838
2839
for (m = 0; m < option->num_choices; m ++)
2840
{
2841
if (option->choices[m].marked)
2842
{
2843
cgiSetArray("cchoice", k, option->choices[m].text);
2844
break;
2845
}
2846
}
2847
2848
k ++;
2849
}
2850
2851
cgiCopyTemplateLang("option-conflict.tmpl");
2852
}
2853
2854
for (i = ppd->num_groups, group = ppd->groups;
2855
i > 0;
2856
i --, group ++)
2857
{
2858
for (j = group->num_options, option = group->options;
2859
j > 0;
2860
j --, option ++)
2861
{
2862
if (!strcmp(option->keyword, "PageRegion"))
2863
continue;
2864
2865
if (option->num_choices > 1)
2866
break;
2867
}
2868
2869
if (j == 0)
2870
continue;
2871
2872
cgiSetVariable("GROUP_ID", group->name);
2873
2874
if (!strcmp(group->name, "InstallableOptions"))
2875
cgiSetVariable("GROUP", cgiText(_("Options Installed")));
2876
else
2877
cgiSetVariable("GROUP", group->text);
2878
2879
cgiCopyTemplateLang("option-header.tmpl");
2880
2881
for (j = group->num_options, option = group->options;
2882
j > 0;
2883
j --, option ++)
2884
{
2885
if (!strcmp(option->keyword, "PageRegion") || option->num_choices < 2)
2886
continue;
2887
2888
cgiSetVariable("KEYWORD", option->keyword);
2889
cgiSetVariable("KEYTEXT", option->text);
2890
2891
if (option->conflicted)
2892
cgiSetVariable("CONFLICTED", "1");
2893
else
2894
cgiSetVariable("CONFLICTED", "0");
2895
2896
cgiSetSize("CHOICES", 0);
2897
cgiSetSize("TEXT", 0);
2898
for (k = 0, m = 0; k < option->num_choices; k ++)
2899
{
2900
cgiSetArray("CHOICES", m, option->choices[k].choice);
2901
cgiSetArray("TEXT", m, option->choices[k].text);
2902
2903
m ++;
2904
2905
if (option->choices[k].marked)
2906
cgiSetVariable("DEFCHOICE", option->choices[k].choice);
2907
}
2908
2909
cgiSetSize("PARAMS", 0);
2910
cgiSetSize("PARAMTEXT", 0);
2911
cgiSetSize("PARAMVALUE", 0);
2912
cgiSetSize("INPUTTYPE", 0);
2913
2914
if ((coption = ppdFindCustomOption(ppd, option->keyword)))
2915
{
2916
const char *units = NULL; /* Units value, if any */
2917
2918
cgiSetVariable("ISCUSTOM", "1");
2919
2920
for (cparam = ppdFirstCustomParam(coption), m = 0;
2921
cparam;
2922
cparam = ppdNextCustomParam(coption), m ++)
2923
{
2924
if (!_cups_strcasecmp(option->keyword, "PageSize") &&
2925
_cups_strcasecmp(cparam->name, "Width") &&
2926
_cups_strcasecmp(cparam->name, "Height"))
2927
{
2928
m --;
2929
continue;
2930
}
2931
2932
cgiSetArray("PARAMS", m, cparam->name);
2933
cgiSetArray("PARAMTEXT", m, cparam->text);
2934
cgiSetArray("INPUTTYPE", m, "text");
2935
2936
switch (cparam->type)
2937
{
2938
case PPD_CUSTOM_UNKNOWN :
2939
break;
2940
2941
case PPD_CUSTOM_POINTS :
2942
if (!_cups_strncasecmp(option->defchoice, "Custom.", 7))
2943
{
2944
units = option->defchoice + strlen(option->defchoice) - 2;
2945
2946
if (strcmp(units, "mm") && strcmp(units, "cm") &&
2947
strcmp(units, "in") && strcmp(units, "ft"))
2948
{
2949
if (units[1] == 'm')
2950
units ++;
2951
else
2952
units = "pt";
2953
}
2954
}
2955
else
2956
units = "pt";
2957
2958
if (!strcmp(units, "mm"))
2959
snprintf(value, sizeof(value), "%g",
2960
cparam->current.custom_points / 72.0 * 25.4);
2961
else if (!strcmp(units, "cm"))
2962
snprintf(value, sizeof(value), "%g",
2963
cparam->current.custom_points / 72.0 * 2.54);
2964
else if (!strcmp(units, "in"))
2965
snprintf(value, sizeof(value), "%g",
2966
cparam->current.custom_points / 72.0);
2967
else if (!strcmp(units, "ft"))
2968
snprintf(value, sizeof(value), "%g",
2969
cparam->current.custom_points / 72.0 / 12.0);
2970
else if (!strcmp(units, "m"))
2971
snprintf(value, sizeof(value), "%g",
2972
cparam->current.custom_points / 72.0 * 0.0254);
2973
else
2974
snprintf(value, sizeof(value), "%g",
2975
cparam->current.custom_points);
2976
cgiSetArray("PARAMVALUE", m, value);
2977
break;
2978
2979
case PPD_CUSTOM_CURVE :
2980
case PPD_CUSTOM_INVCURVE :
2981
case PPD_CUSTOM_REAL :
2982
snprintf(value, sizeof(value), "%g",
2983
cparam->current.custom_real);
2984
cgiSetArray("PARAMVALUE", m, value);
2985
break;
2986
2987
case PPD_CUSTOM_INT:
2988
snprintf(value, sizeof(value), "%d",
2989
cparam->current.custom_int);
2990
cgiSetArray("PARAMVALUE", m, value);
2991
break;
2992
2993
case PPD_CUSTOM_PASSCODE:
2994
case PPD_CUSTOM_PASSWORD:
2995
if (cparam->current.custom_password)
2996
cgiSetArray("PARAMVALUE", m,
2997
cparam->current.custom_password);
2998
else
2999
cgiSetArray("PARAMVALUE", m, "");
3000
cgiSetArray("INPUTTYPE", m, "password");
3001
break;
3002
3003
case PPD_CUSTOM_STRING:
3004
if (cparam->current.custom_string)
3005
cgiSetArray("PARAMVALUE", m,
3006
cparam->current.custom_string);
3007
else
3008
cgiSetArray("PARAMVALUE", m, "");
3009
break;
3010
}
3011
}
3012
3013
if (units)
3014
{
3015
cgiSetArray("PARAMS", m, "Units");
3016
cgiSetArray("PARAMTEXT", m, cgiText(_("Units")));
3017
cgiSetArray("PARAMVALUE", m, units);
3018
}
3019
}
3020
else
3021
cgiSetVariable("ISCUSTOM", "0");
3022
3023
switch (option->ui)
3024
{
3025
case PPD_UI_BOOLEAN :
3026
cgiCopyTemplateLang("option-boolean.tmpl");
3027
break;
3028
case PPD_UI_PICKONE :
3029
cgiCopyTemplateLang("option-pickone.tmpl");
3030
break;
3031
case PPD_UI_PICKMANY :
3032
cgiCopyTemplateLang("option-pickmany.tmpl");
3033
break;
3034
}
3035
}
3036
3037
cgiCopyTemplateLang("option-trailer.tmpl");
3038
}
3039
}
3040
3041
if ((attr = ippFindAttribute(response, "job-sheets-supported",
3042
IPP_TAG_ZERO)) != NULL)
3043
{
3044
/*
3045
* Add the job sheets options...
3046
*/
3047
3048
cgiSetVariable("GROUP_ID", "CUPS_BANNERS");
3049
cgiSetVariable("GROUP", cgiText(_("Banners")));
3050
cgiCopyTemplateLang("option-header.tmpl");
3051
3052
cgiSetSize("CHOICES", attr->num_values);
3053
cgiSetSize("TEXT", attr->num_values);
3054
for (k = 0; k < attr->num_values; k ++)
3055
{
3056
cgiSetArray("CHOICES", k, attr->values[k].string.text);
3057
cgiSetArray("TEXT", k, attr->values[k].string.text);
3058
}
3059
3060
attr = ippFindAttribute(response, "job-sheets-default", IPP_TAG_ZERO);
3061
3062
cgiSetVariable("KEYWORD", "job_sheets_start");
3063
cgiSetVariable("KEYTEXT",
3064
/* TRANSLATORS: Banner/cover sheet before the print job. */
3065
cgiText(_("Starting Banner")));
3066
cgiSetVariable("DEFCHOICE", attr != NULL ?
3067
attr->values[0].string.text : "");
3068
3069
cgiCopyTemplateLang("option-pickone.tmpl");
3070
3071
cgiSetVariable("KEYWORD", "job_sheets_end");
3072
cgiSetVariable("KEYTEXT",
3073
/* TRANSLATORS: Banner/cover sheet after the print job. */
3074
cgiText(_("Ending Banner")));
3075
cgiSetVariable("DEFCHOICE", attr != NULL && attr->num_values > 1 ?
3076
attr->values[1].string.text : "");
3077
3078
cgiCopyTemplateLang("option-pickone.tmpl");
3079
3080
cgiCopyTemplateLang("option-trailer.tmpl");
3081
}
3082
3083
if (ippFindAttribute(response, "printer-error-policy-supported",
3084
IPP_TAG_ZERO) ||
3085
ippFindAttribute(response, "printer-op-policy-supported",
3086
IPP_TAG_ZERO))
3087
{
3088
/*
3089
* Add the error and operation policy options...
3090
*/
3091
3092
cgiSetVariable("GROUP_ID", "CUPS_POLICIES");
3093
cgiSetVariable("GROUP", cgiText(_("Policies")));
3094
cgiCopyTemplateLang("option-header.tmpl");
3095
3096
/*
3097
* Error policy...
3098
*/
3099
3100
attr = ippFindAttribute(response, "printer-error-policy-supported",
3101
IPP_TAG_ZERO);
3102
3103
if (attr)
3104
{
3105
cgiSetSize("CHOICES", attr->num_values);
3106
cgiSetSize("TEXT", attr->num_values);
3107
for (k = 0; k < attr->num_values; k ++)
3108
{
3109
cgiSetArray("CHOICES", k, attr->values[k].string.text);
3110
cgiSetArray("TEXT", k, attr->values[k].string.text);
3111
}
3112
3113
attr = ippFindAttribute(response, "printer-error-policy",
3114
IPP_TAG_ZERO);
3115
3116
cgiSetVariable("KEYWORD", "printer_error_policy");
3117
cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
3118
cgiSetVariable("DEFCHOICE", attr == NULL ?
3119
"" : attr->values[0].string.text);
3120
}
3121
3122
cgiCopyTemplateLang("option-pickone.tmpl");
3123
3124
/*
3125
* Operation policy...
3126
*/
3127
3128
attr = ippFindAttribute(response, "printer-op-policy-supported",
3129
IPP_TAG_ZERO);
3130
3131
if (attr)
3132
{
3133
cgiSetSize("CHOICES", attr->num_values);
3134
cgiSetSize("TEXT", attr->num_values);
3135
for (k = 0; k < attr->num_values; k ++)
3136
{
3137
cgiSetArray("CHOICES", k, attr->values[k].string.text);
3138
cgiSetArray("TEXT", k, attr->values[k].string.text);
3139
}
3140
3141
attr = ippFindAttribute(response, "printer-op-policy", IPP_TAG_ZERO);
3142
3143
cgiSetVariable("KEYWORD", "printer_op_policy");
3144
cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
3145
cgiSetVariable("DEFCHOICE", attr == NULL ?
3146
"" : attr->values[0].string.text);
3147
3148
cgiCopyTemplateLang("option-pickone.tmpl");
3149
}
3150
3151
cgiCopyTemplateLang("option-trailer.tmpl");
3152
}
3153
3154
/*
3155
* Binary protocol support...
3156
*/
3157
3158
if ((attr = ippFindAttribute(response, "port-monitor-supported",
3159
IPP_TAG_NAME)) != NULL && attr->num_values > 1)
3160
{
3161
cgiSetVariable("GROUP_ID", "CUPS_PORT_MONITOR");
3162
cgiSetVariable("GROUP", cgiText(_("Port Monitor")));
3163
3164
cgiSetSize("CHOICES", attr->num_values);
3165
cgiSetSize("TEXT", attr->num_values);
3166
3167
for (i = 0; i < attr->num_values; i ++)
3168
{
3169
cgiSetArray("CHOICES", i, attr->values[i].string.text);
3170
cgiSetArray("TEXT", i, attr->values[i].string.text);
3171
}
3172
3173
attr = ippFindAttribute(response, "port-monitor", IPP_TAG_NAME);
3174
cgiSetVariable("KEYWORD", "port_monitor");
3175
cgiSetVariable("KEYTEXT", cgiText(_("Port Monitor")));
3176
cgiSetVariable("DEFCHOICE", attr ? attr->values[0].string.text : "none");
3177
3178
cgiCopyTemplateLang("option-header.tmpl");
3179
cgiCopyTemplateLang("option-pickone.tmpl");
3180
cgiCopyTemplateLang("option-trailer.tmpl");
3181
}
3182
3183
cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
3184
cgiEndHTML();
3185
3186
ippDelete(response);
3187
}
3188
else
3189
{
3190
/*
3191
* Set default options...
3192
*/
3193
3194
fputs("DEBUG: Setting options...\n", stderr);
3195
3196
if (filename)
3197
{
3198
out = cupsTempFile2(tempfile, sizeof(tempfile));
3199
in = cupsFileOpen(filename, "r");
3200
3201
if (!in || !out)
3202
{
3203
cgiSetVariable("ERROR", strerror(errno));
3204
cgiStartHTML(cgiText(_("Set Printer Options")));
3205
cgiCopyTemplateLang("error.tmpl");
3206
cgiEndHTML();
3207
3208
if (in)
3209
cupsFileClose(in);
3210
3211
if (out)
3212
{
3213
cupsFileClose(out);
3214
unlink(tempfile);
3215
}
3216
3217
unlink(filename);
3218
return;
3219
}
3220
3221
while (cupsFileGets(in, line, sizeof(line)))
3222
{
3223
if (!strncmp(line, "*cupsProtocol:", 14))
3224
continue;
3225
else if (strncmp(line, "*Default", 8))
3226
cupsFilePrintf(out, "%s\n", line);
3227
else
3228
{
3229
/*
3230
* Get default option name...
3231
*/
3232
3233
strlcpy(keyword, line + 8, sizeof(keyword));
3234
3235
for (keyptr = keyword; *keyptr; keyptr ++)
3236
if (*keyptr == ':' || isspace(*keyptr & 255))
3237
break;
3238
3239
*keyptr = '\0';
3240
3241
if (!strcmp(keyword, "PageRegion") ||
3242
!strcmp(keyword, "PaperDimension") ||
3243
!strcmp(keyword, "ImageableArea"))
3244
var = get_option_value(ppd, "PageSize", value, sizeof(value));
3245
else
3246
var = get_option_value(ppd, keyword, value, sizeof(value));
3247
3248
if (!var)
3249
cupsFilePrintf(out, "%s\n", line);
3250
else
3251
cupsFilePrintf(out, "*Default%s: %s\n", keyword, var);
3252
}
3253
}
3254
3255
cupsFileClose(in);
3256
cupsFileClose(out);
3257
}
3258
else
3259
{
3260
/*
3261
* Make sure temporary filename is cleared when there is no PPD...
3262
*/
3263
3264
tempfile[0] = '\0';
3265
}
3266
3267
/*
3268
* Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the
3269
* following attributes:
3270
*
3271
* attributes-charset
3272
* attributes-natural-language
3273
* printer-uri
3274
* job-sheets-default
3275
* printer-error-policy
3276
* printer-op-policy
3277
* [ppd file]
3278
*/
3279
3280
request = ippNewRequest(is_class ? CUPS_ADD_MODIFY_CLASS :
3281
CUPS_ADD_MODIFY_PRINTER);
3282
3283
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3284
NULL, uri);
3285
3286
attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3287
"job-sheets-default", 2, NULL, NULL);
3288
ippSetString(request, &attr, 0, cgiGetVariable("job_sheets_start"));
3289
ippSetString(request, &attr, 1, cgiGetVariable("job_sheets_end"));
3290
3291
if ((var = cgiGetVariable("printer_error_policy")) != NULL)
3292
ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3293
"printer-error-policy", NULL, var);
3294
3295
if ((var = cgiGetVariable("printer_op_policy")) != NULL)
3296
ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3297
"printer-op-policy", NULL, var);
3298
3299
if ((var = cgiGetVariable("port_monitor")) != NULL)
3300
ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3301
"port-monitor", NULL, var);
3302
3303
/*
3304
* Do the request and get back a response...
3305
*/
3306
3307
if (filename)
3308
ippDelete(cupsDoFileRequest(http, request, "/admin/", tempfile));
3309
else
3310
ippDelete(cupsDoRequest(http, request, "/admin/"));
3311
3312
if (cupsLastError() == IPP_NOT_AUTHORIZED)
3313
{
3314
puts("Status: 401\n");
3315
exit(0);
3316
}
3317
else if (cupsLastError() > IPP_OK_CONFLICT)
3318
{
3319
cgiStartHTML(title);
3320
cgiShowIPPError(_("Unable to set options"));
3321
}
3322
else
3323
{
3324
/*
3325
* Redirect successful updates back to the printer page...
3326
*/
3327
3328
char refresh[1024]; /* Refresh URL */
3329
3330
3331
cgiFormEncode(uri, printer, sizeof(uri));
3332
snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
3333
is_class ? "classes" : "printers", uri);
3334
cgiSetVariable("refresh_page", refresh);
3335
3336
cgiStartHTML(title);
3337
3338
cgiCopyTemplateLang("printer-configured.tmpl");
3339
}
3340
3341
cgiEndHTML();
3342
3343
if (filename)
3344
unlink(tempfile);
3345
}
3346
3347
if (filename)
3348
unlink(filename);
3349
}
3350
3351
3352
/*
3353
* 'do_set_sharing()' - Set printer-is-shared value.
3354
*/
3355
3356
static void
3357
do_set_sharing(http_t *http) /* I - HTTP connection */
3358
{
3359
ipp_t *request, /* IPP request */
3360
*response; /* IPP response */
3361
char uri[HTTP_MAX_URI]; /* Printer URI */
3362
const char *printer, /* Printer name */
3363
*is_class, /* Is a class? */
3364
*shared; /* Sharing value */
3365
3366
3367
is_class = cgiGetVariable("IS_CLASS");
3368
printer = cgiGetVariable("PRINTER_NAME");
3369
shared = cgiGetVariable("SHARED");
3370
3371
if (!printer || !shared)
3372
{
3373
cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3374
cgiStartHTML(cgiText(_("Set Publishing")));
3375
cgiCopyTemplateLang("error.tmpl");
3376
cgiEndHTML();
3377
return;
3378
}
3379
3380
/*
3381
* Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
3382
* following attributes:
3383
*
3384
* attributes-charset
3385
* attributes-natural-language
3386
* printer-uri
3387
* printer-is-shared
3388
*/
3389
3390
request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER);
3391
3392
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3393
"localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
3394
printer);
3395
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3396
NULL, uri);
3397
3398
ippAddBoolean(request, IPP_TAG_OPERATION, "printer-is-shared", (char)atoi(shared));
3399
3400
/*
3401
* Do the request and get back a response...
3402
*/
3403
3404
if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
3405
{
3406
cgiSetIPPVars(response, NULL, NULL, NULL, 0);
3407
3408
ippDelete(response);
3409
}
3410
3411
if (cupsLastError() == IPP_NOT_AUTHORIZED)
3412
{
3413
puts("Status: 401\n");
3414
exit(0);
3415
}
3416
else if (cupsLastError() > IPP_OK_CONFLICT)
3417
{
3418
cgiStartHTML(cgiText(_("Set Publishing")));
3419
cgiShowIPPError(_("Unable to change printer-is-shared attribute"));
3420
}
3421
else
3422
{
3423
/*
3424
* Redirect successful updates back to the printer page...
3425
*/
3426
3427
char url[1024], /* Printer/class URL */
3428
refresh[1024]; /* Refresh URL */
3429
3430
3431
cgiRewriteURL(uri, url, sizeof(url), NULL);
3432
cgiFormEncode(uri, url, sizeof(uri));
3433
snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri);
3434
cgiSetVariable("refresh_page", refresh);
3435
3436
cgiStartHTML(cgiText(_("Set Publishing")));
3437
cgiCopyTemplateLang(is_class ? "class-modified.tmpl" :
3438
"printer-modified.tmpl");
3439
}
3440
3441
cgiEndHTML();
3442
}
3443
3444
3445
/*
3446
* 'get_option_value()' - Return the value of an option.
3447
*
3448
* This function also handles generation of custom option values.
3449
*/
3450
3451
static char * /* O - Value string or NULL on error */
3452
get_option_value(
3453
ppd_file_t *ppd, /* I - PPD file */
3454
const char *name, /* I - Option name */
3455
char *buffer, /* I - String buffer */
3456
size_t bufsize) /* I - Size of buffer */
3457
{
3458
char *bufptr, /* Pointer into buffer */
3459
*bufend; /* End of buffer */
3460
ppd_coption_t *coption; /* Custom option */
3461
ppd_cparam_t *cparam; /* Current custom parameter */
3462
char keyword[256]; /* Parameter name */
3463
const char *val, /* Parameter value */
3464
*uval; /* Units value */
3465
long integer; /* Integer value */
3466
double number, /* Number value */
3467
number_points; /* Number in points */
3468
3469
3470
/*
3471
* See if we have a custom option choice...
3472
*/
3473
3474
if ((val = cgiGetVariable(name)) == NULL)
3475
{
3476
/*
3477
* Option not found!
3478
*/
3479
3480
return (NULL);
3481
}
3482
else if (_cups_strcasecmp(val, "Custom") ||
3483
(coption = ppdFindCustomOption(ppd, name)) == NULL)
3484
{
3485
/*
3486
* Not a custom choice...
3487
*/
3488
3489
strlcpy(buffer, val, bufsize);
3490
return (buffer);
3491
}
3492
3493
/*
3494
* OK, we have a custom option choice, format it...
3495
*/
3496
3497
*buffer = '\0';
3498
3499
if (!strcmp(coption->keyword, "PageSize"))
3500
{
3501
const char *lval; /* Length string value */
3502
double width, /* Width value */
3503
width_points, /* Width in points */
3504
length, /* Length value */
3505
length_points; /* Length in points */
3506
3507
3508
val = cgiGetVariable("PageSize.Width");
3509
lval = cgiGetVariable("PageSize.Height");
3510
uval = cgiGetVariable("PageSize.Units");
3511
3512
if (!val || !lval || !uval ||
3513
(width = strtod(val, NULL)) == 0.0 ||
3514
(length = strtod(lval, NULL)) == 0.0 ||
3515
(strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") &&
3516
strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m")))
3517
return (NULL);
3518
3519
width_points = get_points(width, uval);
3520
length_points = get_points(length, uval);
3521
3522
if (width_points < ppd->custom_min[0] ||
3523
width_points > ppd->custom_max[0] ||
3524
length_points < ppd->custom_min[1] ||
3525
length_points > ppd->custom_max[1])
3526
return (NULL);
3527
3528
snprintf(buffer, bufsize, "Custom.%gx%g%s", width, length, uval);
3529
}
3530
else if (cupsArrayCount(coption->params) == 1)
3531
{
3532
cparam = ppdFirstCustomParam(coption);
3533
snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword, cparam->name);
3534
3535
if ((val = cgiGetVariable(keyword)) == NULL)
3536
return (NULL);
3537
3538
switch (cparam->type)
3539
{
3540
case PPD_CUSTOM_UNKNOWN :
3541
break;
3542
3543
case PPD_CUSTOM_CURVE :
3544
case PPD_CUSTOM_INVCURVE :
3545
case PPD_CUSTOM_REAL :
3546
if ((number = strtod(val, NULL)) == 0.0 ||
3547
number < cparam->minimum.custom_real ||
3548
number > cparam->maximum.custom_real)
3549
return (NULL);
3550
3551
snprintf(buffer, bufsize, "Custom.%g", number);
3552
break;
3553
3554
case PPD_CUSTOM_INT :
3555
if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN ||
3556
integer == LONG_MAX ||
3557
integer < cparam->minimum.custom_int ||
3558
integer > cparam->maximum.custom_int)
3559
return (NULL);
3560
3561
snprintf(buffer, bufsize, "Custom.%ld", integer);
3562
break;
3563
3564
case PPD_CUSTOM_POINTS :
3565
snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword);
3566
3567
if ((number = strtod(val, NULL)) == 0.0 ||
3568
(uval = cgiGetVariable(keyword)) == NULL ||
3569
(strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") &&
3570
strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m")))
3571
return (NULL);
3572
3573
number_points = get_points(number, uval);
3574
if (number_points < cparam->minimum.custom_points ||
3575
number_points > cparam->maximum.custom_points)
3576
return (NULL);
3577
3578
snprintf(buffer, bufsize, "Custom.%g%s", number, uval);
3579
break;
3580
3581
case PPD_CUSTOM_PASSCODE :
3582
for (uval = val; *uval; uval ++)
3583
if (!isdigit(*uval & 255))
3584
return (NULL);
3585
3586
case PPD_CUSTOM_PASSWORD :
3587
case PPD_CUSTOM_STRING :
3588
integer = (long)strlen(val);
3589
if (integer < cparam->minimum.custom_string ||
3590
integer > cparam->maximum.custom_string)
3591
return (NULL);
3592
3593
snprintf(buffer, bufsize, "Custom.%s", val);
3594
break;
3595
}
3596
}
3597
else
3598
{
3599
const char *prefix = "{"; /* Prefix string */
3600
3601
3602
bufptr = buffer;
3603
bufend = buffer + bufsize;
3604
3605
for (cparam = ppdFirstCustomParam(coption);
3606
cparam;
3607
cparam = ppdNextCustomParam(coption))
3608
{
3609
snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword,
3610
cparam->name);
3611
3612
if ((val = cgiGetVariable(keyword)) == NULL)
3613
return (NULL);
3614
3615
snprintf(bufptr, (size_t)(bufend - bufptr), "%s%s=", prefix, cparam->name);
3616
bufptr += strlen(bufptr);
3617
prefix = " ";
3618
3619
switch (cparam->type)
3620
{
3621
case PPD_CUSTOM_UNKNOWN :
3622
break;
3623
3624
case PPD_CUSTOM_CURVE :
3625
case PPD_CUSTOM_INVCURVE :
3626
case PPD_CUSTOM_REAL :
3627
if ((number = strtod(val, NULL)) == 0.0 ||
3628
number < cparam->minimum.custom_real ||
3629
number > cparam->maximum.custom_real)
3630
return (NULL);
3631
3632
snprintf(bufptr, (size_t)(bufend - bufptr), "%g", number);
3633
break;
3634
3635
case PPD_CUSTOM_INT :
3636
if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN ||
3637
integer == LONG_MAX ||
3638
integer < cparam->minimum.custom_int ||
3639
integer > cparam->maximum.custom_int)
3640
return (NULL);
3641
3642
snprintf(bufptr, (size_t)(bufend - bufptr), "%ld", integer);
3643
break;
3644
3645
case PPD_CUSTOM_POINTS :
3646
snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword);
3647
3648
if ((number = strtod(val, NULL)) == 0.0 ||
3649
(uval = cgiGetVariable(keyword)) == NULL ||
3650
(strcmp(uval, "pt") && strcmp(uval, "in") &&
3651
strcmp(uval, "ft") && strcmp(uval, "cm") &&
3652
strcmp(uval, "mm") && strcmp(uval, "m")))
3653
return (NULL);
3654
3655
number_points = get_points(number, uval);
3656
if (number_points < cparam->minimum.custom_points ||
3657
number_points > cparam->maximum.custom_points)
3658
return (NULL);
3659
3660
snprintf(bufptr, (size_t)(bufend - bufptr), "%g%s", number, uval);
3661
break;
3662
3663
case PPD_CUSTOM_PASSCODE :
3664
for (uval = val; *uval; uval ++)
3665
if (!isdigit(*uval & 255))
3666
return (NULL);
3667
3668
case PPD_CUSTOM_PASSWORD :
3669
case PPD_CUSTOM_STRING :
3670
integer = (long)strlen(val);
3671
if (integer < cparam->minimum.custom_string ||
3672
integer > cparam->maximum.custom_string)
3673
return (NULL);
3674
3675
if ((bufptr + 2) > bufend)
3676
return (NULL);
3677
3678
bufend --;
3679
*bufptr++ = '\"';
3680
3681
while (*val && bufptr < bufend)
3682
{
3683
if (*val == '\\' || *val == '\"')
3684
{
3685
if ((bufptr + 1) >= bufend)
3686
return (NULL);
3687
3688
*bufptr++ = '\\';
3689
}
3690
3691
*bufptr++ = *val++;
3692
}
3693
3694
if (bufptr >= bufend)
3695
return (NULL);
3696
3697
*bufptr++ = '\"';
3698
*bufptr = '\0';
3699
bufend ++;
3700
break;
3701
}
3702
3703
bufptr += strlen(bufptr);
3704
}
3705
3706
if (bufptr == buffer || (bufend - bufptr) < 2)
3707
return (NULL);
3708
3709
memcpy(bufptr, "}", 2);
3710
}
3711
3712
return (buffer);
3713
}
3714
3715
3716
/*
3717
* 'get_points()' - Get a value in points.
3718
*/
3719
3720
static double /* O - Number in points */
3721
get_points(double number, /* I - Original number */
3722
const char *uval) /* I - Units */
3723
{
3724
if (!strcmp(uval, "mm")) /* Millimeters */
3725
return (number * 72.0 / 25.4);
3726
else if (!strcmp(uval, "cm")) /* Centimeters */
3727
return (number * 72.0 / 2.54);
3728
else if (!strcmp(uval, "in")) /* Inches */
3729
return (number * 72.0);
3730
else if (!strcmp(uval, "ft")) /* Feet */
3731
return (number * 72.0 * 12.0);
3732
else if (!strcmp(uval, "m")) /* Meters */
3733
return (number * 72.0 / 0.0254);
3734
else /* Points */
3735
return (number);
3736
}
3737
3738