2 * "$Id: admin.c,v 1.22 2001/03/05 21:37:33 mike Exp $"
4 * Administration CGI for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2001 by Easy Software Products.
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636-3111 USA
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
26 * main() - Main entry for CGI.
27 * do_am_class() - Add or modify a class.
28 * do_am_printer() - Add or modify a printer.
29 * do_config_printer() - Configure the default options for a printer.
30 * do_delete_class() - Delete a class...
31 * do_delete_printer() - Delete a printer...
32 * do_job_op() - Do a job operation.
33 * do_printer_op() - Do a printer operation.
34 * get_line() - Get a line that is terminated by a LF, CR, or CR LF.
38 * Include necessary headers...
50 static void do_am_class(http_t
*http
, cups_lang_t
*language
, int modify
);
51 static void do_am_printer(http_t
*http
, cups_lang_t
*language
, int modify
);
52 static void do_config_printer(http_t
*http
, cups_lang_t
*language
);
53 static void do_delete_class(http_t
*http
, cups_lang_t
*language
);
54 static void do_delete_printer(http_t
*http
, cups_lang_t
*language
);
55 static void do_job_op(http_t
*http
, cups_lang_t
*language
, ipp_op_t op
);
56 static void do_printer_op(http_t
*http
, cups_lang_t
*language
, ipp_op_t op
);
57 static char *get_line(char *buf
, int length
, FILE *fp
);
61 * 'main()' - Main entry for CGI.
64 int /* O - Exit status */
65 main(int argc
, /* I - Number of command-line arguments */
66 char *argv
[]) /* I - Command-line arguments */
68 cups_lang_t
*language
; /* Language information */
69 http_t
*http
; /* Connection to the server */
70 const char *op
; /* Operation name */
74 * Get the request language...
77 language
= cupsLangDefault();
80 * Send a standard header...
83 printf("Content-Type: text/html;charset=%s\n\n", cupsLangEncoding(language
));
85 cgiSetVariable("TITLE", "Admin");
86 ippSetServerVersion();
88 cgiCopyTemplateLang(stdout
, TEMPLATES
, "header.tmpl", getenv("LANG"));
91 * See if we have form data...
97 * Nope, send the administration menu...
100 cgiCopyTemplateLang(stdout
, TEMPLATES
, "admin.tmpl", getenv("LANG"));
102 else if ((op
= cgiGetVariable("OP")) != NULL
)
105 * Connect to the HTTP server...
108 http
= httpConnect("localhost", ippPort());
111 * Do the operation...
114 if (strcmp(op
, "cancel-job") == 0)
115 do_job_op(http
, language
, IPP_CANCEL_JOB
);
116 else if (strcmp(op
, "hold-job") == 0)
117 do_job_op(http
, language
, IPP_HOLD_JOB
);
118 else if (strcmp(op
, "release-job") == 0)
119 do_job_op(http
, language
, IPP_RELEASE_JOB
);
120 else if (strcmp(op
, "restart-job") == 0)
121 do_job_op(http
, language
, IPP_RESTART_JOB
);
122 else if (strcmp(op
, "start-printer") == 0)
123 do_printer_op(http
, language
, IPP_RESUME_PRINTER
);
124 else if (strcmp(op
, "stop-printer") == 0)
125 do_printer_op(http
, language
, IPP_PAUSE_PRINTER
);
126 else if (strcmp(op
, "accept-jobs") == 0)
127 do_printer_op(http
, language
, CUPS_ACCEPT_JOBS
);
128 else if (strcmp(op
, "reject-jobs") == 0)
129 do_printer_op(http
, language
, CUPS_REJECT_JOBS
);
130 else if (strcmp(op
, "add-class") == 0)
131 do_am_class(http
, language
, 0);
132 else if (strcmp(op
, "add-printer") == 0)
133 do_am_printer(http
, language
, 0);
134 else if (strcmp(op
, "modify-class") == 0)
135 do_am_class(http
, language
, 1);
136 else if (strcmp(op
, "modify-printer") == 0)
137 do_am_printer(http
, language
, 1);
138 else if (strcmp(op
, "delete-class") == 0)
139 do_delete_class(http
, language
);
140 else if (strcmp(op
, "delete-printer") == 0)
141 do_delete_printer(http
, language
);
142 else if (strcmp(op
, "config-printer") == 0)
143 do_config_printer(http
, language
);
147 * Bad operation code... Display an error...
150 cgiCopyTemplateLang(stdout
, TEMPLATES
, "admin-op.tmpl", getenv("LANG"));
154 * Close the HTTP server connection...
162 * Form data but no operation code... Display an error...
165 cgiCopyTemplateLang(stdout
, TEMPLATES
, "admin-op.tmpl", getenv("LANG"));
169 * Send the standard trailer...
172 cgiCopyTemplateLang(stdout
, TEMPLATES
, "trailer.tmpl", getenv("LANG"));
175 * Free the request language...
178 cupsLangFree(language
);
181 * Return with no errors...
189 * 'do_am_class()' - Add or modify a class.
193 do_am_class(http_t
*http
, /* I - HTTP connection */
194 cups_lang_t
*language
, /* I - Client's language */
195 int modify
) /* I - Modify the printer? */
197 int i
, j
; /* Looping vars */
198 int element
; /* Element number */
199 int num_printers
; /* Number of printers */
200 ipp_t
*request
, /* IPP request */
201 *response
; /* IPP response */
202 ipp_attribute_t
*attr
; /* member-uris attribute */
203 ipp_status_t status
; /* Request status */
204 char uri
[HTTP_MAX_URI
]; /* Device or printer URI */
205 const char *name
, /* Pointer to class name */
206 *ptr
; /* Pointer to CGI variable */
209 if (cgiGetVariable("PRINTER_LOCATION") == NULL
)
214 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
215 * following attributes:
218 * attributes-natural-language
224 request
->request
.op
.operation_id
= IPP_GET_PRINTER_ATTRIBUTES
;
225 request
->request
.op
.request_id
= 1;
227 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
228 "attributes-charset", NULL
, cupsLangEncoding(language
));
230 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
231 "attributes-natural-language", NULL
, language
->language
);
233 snprintf(uri
, sizeof(uri
), "ipp://localhost/classes/%s",
234 cgiGetVariable("PRINTER_NAME"));
235 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
239 * Do the request and get back a response...
242 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
244 ippSetCGIVars(response
, NULL
, NULL
);
249 * Update the location and description of an existing printer...
252 cgiCopyTemplateLang(stdout
, TEMPLATES
, "modify-class.tmpl", getenv("LANG"));
257 * Get the name, location, and description for a new printer...
260 cgiCopyTemplateLang(stdout
, TEMPLATES
, "add-class.tmpl", getenv("LANG"));
266 name
= cgiGetVariable("PRINTER_NAME");
270 for (ptr
= name
; *ptr
; ptr
++)
271 if (!isalnum(*ptr
) && *ptr
!= '_')
274 if (*ptr
|| ptr
== name
)
276 cgiSetVariable("ERROR", "The class name may only contain letters, "
277 "numbers, and the underscore.");
278 cgiCopyTemplateLang(stdout
, TEMPLATES
, "error.tmpl", getenv("LANG"));
282 if (cgiGetVariable("MEMBER_URIS") == NULL
)
285 * Build a CUPS_GET_PRINTERS request, which requires the
286 * following attributes:
289 * attributes-natural-language
295 request
->request
.op
.operation_id
= CUPS_GET_PRINTERS
;
296 request
->request
.op
.request_id
= 1;
298 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
299 "attributes-charset", NULL
, cupsLangEncoding(language
));
301 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
302 "attributes-natural-language", NULL
, language
->language
);
304 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
305 NULL
, "ipp://localhost/printers");
308 * Do the request and get back a response...
311 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
314 * Create MEMBER_URIS and MEMBER_NAMES arrays...
317 for (element
= 0, attr
= response
->attrs
;
320 if (attr
->name
&& strcmp(attr
->name
, "printer-uri-supported") == 0)
322 cgiSetArray("MEMBER_URIS", element
, attr
->values
[0].string
.text
);
326 for (element
= 0, attr
= response
->attrs
;
329 if (attr
->name
&& strcmp(attr
->name
, "printer-name") == 0)
331 cgiSetArray("MEMBER_NAMES", element
, attr
->values
[0].string
.text
);
335 num_printers
= cgiGetSize("MEMBER_URIS");
343 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
344 * following attributes:
347 * attributes-natural-language
353 request
->request
.op
.operation_id
= IPP_GET_PRINTER_ATTRIBUTES
;
354 request
->request
.op
.request_id
= 1;
356 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
357 "attributes-charset", NULL
, cupsLangEncoding(language
));
359 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
360 "attributes-natural-language", NULL
, language
->language
);
362 snprintf(uri
, sizeof(uri
), "ipp://localhost/classes/%s",
363 cgiGetVariable("PRINTER_NAME"));
364 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
368 * Do the request and get back a response...
371 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
373 if ((attr
= ippFindAttribute(response
, "member-uris", IPP_TAG_URI
)) != NULL
)
376 * Mark any current members in the class...
379 for (j
= 0; j
< num_printers
; j
++)
380 cgiSetArray("MEMBER_SELECTED", j
, "");
382 for (i
= 0; i
< attr
->num_values
; i
++)
383 for (j
= 0; j
< num_printers
; j
++)
384 if (strcmp(attr
->values
[i
].string
.text
, cgiGetArray("MEMBER_URIS", j
)) == 0)
386 cgiSetArray("MEMBER_SELECTED", j
, "SELECTED");
395 * Let the user choose...
398 cgiCopyTemplateLang(stdout
, TEMPLATES
, "choose-members.tmpl", getenv("LANG"));
403 * Build a CUPS_ADD_CLASS request, which requires the following
407 * attributes-natural-language
411 * printer-is-accepting-jobs
418 request
->request
.op
.operation_id
= CUPS_ADD_CLASS
;
419 request
->request
.op
.request_id
= 1;
421 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
422 "attributes-charset", NULL
, cupsLangEncoding(language
));
424 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
425 "attributes-natural-language", NULL
, language
->language
);
427 snprintf(uri
, sizeof(uri
), "ipp://localhost/classes/%s",
428 cgiGetVariable("PRINTER_NAME"));
429 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
432 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
433 NULL
, cgiGetVariable("PRINTER_LOCATION"));
435 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
436 NULL
, cgiGetVariable("PRINTER_INFO"));
438 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
440 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
443 if ((num_printers
= cgiGetSize("MEMBER_URIS")) > 0)
445 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "member-uris",
446 num_printers
, NULL
, NULL
);
447 for (i
= 0; i
< num_printers
; i
++)
448 attr
->values
[i
].string
.text
= strdup(cgiGetArray("MEMBER_URIS", i
));
452 * Do the request and get back a response...
455 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
)
457 status
= response
->request
.status
.status_code
;
461 status
= IPP_NOT_AUTHORIZED
;
463 if (status
> IPP_OK_CONFLICT
)
465 cgiSetVariable("ERROR", ippErrorString(status
));
466 cgiCopyTemplateLang(stdout
, TEMPLATES
, "error.tmpl", getenv("LANG"));
469 cgiCopyTemplateLang(stdout
, TEMPLATES
, "class-modified.tmpl", getenv("LANG"));
471 cgiCopyTemplateLang(stdout
, TEMPLATES
, "class-added.tmpl", getenv("LANG"));
477 * 'do_am_printer()' - Add or modify a printer.
481 do_am_printer(http_t
*http
, /* I - HTTP connection */
482 cups_lang_t
*language
, /* I - Client's language */
483 int modify
) /* I - Modify the printer? */
485 int i
; /* Looping var */
486 int element
; /* Element number */
487 ipp_attribute_t
*attr
, /* Current attribute */
488 *last
; /* Last attribute */
489 ipp_t
*request
, /* IPP request */
490 *response
, /* IPP response */
491 *oldinfo
; /* Old printer information */
492 ipp_status_t status
; /* Request status */
493 const char *var
; /* CGI variable */
494 char uri
[HTTP_MAX_URI
], /* Device or printer URI */
495 *uriptr
; /* Pointer into URI */
496 int maxrate
; /* Maximum baud rate */
497 char baudrate
[255]; /* Baud rate string */
498 char make
[255]; /* Make string */
499 const char *name
, /* Pointer to class name */
500 *ptr
; /* Pointer to CGI variable */
501 static int baudrates
[] = /* Baud rates */
519 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
520 * following attributes:
523 * attributes-natural-language
529 request
->request
.op
.operation_id
= IPP_GET_PRINTER_ATTRIBUTES
;
530 request
->request
.op
.request_id
= 1;
532 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
533 "attributes-charset", NULL
, cupsLangEncoding(language
));
535 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
536 "attributes-natural-language", NULL
, language
->language
);
538 snprintf(uri
, sizeof(uri
), "ipp://localhost/printers/%s",
539 cgiGetVariable("PRINTER_NAME"));
540 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
544 * Do the request and get back a response...
547 oldinfo
= cupsDoRequest(http
, request
, "/");
552 if ((name
= cgiGetVariable("PRINTER_NAME")) == NULL
)
557 * Update the location and description of an existing printer...
561 ippSetCGIVars(oldinfo
, NULL
, NULL
);
563 cgiCopyTemplateLang(stdout
, TEMPLATES
, "modify-printer.tmpl", getenv("LANG"));
568 * Get the name, location, and description for a new printer...
571 cgiCopyTemplateLang(stdout
, TEMPLATES
, "add-printer.tmpl", getenv("LANG"));
583 for (ptr
= name
; *ptr
; ptr
++)
584 if (!isalnum(*ptr
) && *ptr
!= '_')
587 if (*ptr
|| ptr
== name
)
589 cgiSetVariable("ERROR", "The printer name may only contain letters, "
590 "numbers, and the underscore.");
591 cgiCopyTemplateLang(stdout
, TEMPLATES
, "error.tmpl", getenv("LANG"));
595 if ((var
= cgiGetVariable("DEVICE_URI")) == NULL
)
598 * Build a CUPS_GET_DEVICES request, which requires the following
602 * attributes-natural-language
608 request
->request
.op
.operation_id
= CUPS_GET_DEVICES
;
609 request
->request
.op
.request_id
= 1;
611 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
612 "attributes-charset", NULL
, cupsLangEncoding(language
));
614 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
615 "attributes-natural-language", NULL
, language
->language
);
617 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
618 NULL
, "ipp://localhost/printers/");
621 * Do the request and get back a response...
624 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
626 ippSetCGIVars(response
, NULL
, NULL
);
631 * Let the user choose...
635 (attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
637 strncpy(uri
, attr
->values
[0].string
.text
, sizeof(uri
) - 1);
638 uri
[sizeof(uri
) - 1] = '\0';
639 if ((uriptr
= strchr(uri
, ':')) != NULL
&& strncmp(uriptr
, "://", 3) == 0)
642 cgiSetVariable("CURRENT_DEVICE_URI", uri
);
645 cgiCopyTemplateLang(stdout
, TEMPLATES
, "choose-device.tmpl", getenv("LANG"));
647 else if (strchr(var
, '/') == NULL
)
650 (attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
653 * Set the current device URI for the form to the old one...
656 if (strncmp(attr
->values
[0].string
.text
, var
, strlen(var
)) == 0)
657 cgiSetVariable("DEVICE_URI", attr
->values
[0].string
.text
);
661 * User needs to set the full URI...
664 cgiCopyTemplateLang(stdout
, TEMPLATES
, "choose-uri.tmpl", getenv("LANG"));
666 else if (strncmp(var
, "serial:", 7) == 0 && cgiGetVariable("BAUDRATE") == NULL
)
669 * Need baud rate, parity, etc.
672 if ((var
= strchr(var
, '?')) != NULL
&&
673 strncmp(var
, "?baud=", 6) == 0)
674 maxrate
= atoi(var
+ 6);
678 for (i
= 0; i
< 10; i
++)
679 if (baudrates
[i
] > maxrate
)
683 sprintf(baudrate
, "%d", baudrates
[i
]);
684 cgiSetArray("BAUDRATES", i
, baudrate
);
687 cgiCopyTemplateLang(stdout
, TEMPLATES
, "choose-serial.tmpl", getenv("LANG"));
689 else if ((var
= cgiGetVariable("PPD_NAME")) == NULL
)
694 * Get the PPD file...
697 int fd
; /* PPD file */
698 char filename
[1024]; /* PPD filename */
699 ppd_file_t
*ppd
; /* PPD information */
700 char buffer
[1024]; /* Buffer */
701 int bytes
; /* Number of bytes */
704 snprintf(uri
, sizeof(uri
), "/printers/%s.ppd", name
);
706 if (httpGet(http
, uri
))
709 while (httpUpdate(http
) == HTTP_CONTINUE
);
711 if ((fd
= cupsTempFd(filename
, sizeof(filename
))) >= 0)
713 while ((bytes
= httpRead(http
, buffer
, sizeof(buffer
))) > 0)
714 write(fd
, buffer
, bytes
);
718 if ((ppd
= ppdOpenFile(filename
)) != NULL
)
720 if (ppd
->manufacturer
)
721 cgiSetVariable("CURRENT_MAKE", ppd
->manufacturer
);
723 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd
->nickname
);
735 * Build a CUPS_GET_PPDS request, which requires the following
739 * attributes-natural-language
745 request
->request
.op
.operation_id
= CUPS_GET_PPDS
;
746 request
->request
.op
.request_id
= 1;
748 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
749 "attributes-charset", NULL
, cupsLangEncoding(language
));
751 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
752 "attributes-natural-language", NULL
, language
->language
);
754 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
755 NULL
, "ipp://localhost/printers/");
758 * Do the request and get back a response...
761 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
763 if ((var
= cgiGetVariable("PPD_MAKE")) == NULL
)
766 * Let the user choose a make...
769 for (element
= 0, attr
= response
->attrs
, last
= NULL
;
772 if (attr
->name
&& strcmp(attr
->name
, "ppd-make") == 0)
774 strcasecmp(last
->values
[0].string
.text
,
775 attr
->values
[0].string
.text
) != 0)
777 cgiSetArray("PPD_MAKE", element
, attr
->values
[0].string
.text
);
782 cgiCopyTemplateLang(stdout
, TEMPLATES
, "choose-make.tmpl",
788 * Let the user choose a model...
791 strncpy(make
, var
, sizeof(make
) - 1);
792 make
[sizeof(make
) - 1] = '\0';
794 ippSetCGIVars(response
, "ppd-make", make
);
795 cgiCopyTemplateLang(stdout
, TEMPLATES
, "choose-model.tmpl",
806 snprintf(message
, sizeof(message
), "Unable to get list of printer drivers: %s",
807 ippErrorString(cupsLastError()));
808 cgiSetVariable("ERROR", message
);
809 cgiCopyTemplateLang(stdout
, TEMPLATES
, "error.tmpl", getenv("LANG"));
815 * Build a CUPS_ADD_PRINTER request, which requires the following
819 * attributes-natural-language
825 * printer-is-accepting-jobs
831 request
->request
.op
.operation_id
= CUPS_ADD_PRINTER
;
832 request
->request
.op
.request_id
= 1;
834 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
835 "attributes-charset", NULL
, cupsLangEncoding(language
));
837 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
838 "attributes-natural-language", NULL
, language
->language
);
840 snprintf(uri
, sizeof(uri
), "ipp://localhost/printers/%s",
841 cgiGetVariable("PRINTER_NAME"));
842 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
845 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
846 NULL
, cgiGetVariable("PRINTER_LOCATION"));
848 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
849 NULL
, cgiGetVariable("PRINTER_INFO"));
851 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
, "ppd-name",
852 NULL
, cgiGetVariable("PPD_NAME"));
854 strncpy(uri
, cgiGetVariable("DEVICE_URI"), sizeof(uri
) - 1);
855 uri
[sizeof(uri
) - 1] = '\0';
856 if (strncmp(uri
, "serial:", 7) == 0)
859 * Update serial port URI to include baud rate, etc.
862 if ((uriptr
= strchr(uri
, '?')) == NULL
)
863 uriptr
= uri
+ strlen(uri
);
865 snprintf(uriptr
, sizeof(uri
) - (uriptr
- uri
),
866 "?baud=%s+bits=%s+parity=%s+flow=%s",
867 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
868 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
871 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "device-uri",
874 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
876 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
880 * Do the request and get back a response...
883 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
)
885 status
= response
->request
.status
.status_code
;
889 status
= IPP_NOT_AUTHORIZED
;
891 if (status
> IPP_OK_CONFLICT
)
893 cgiSetVariable("ERROR", ippErrorString(status
));
894 cgiCopyTemplateLang(stdout
, TEMPLATES
, "error.tmpl", getenv("LANG"));
897 cgiCopyTemplateLang(stdout
, TEMPLATES
, "printer-modified.tmpl", getenv("LANG"));
899 cgiCopyTemplateLang(stdout
, TEMPLATES
, "printer-added.tmpl", getenv("LANG"));
908 * 'do_config_printer()' - Configure the default options for a printer.
912 do_config_printer(http_t
*http
, /* I - HTTP connection */
913 cups_lang_t
*language
)/* I - Client's language */
915 int i
, j
, k
; /* Looping vars */
916 int have_options
; /* Have options? */
917 ipp_t
*request
, /* IPP request */
918 *response
; /* IPP response */
919 ipp_attribute_t
*attr
; /* IPP attribute */
920 char uri
[HTTP_MAX_URI
]; /* Job URI */
921 const char *var
; /* Variable value */
922 const char *printer
; /* Printer printer name */
923 ipp_status_t status
; /* Operation status... */
924 const char *filename
; /* PPD filename */
925 char tempfile
[1024]; /* Temporary filename */
926 FILE *in
, /* Input file */
927 *out
; /* Output file */
928 int outfd
; /* Output file descriptor */
929 char line
[1024]; /* Line from PPD file */
930 char keyword
[1024], /* Keyword from Default line */
931 *keyptr
; /* Pointer into keyword... */
932 ppd_file_t
*ppd
; /* PPD file */
933 ppd_group_t
*group
; /* Option group */
934 ppd_option_t
*option
; /* Option */
938 * Get the printer name...
941 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
942 snprintf(uri
, sizeof(uri
), "ipp://localhost/printers/%s", printer
);
945 cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND
));
946 cgiCopyTemplateLang(stdout
, TEMPLATES
, "error.tmpl", getenv("LANG"));
951 * Get the PPD file...
954 if ((filename
= cupsGetPPD(printer
)) == NULL
)
956 cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND
));
957 cgiCopyTemplateLang(stdout
, TEMPLATES
, "error.tmpl", getenv("LANG"));
961 ppd
= ppdOpenFile(filename
);
963 if (cgiGetVariable("job_sheets_start") != NULL
||
964 cgiGetVariable("job_sheets_end") != NULL
)
969 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
970 i
> 0 && !have_options
;
972 for (j
= group
->num_options
, option
= group
->options
;
975 if ((var
= cgiGetVariable(option
->keyword
)) != NULL
)
984 * Show the options to the user...
987 cgiCopyTemplateLang(stdout
, TEMPLATES
, "config-printer.tmpl",
990 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
994 cgiSetVariable("GROUP", group
->text
);
995 cgiCopyTemplateLang(stdout
, TEMPLATES
, "option-header.tmpl",
998 for (j
= group
->num_options
, option
= group
->options
;
1002 if (strcmp(option
->keyword
, "PageRegion") == 0)
1005 cgiSetVariable("KEYWORD", option
->keyword
);
1006 cgiSetVariable("KEYTEXT", option
->text
);
1007 cgiSetVariable("DEFCHOICE", option
->defchoice
);
1009 cgiSetSize("CHOICES", option
->num_choices
);
1010 cgiSetSize("TEXT", option
->num_choices
);
1011 for (k
= 0; k
< option
->num_choices
; k
++)
1013 cgiSetArray("CHOICES", k
, option
->choices
[k
].choice
);
1014 cgiSetArray("TEXT", k
, option
->choices
[k
].text
);
1019 case PPD_UI_BOOLEAN
:
1020 cgiCopyTemplateLang(stdout
, TEMPLATES
, "option-boolean.tmpl",
1023 case PPD_UI_PICKONE
:
1024 cgiCopyTemplateLang(stdout
, TEMPLATES
, "option-pickone.tmpl",
1027 case PPD_UI_PICKMANY
:
1028 cgiCopyTemplateLang(stdout
, TEMPLATES
, "option-pickmany.tmpl",
1034 cgiCopyTemplateLang(stdout
, TEMPLATES
, "option-trailer.tmpl",
1039 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
1040 * following attributes:
1042 * attributes-charset
1043 * attributes-natural-language
1049 request
->request
.op
.operation_id
= IPP_GET_PRINTER_ATTRIBUTES
;
1050 request
->request
.op
.request_id
= 1;
1052 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1053 "attributes-charset", NULL
, cupsLangEncoding(language
));
1055 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1056 "attributes-natural-language", NULL
, language
->language
);
1058 snprintf(uri
, sizeof(uri
), "ipp://localhost/printers/%s",
1059 cgiGetVariable("PRINTER_NAME"));
1060 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1064 * Do the request and get back a response...
1067 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1069 if ((attr
= ippFindAttribute(response
, "job-sheets-supported", IPP_TAG_ZERO
)) != NULL
)
1072 * Add the job sheets options...
1075 cgiSetVariable("GROUP", "Banners");
1076 cgiCopyTemplateLang(stdout
, TEMPLATES
, "option-header.tmpl",
1079 cgiSetSize("CHOICES", attr
->num_values
);
1080 cgiSetSize("TEXT", attr
->num_values
);
1081 for (k
= 0; k
< attr
->num_values
; k
++)
1083 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
1084 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
1087 attr
= ippFindAttribute(response
, "job-sheets-default", IPP_TAG_ZERO
);
1089 cgiSetVariable("KEYWORD", "job_sheets_start");
1090 cgiSetVariable("KEYTEXT", "Starting Banner");
1091 cgiSetVariable("DEFCHOICE", attr
== NULL
?
1092 "" : attr
->values
[0].string
.text
);
1094 cgiCopyTemplateLang(stdout
, TEMPLATES
, "option-pickone.tmpl",
1097 cgiSetVariable("KEYWORD", "job_sheets_end");
1098 cgiSetVariable("KEYTEXT", "Ending Banner");
1099 cgiSetVariable("DEFCHOICE", attr
== NULL
&& attr
->num_values
> 1 ?
1100 "" : attr
->values
[1].string
.text
);
1102 cgiCopyTemplateLang(stdout
, TEMPLATES
, "option-pickone.tmpl",
1105 cgiCopyTemplateLang(stdout
, TEMPLATES
, "option-trailer.tmpl",
1109 ippDelete(response
);
1112 cgiCopyTemplateLang(stdout
, TEMPLATES
, "config-printer2.tmpl",
1118 * Set default options...
1121 outfd
= cupsTempFd(tempfile
, sizeof(tempfile
));
1122 in
= fopen(filename
, "rb");
1123 out
= fdopen(outfd
, "wb");
1125 if (outfd
< 0 || in
== NULL
|| out
== NULL
)
1127 cgiSetVariable("ERROR", strerror(errno
));
1128 cgiCopyTemplateLang(stdout
, TEMPLATES
, "error.tmpl", getenv("LANG"));
1133 while (get_line(line
, sizeof(line
), in
) != NULL
)
1135 if (strncmp(line
, "*Default", 8) != 0)
1136 fprintf(out
, "%s\n", line
);
1140 * Get default option name...
1143 strncpy(keyword
, line
+ 8, sizeof(keyword
) - 1);
1144 keyword
[sizeof(keyword
) - 1] = '\0';
1146 for (keyptr
= keyword
; *keyptr
; keyptr
++)
1147 if (*keyptr
== ':' || isspace(*keyptr
))
1152 if (strcmp(keyword
, "PageRegion") == 0)
1153 var
= cgiGetVariable("PageSize");
1155 var
= cgiGetVariable(keyword
);
1158 fprintf(out
, "*Default%s: %s\n", keyword
, var
);
1160 fprintf(out
, "%s\n", line
);
1169 * Build a CUPS_ADD_PRINTER request, which requires the following
1172 * attributes-charset
1173 * attributes-natural-language
1175 * job-sheets-default
1181 request
->request
.op
.operation_id
= CUPS_ADD_PRINTER
;
1182 request
->request
.op
.request_id
= 1;
1184 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1185 "attributes-charset", NULL
, cupsLangEncoding(language
));
1187 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1188 "attributes-natural-language", NULL
, language
->language
);
1190 snprintf(uri
, sizeof(uri
), "ipp://localhost/printers/%s",
1191 cgiGetVariable("PRINTER_NAME"));
1192 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1195 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
1196 "job-sheets-default", 2, NULL
, NULL
);
1197 attr
->values
[0].string
.text
= strdup(cgiGetVariable("job_sheets_start"));
1198 attr
->values
[1].string
.text
= strdup(cgiGetVariable("job_sheets_end"));
1201 * Do the request and get back a response...
1204 if ((response
= cupsDoFileRequest(http
, request
, "/admin/", tempfile
)) != NULL
)
1206 status
= response
->request
.status
.status_code
;
1207 ippDelete(response
);
1210 status
= IPP_NOT_AUTHORIZED
;
1212 if (status
> IPP_OK_CONFLICT
)
1214 cgiSetVariable("ERROR", ippErrorString(status
));
1215 cgiCopyTemplateLang(stdout
, TEMPLATES
, "error.tmpl", getenv("LANG"));
1218 cgiCopyTemplateLang(stdout
, TEMPLATES
, "printer-configured.tmpl", getenv("LANG"));
1228 * 'do_delete_class()' - Delete a class...
1232 do_delete_class(http_t
*http
, /* I - HTTP connection */
1233 cups_lang_t
*language
) /* I - Client's language */
1235 ipp_t
*request
, /* IPP request */
1236 *response
; /* IPP response */
1237 char uri
[HTTP_MAX_URI
]; /* Job URI */
1238 const char *pclass
; /* Printer class name */
1239 ipp_status_t status
; /* Operation status... */
1242 if (cgiGetVariable("CONFIRM") == NULL
)
1244 cgiCopyTemplateLang(stdout
, TEMPLATES
, "class-confirm.tmpl", getenv("LANG"));
1248 if ((pclass
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1249 snprintf(uri
, sizeof(uri
), "ipp://localhost/classes/%s", pclass
);
1252 cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND
));
1253 cgiCopyTemplateLang(stdout
, TEMPLATES
, "error.tmpl", getenv("LANG"));
1258 * Build a CUPS_DELETE_CLASS request, which requires the following
1261 * attributes-charset
1262 * attributes-natural-language
1268 request
->request
.op
.operation_id
= CUPS_DELETE_CLASS
;
1269 request
->request
.op
.request_id
= 1;
1271 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1272 "attributes-charset", NULL
, cupsLangEncoding(language
));
1274 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1275 "attributes-natural-language", NULL
, language
->language
);
1277 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1281 * Do the request and get back a response...
1284 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
)
1286 status
= response
->request
.status
.status_code
;
1288 ippDelete(response
);
1293 if (status
> IPP_OK_CONFLICT
)
1295 cgiSetVariable("ERROR", ippErrorString(status
));
1296 cgiCopyTemplateLang(stdout
, TEMPLATES
, "error.tmpl", getenv("LANG"));
1299 cgiCopyTemplateLang(stdout
, TEMPLATES
, "class-deleted.tmpl", getenv("LANG"));
1304 * 'do_delete_printer()' - Delete a printer...
1308 do_delete_printer(http_t
*http
, /* I - HTTP connection */
1309 cups_lang_t
*language
)/* I - Client's language */
1311 ipp_t
*request
, /* IPP request */
1312 *response
; /* IPP response */
1313 char uri
[HTTP_MAX_URI
]; /* Job URI */
1314 const char *printer
; /* Printer printer name */
1315 ipp_status_t status
; /* Operation status... */
1318 if (cgiGetVariable("CONFIRM") == NULL
)
1320 cgiCopyTemplateLang(stdout
, TEMPLATES
, "printer-confirm.tmpl", getenv("LANG"));
1324 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1325 snprintf(uri
, sizeof(uri
), "ipp://localhost/printers/%s", printer
);
1328 cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND
));
1329 cgiCopyTemplateLang(stdout
, TEMPLATES
, "error.tmpl", getenv("LANG"));
1334 * Build a CUPS_DELETE_PRINTER request, which requires the following
1337 * attributes-charset
1338 * attributes-natural-language
1344 request
->request
.op
.operation_id
= CUPS_DELETE_PRINTER
;
1345 request
->request
.op
.request_id
= 1;
1347 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1348 "attributes-charset", NULL
, cupsLangEncoding(language
));
1350 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1351 "attributes-natural-language", NULL
, language
->language
);
1353 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1357 * Do the request and get back a response...
1360 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
)
1362 status
= response
->request
.status
.status_code
;
1364 ippDelete(response
);
1369 if (status
> IPP_OK_CONFLICT
)
1371 cgiSetVariable("ERROR", ippErrorString(status
));
1372 cgiCopyTemplateLang(stdout
, TEMPLATES
, "error.tmpl", getenv("LANG"));
1375 cgiCopyTemplateLang(stdout
, TEMPLATES
, "printer-deleted.tmpl", getenv("LANG"));
1380 * 'do_job_op()' - Do a job operation.
1384 do_job_op(http_t
*http
, /* I - HTTP connection */
1385 cups_lang_t
*language
, /* I - Client's language */
1386 ipp_op_t op
) /* I - Operation to perform */
1388 ipp_t
*request
, /* IPP request */
1389 *response
; /* IPP response */
1390 char uri
[HTTP_MAX_URI
]; /* Job URI */
1391 const char *job
; /* Job ID */
1392 const char *printer
; /* Printer name (purge-jobs) */
1393 ipp_status_t status
; /* Operation status... */
1396 if ((job
= cgiGetVariable("JOB_ID")) != NULL
)
1397 snprintf(uri
, sizeof(uri
), "ipp://localhost/jobs/%s", job
);
1398 else if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1399 snprintf(uri
, sizeof(uri
), "ipp://localhost/printers/%s", printer
);
1402 cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND
));
1403 cgiCopyTemplateLang(stdout
, TEMPLATES
, "error.tmpl", getenv("LANG"));
1408 * Build a job request, which requires the following
1411 * attributes-charset
1412 * attributes-natural-language
1413 * job-uri or printer-uri (purge-jobs)
1414 * requesting-user-name
1419 request
->request
.op
.operation_id
= op
;
1420 request
->request
.op
.request_id
= 1;
1422 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1423 "attributes-charset", NULL
, cupsLangEncoding(language
));
1425 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1426 "attributes-natural-language", NULL
, language
->language
);
1429 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri",
1432 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1435 if (getenv("REMOTE_USER") != NULL
)
1436 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1437 NULL
, getenv("REMOTE_USER"));
1439 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1443 * Do the request and get back a response...
1446 if ((response
= cupsDoRequest(http
, request
, "/jobs")) != NULL
)
1448 status
= response
->request
.status
.status_code
;
1450 ippDelete(response
);
1455 if (status
> IPP_OK_CONFLICT
)
1457 cgiSetVariable("ERROR", ippErrorString(status
));
1458 cgiCopyTemplateLang(stdout
, TEMPLATES
, "error.tmpl", getenv("LANG"));
1460 else if (op
== IPP_CANCEL_JOB
)
1461 cgiCopyTemplateLang(stdout
, TEMPLATES
, "job-cancel.tmpl", getenv("LANG"));
1462 else if (op
== IPP_HOLD_JOB
)
1463 cgiCopyTemplateLang(stdout
, TEMPLATES
, "job-hold.tmpl", getenv("LANG"));
1464 else if (op
== IPP_RELEASE_JOB
)
1465 cgiCopyTemplateLang(stdout
, TEMPLATES
, "job-release.tmpl", getenv("LANG"));
1466 else if (op
== IPP_RESTART_JOB
)
1467 cgiCopyTemplateLang(stdout
, TEMPLATES
, "job-restart.tmpl", getenv("LANG"));
1472 * 'do_printer_op()' - Do a printer operation.
1476 do_printer_op(http_t
*http
, /* I - HTTP connection */
1477 cups_lang_t
*language
, /* I - Client's language */
1478 ipp_op_t op
) /* I - Operation to perform */
1480 ipp_t
*request
, /* IPP request */
1481 *response
; /* IPP response */
1482 char uri
[HTTP_MAX_URI
]; /* Printer URI */
1483 const char *printer
; /* Printer name (purge-jobs) */
1484 ipp_status_t status
; /* Operation status... */
1487 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1488 snprintf(uri
, sizeof(uri
), "ipp://localhost/printers/%s", printer
);
1491 cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND
));
1492 cgiCopyTemplateLang(stdout
, TEMPLATES
, "error.tmpl", getenv("LANG"));
1497 * Build a printer request, which requires the following
1500 * attributes-charset
1501 * attributes-natural-language
1507 request
->request
.op
.operation_id
= op
;
1508 request
->request
.op
.request_id
= 1;
1510 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1511 "attributes-charset", NULL
, cupsLangEncoding(language
));
1513 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1514 "attributes-natural-language", NULL
, language
->language
);
1516 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1520 * Do the request and get back a response...
1523 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
)
1525 status
= response
->request
.status
.status_code
;
1527 ippDelete(response
);
1532 if (status
> IPP_OK_CONFLICT
)
1534 cgiSetVariable("ERROR", ippErrorString(status
));
1535 cgiCopyTemplateLang(stdout
, TEMPLATES
, "error.tmpl", getenv("LANG"));
1537 else if (op
== IPP_PAUSE_PRINTER
)
1538 cgiCopyTemplateLang(stdout
, TEMPLATES
, "printer-stop.tmpl", getenv("LANG"));
1539 else if (op
== IPP_RESUME_PRINTER
)
1540 cgiCopyTemplateLang(stdout
, TEMPLATES
, "printer-start.tmpl", getenv("LANG"));
1541 else if (op
== CUPS_ACCEPT_JOBS
)
1542 cgiCopyTemplateLang(stdout
, TEMPLATES
, "printer-accept.tmpl", getenv("LANG"));
1543 else if (op
== CUPS_REJECT_JOBS
)
1544 cgiCopyTemplateLang(stdout
, TEMPLATES
, "printer-reject.tmpl", getenv("LANG"));
1549 * 'get_line()' - Get a line that is terminated by a LF, CR, or CR LF.
1552 static char * /* O - Pointer to buf or NULL on EOF */
1553 get_line(char *buf
, /* I - Line buffer */
1554 int length
, /* I - Length of buffer */
1555 FILE *fp
) /* I - File to read from */
1557 char *bufptr
; /* Pointer into buffer */
1558 int ch
; /* Character from file */
1564 while ((ch
= getc(fp
)) != EOF
)
1568 else if (ch
== '\r')
1575 if (ch
!= '\n' && ch
!= EOF
)
1597 * End of "$Id: admin.c,v 1.22 2001/03/05 21:37:33 mike Exp $".