2 * CGI <-> IPP variable routines for CUPS.
4 * Copyright 2007-2016 by Apple Inc.
5 * Copyright 1997-2007 by Easy Software Products.
7 * These coded instructions, statements, and computer programs are the
8 * property of Apple Inc. and are protected by Federal copyright
9 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
10 * which should have been included with this file. If this file is
11 * file is missing or damaged, see the license at "http://www.cups.org/".
15 * Include necessary headers...
18 #include "cgi-private.h"
22 * 'cgiGetAttributes()' - Get the list of attributes that are needed
23 * by the template file.
27 cgiGetAttributes(ipp_t
*request
, /* I - IPP request */
28 const char *tmpl
) /* I - Base filename */
30 int num_attrs
; /* Number of attributes */
31 char *attrs
[1000]; /* Attributes */
32 int i
; /* Looping var */
33 char filename
[1024], /* Filename */
34 locale
[16]; /* Locale name */
35 const char *directory
, /* Directory */
37 FILE *in
; /* Input file */
38 int ch
; /* Character from file */
39 char name
[255], /* Name of variable */
40 *nameptr
; /* Pointer into name */
44 * Convert the language to a locale name...
47 if ((lang
= getenv("LANG")) != NULL
)
49 for (i
= 0; lang
[i
] && i
< 15; i
++)
50 if (isalnum(lang
[i
] & 255))
51 locale
[i
] = (char)tolower(lang
[i
]);
61 * See if we have a template file for this language...
64 directory
= cgiGetTemplateDir();
66 snprintf(filename
, sizeof(filename
), "%s/%s/%s", directory
, locale
, tmpl
);
67 if (access(filename
, 0))
71 snprintf(filename
, sizeof(filename
), "%s/%s/%s", directory
, locale
, tmpl
);
72 if (access(filename
, 0))
73 snprintf(filename
, sizeof(filename
), "%s/%s", directory
, tmpl
);
77 * Open the template file...
80 if ((in
= fopen(filename
, "r")) == NULL
)
84 * Loop through the file adding attribute names as needed...
88 attrs
[0] = NULL
; /* Eliminate compiler warning */
90 while ((ch
= getc(in
)) != EOF
)
93 else if (ch
== '{' && num_attrs
< (int)(sizeof(attrs
) / sizeof(attrs
[0])))
99 for (nameptr
= name
; (ch
= getc(in
)) != EOF
;)
100 if (strchr("}]<>=!~ \t\n", ch
))
102 else if (nameptr
> name
&& ch
== '?')
104 else if (nameptr
< (name
+ sizeof(name
) - 1))
109 *nameptr
++ = (char)ch
;
114 if (!strncmp(name
, "printer_state_history", 21))
115 strlcpy(name
, "printer_state_history", sizeof(name
));
118 * Possibly add it to the list of attributes...
121 for (i
= 0; i
< num_attrs
; i
++)
122 if (!strcmp(attrs
[i
], name
))
127 attrs
[num_attrs
] = strdup(name
);
133 * If we have attributes, add a requested-attributes attribute to the
139 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
140 "requested-attributes", num_attrs
, NULL
, (const char **)attrs
);
142 for (i
= 0; i
< num_attrs
; i
++)
151 * 'cgiGetIPPObjects()' - Get the objects in an IPP response.
154 cups_array_t
* /* O - Array of objects */
155 cgiGetIPPObjects(ipp_t
*response
, /* I - IPP response */
156 void *search
) /* I - Search filter */
158 int i
; /* Looping var */
159 cups_array_t
*objs
; /* Array of objects */
160 ipp_attribute_t
*attr
, /* Current attribute */
161 *first
; /* First attribute for object */
162 ipp_tag_t group
; /* Current group tag */
163 int add
; /* Add this object to the array? */
169 for (add
= 0, first
= NULL
, objs
= cupsArrayNew(NULL
, NULL
),
170 group
= IPP_TAG_ZERO
, attr
= response
->attrs
;
174 if (attr
->group_tag
!= group
)
176 group
= attr
->group_tag
;
178 if (group
!= IPP_TAG_ZERO
&& group
!= IPP_TAG_OPERATION
)
183 else if (add
&& first
)
185 cupsArrayAdd(objs
, first
);
192 if (attr
->name
&& attr
->group_tag
!= IPP_TAG_OPERATION
&& !add
)
197 * Add all objects if there is no search...
205 * Check the search string against the string and integer values.
208 switch (attr
->value_tag
)
210 case IPP_TAG_TEXTLANG
:
211 case IPP_TAG_NAMELANG
:
214 case IPP_TAG_KEYWORD
:
216 case IPP_TAG_MIMETYPE
:
217 for (i
= 0; !add
&& i
< attr
->num_values
; i
++)
218 if (cgiDoSearch(search
, attr
->values
[i
].string
.text
))
222 case IPP_TAG_INTEGER
:
223 if (!strncmp(ippGetName(attr
), "time-at-", 8))
224 break; /* Ignore time-at-xxx */
226 for (i
= 0; !add
&& i
< attr
->num_values
; i
++)
228 char buf
[255]; /* Number buffer */
231 sprintf(buf
, "%d", attr
->values
[i
].integer
);
233 if (cgiDoSearch(search
, buf
))
246 cupsArrayAdd(objs
, first
);
253 * 'cgiMoveJobs()' - Move one or more jobs.
255 * At least one of dest or job_id must be non-zero/NULL.
259 cgiMoveJobs(http_t
*http
, /* I - Connection to server */
260 const char *dest
, /* I - Destination or NULL */
261 int job_id
) /* I - Job ID or 0 for all */
263 int i
; /* Looping var */
264 const char *user
; /* Username */
265 ipp_t
*request
, /* IPP request */
266 *response
; /* IPP response */
267 ipp_attribute_t
*attr
; /* Current attribute */
268 const char *name
; /* Destination name */
269 const char *job_printer_uri
; /* JOB_PRINTER_URI form variable */
270 char current_dest
[1024]; /* Current destination */
274 * Make sure we have a username...
277 if ((user
= getenv("REMOTE_USER")) == NULL
)
279 puts("Status: 401\n");
284 * See if the user has already selected a new destination...
287 if ((job_printer_uri
= cgiGetVariable("JOB_PRINTER_URI")) == NULL
)
290 * Make sure necessary form variables are set...
295 char temp
[255]; /* Temporary string */
298 sprintf(temp
, "%d", job_id
);
299 cgiSetVariable("JOB_ID", temp
);
303 cgiSetVariable("PRINTER_NAME", dest
);
306 * No new destination specified, show the user what the available
307 * printers/classes are...
313 * Get the current destination for job N...
316 char job_uri
[1024]; /* Job URI */
319 request
= ippNewRequest(IPP_GET_JOB_ATTRIBUTES
);
321 snprintf(job_uri
, sizeof(job_uri
), "ipp://localhost/jobs/%d", job_id
);
322 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri",
324 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
325 "requested-attributes", NULL
, "job-printer-uri");
327 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
329 if ((attr
= ippFindAttribute(response
, "job-printer-uri",
330 IPP_TAG_URI
)) != NULL
)
333 * Pull the name from the URI...
336 strlcpy(current_dest
, strrchr(attr
->values
[0].string
.text
, '/') + 1,
337 sizeof(current_dest
));
347 * Couldn't get the current destination...
350 cgiStartHTML(cgiText(_("Move Job")));
351 cgiShowIPPError(_("Unable to find destination for job"));
358 * Get the list of available destinations...
361 request
= ippNewRequest(CUPS_GET_PRINTERS
);
363 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
364 "requested-attributes", NULL
, "printer-uri-supported");
367 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
368 "requesting-user-name", NULL
, user
);
370 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
372 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
373 CUPS_PRINTER_SCANNER
);
375 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
377 for (i
= 0, attr
= ippFindAttribute(response
, "printer-uri-supported",
380 attr
= ippFindNextAttribute(response
, "printer-uri-supported",
384 * Pull the name from the URI...
387 name
= strrchr(attr
->values
[0].string
.text
, '/') + 1;
390 * If the name is not the same as the current destination, add it!
393 if (_cups_strcasecmp(name
, dest
))
395 cgiSetArray("JOB_PRINTER_URI", i
, attr
->values
[0].string
.text
);
396 cgiSetArray("JOB_PRINTER_NAME", i
, name
);
409 cgiStartHTML(cgiText(_("Move Job")));
411 cgiStartHTML(cgiText(_("Move All Jobs")));
413 if (cgiGetSize("JOB_PRINTER_NAME") > 0)
414 cgiCopyTemplateLang("job-move.tmpl");
418 cgiSetVariable("MESSAGE", cgiText(_("Unable to move job")));
420 cgiSetVariable("MESSAGE", cgiText(_("Unable to move jobs")));
422 cgiSetVariable("ERROR", cgiText(_("No destinations added.")));
423 cgiCopyTemplateLang("error.tmpl");
429 * Try moving the job or jobs...
432 char uri
[1024], /* Job/printer URI */
433 resource
[1024], /* Post resource */
434 refresh
[1024]; /* Refresh URL */
435 const char *job_printer_name
; /* New printer name */
438 request
= ippNewRequest(CUPS_MOVE_JOB
);
446 snprintf(resource
, sizeof(resource
), "/jobs/%d", job_id
);
448 snprintf(uri
, sizeof(uri
), "ipp://localhost/jobs/%d", job_id
);
449 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri",
455 * Move all active jobs on a destination...
458 snprintf(resource
, sizeof(resource
), "/%s/%s",
459 cgiGetVariable("SECTION"), dest
);
461 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
462 "localhost", ippPort(), "/%s/%s",
463 cgiGetVariable("SECTION"), dest
);
464 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
468 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-printer-uri",
469 NULL
, job_printer_uri
);
471 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
472 "requesting-user-name", NULL
, user
);
474 ippDelete(cupsDoRequest(http
, request
, resource
));
477 * Show the results...
480 job_printer_name
= strrchr(job_printer_uri
, '/') + 1;
482 if (cupsLastError() <= IPP_OK_CONFLICT
)
484 const char *path
= strstr(job_printer_uri
, "/printers/");
487 path
= strstr(job_printer_uri
, "/classes/");
488 cgiSetVariable("IS_CLASS", "YES");
493 cgiFormEncode(uri
, path
, sizeof(uri
));
494 snprintf(refresh
, sizeof(refresh
), "2;URL=%s", uri
);
495 cgiSetVariable("refresh_page", refresh
);
500 cgiStartHTML(cgiText(_("Move Job")));
502 cgiStartHTML(cgiText(_("Move All Jobs")));
504 if (cupsLastError() > IPP_OK_CONFLICT
)
507 cgiShowIPPError(_("Unable to move job"));
509 cgiShowIPPError(_("Unable to move jobs"));
513 cgiSetVariable("JOB_PRINTER_NAME", job_printer_name
);
514 cgiCopyTemplateLang("job-moved.tmpl");
523 * 'cgiPrintCommand()' - Print a CUPS command job.
527 cgiPrintCommand(http_t
*http
, /* I - Connection to server */
528 const char *dest
, /* I - Destination printer */
529 const char *command
, /* I - Command to send */
530 const char *title
) /* I - Page/job title */
532 int job_id
; /* Command file job */
533 char uri
[HTTP_MAX_URI
], /* Job URI */
534 resource
[1024], /* Printer resource path */
535 refresh
[1024], /* Refresh URL */
536 command_file
[1024]; /* Command "file" */
537 http_status_t status
; /* Document status */
538 cups_option_t hold_option
; /* job-hold-until option */
539 const char *user
; /* User name */
540 ipp_t
*request
, /* Get-Job-Attributes request */
541 *response
; /* Get-Job-Attributes response */
542 ipp_attribute_t
*attr
; /* Current job attribute */
543 static const char * const job_attrs
[] =/* Job attributes we want */
546 "job-printer-state-message"
551 * Create the CUPS command file...
554 snprintf(command_file
, sizeof(command_file
), "#CUPS-COMMAND\n%s\n", command
);
560 if (cgiSupportsMultipart())
564 cgiCopyTemplateLang("command.tmpl");
570 * Send the command file job...
573 hold_option
.name
= "job-hold-until";
574 hold_option
.value
= "no-hold";
576 if ((user
= getenv("REMOTE_USER")) != NULL
)
579 cupsSetUser("anonymous");
581 if ((job_id
= cupsCreateJob(http
, dest
, title
,
582 1, &hold_option
)) < 1)
584 cgiSetVariable("MESSAGE", cgiText(_("Unable to send command to printer driver")));
585 cgiSetVariable("ERROR", cupsLastErrorString());
587 cgiCopyTemplateLang("error.tmpl");
590 if (cgiSupportsMultipart())
595 status
= cupsStartDocument(http
, dest
, job_id
, NULL
, CUPS_FORMAT_COMMAND
, 1);
596 if (status
== HTTP_CONTINUE
)
597 status
= cupsWriteRequestData(http
, command_file
,
598 strlen(command_file
));
599 if (status
== HTTP_CONTINUE
)
600 cupsFinishDocument(http
, dest
);
602 if (cupsLastError() >= IPP_REDIRECTION_OTHER_SITE
)
604 cgiSetVariable("MESSAGE", cgiText(_("Unable to send command to printer driver")));
605 cgiSetVariable("ERROR", cupsLastErrorString());
607 cgiCopyTemplateLang("error.tmpl");
610 if (cgiSupportsMultipart())
613 cupsCancelJob(dest
, job_id
);
618 * Wait for the job to complete...
621 if (cgiSupportsMultipart())
626 * Get the current job state...
629 snprintf(uri
, sizeof(uri
), "ipp://localhost/jobs/%d", job_id
);
630 request
= ippNewRequest(IPP_GET_JOB_ATTRIBUTES
);
631 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri",
634 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
635 "requesting-user-name", NULL
, user
);
636 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
637 "requested-attributes", 2, NULL
, job_attrs
);
639 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
640 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
642 attr
= ippFindAttribute(response
, "job-state", IPP_TAG_ENUM
);
643 if (!attr
|| attr
->values
[0].integer
>= IPP_JOB_STOPPED
||
644 attr
->values
[0].integer
== IPP_JOB_HELD
)
651 * Job not complete, so update the status...
657 cgiCopyTemplateLang("command.tmpl");
666 * Send the final page that reloads the printer's page...
669 snprintf(resource
, sizeof(resource
), "/printers/%s", dest
);
671 cgiFormEncode(uri
, resource
, sizeof(uri
));
672 snprintf(refresh
, sizeof(refresh
), "5;URL=%s", uri
);
673 cgiSetVariable("refresh_page", refresh
);
676 cgiCopyTemplateLang("command.tmpl");
679 if (cgiSupportsMultipart())
685 * 'cgiPrintTestPage()' - Print a test page.
689 cgiPrintTestPage(http_t
*http
, /* I - Connection to server */
690 const char *dest
) /* I - Destination printer/class */
692 ipp_t
*request
, /* IPP request */
693 *response
; /* IPP response */
694 char uri
[HTTP_MAX_URI
], /* Printer URI */
695 resource
[1024], /* POST resource path */
696 refresh
[1024], /* Refresh URL */
697 filename
[1024]; /* Test page filename */
698 const char *datadir
; /* CUPS_DATADIR env var */
699 const char *user
; /* Username */
703 * See who is logged in...
706 user
= getenv("REMOTE_USER");
709 * Locate the test page file...
712 if ((datadir
= getenv("CUPS_DATADIR")) == NULL
)
713 datadir
= CUPS_DATADIR
;
715 snprintf(filename
, sizeof(filename
), "%s/data/testprint", datadir
);
718 * Point to the printer/class...
721 snprintf(resource
, sizeof(resource
), "/%s/%s", cgiGetVariable("SECTION"),
724 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
725 "localhost", ippPort(), "/%s/%s", cgiGetVariable("SECTION"),
729 * Build an IPP_PRINT_JOB request, which requires the following
733 * attributes-natural-language
735 * requesting-user-name
738 request
= ippNewRequest(IPP_PRINT_JOB
);
740 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
744 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
745 "requesting-user-name", NULL
, user
);
747 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "job-name",
751 * Do the request and get back a response...
754 if ((response
= cupsDoFileRequest(http
, request
, resource
,
757 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
762 if (cupsLastError() <= IPP_OK_CONFLICT
)
765 * Automatically reload the printer status page...
768 cgiFormEncode(uri
, resource
, sizeof(uri
));
769 snprintf(refresh
, sizeof(refresh
), "2;URL=%s", uri
);
770 cgiSetVariable("refresh_page", refresh
);
772 else if (cupsLastError() == IPP_NOT_AUTHORIZED
)
774 puts("Status: 401\n");
778 cgiStartHTML(cgiText(_("Print Test Page")));
780 if (cupsLastError() > IPP_OK_CONFLICT
)
781 cgiShowIPPError(_("Unable to print test page"));
784 cgiSetVariable("PRINTER_NAME", dest
);
786 cgiCopyTemplateLang("test-page.tmpl");
794 * 'cgiRewriteURL()' - Rewrite a printer URI into a web browser URL...
797 char * /* O - New URL */
798 cgiRewriteURL(const char *uri
, /* I - Current URI */
799 char *url
, /* O - New URL */
800 int urlsize
, /* I - Size of URL buffer */
801 const char *newresource
) /* I - Replacement resource */
803 char scheme
[HTTP_MAX_URI
],
804 userpass
[HTTP_MAX_URI
],
805 hostname
[HTTP_MAX_URI
],
806 rawresource
[HTTP_MAX_URI
],
807 resource
[HTTP_MAX_URI
],
808 /* URI components... */
809 *rawptr
, /* Pointer into rawresource */
810 *resptr
; /* Pointer into resource */
811 int port
; /* Port number */
812 static int ishttps
= -1; /* Using encryption? */
813 static const char *server
; /* Name of server */
814 static char servername
[1024];
815 /* Local server name */
816 static const char hexchars
[] = "0123456789ABCDEF";
817 /* Hexadecimal conversion characters */
821 * Check if we have been called before...
827 * No, initialize static vars for the conversion...
829 * First get the server name associated with the client interface as
830 * well as the locally configured hostname. We'll check *both* of
831 * these to see if the printer URL is local...
834 if ((server
= getenv("SERVER_NAME")) == NULL
)
837 httpGetHostname(NULL
, servername
, sizeof(servername
));
840 * Then flag whether we are using SSL on this connection...
843 ishttps
= getenv("HTTPS") != NULL
;
847 * Convert the URI to a URL...
850 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
, scheme
, sizeof(scheme
), userpass
,
851 sizeof(userpass
), hostname
, sizeof(hostname
), &port
,
852 rawresource
, sizeof(rawresource
));
854 if (!strcmp(scheme
, "ipp") ||
855 !strcmp(scheme
, "http") ||
856 !strcmp(scheme
, "https"))
861 * Force the specified resource name instead of the one in the URL...
864 strlcpy(resource
, newresource
, sizeof(resource
));
869 * Rewrite the resource string so it doesn't contain any
873 for (rawptr
= rawresource
, resptr
= resource
; *rawptr
; rawptr
++)
874 if ((*rawptr
& 128) || *rawptr
== '%' || *rawptr
== ' ' ||
875 *rawptr
== '#' || *rawptr
== '?' ||
876 *rawptr
== '.') /* For MSIE */
878 if (resptr
< (resource
+ sizeof(resource
) - 3))
881 *resptr
++ = hexchars
[(*rawptr
>> 4) & 15];
882 *resptr
++ = hexchars
[*rawptr
& 15];
885 else if (resptr
< (resource
+ sizeof(resource
) - 1))
892 * Map local access to a local URI...
895 if (!_cups_strcasecmp(hostname
, "127.0.0.1") ||
896 !_cups_strcasecmp(hostname
, "[::1]") ||
897 !_cups_strcasecmp(hostname
, "localhost") ||
898 !_cups_strncasecmp(hostname
, "localhost.", 10) ||
899 !_cups_strcasecmp(hostname
, server
) ||
900 !_cups_strcasecmp(hostname
, servername
))
903 * Make URI relative to the current server...
906 strlcpy(url
, resource
, (size_t)urlsize
);
911 * Rewrite URI with HTTP/HTTPS scheme...
915 snprintf(url
, (size_t)urlsize
, "%s://%s@%s:%d%s", ishttps
? "https" : "http", userpass
, hostname
, port
, resource
);
917 snprintf(url
, (size_t)urlsize
, "%s://%s:%d%s", ishttps
? "https" : "http", hostname
, port
, resource
);
921 strlcpy(url
, uri
, (size_t)urlsize
);
928 * 'cgiSetIPPObjectVars()' - Set CGI variables from an IPP object.
931 ipp_attribute_t
* /* O - Next object */
933 ipp_attribute_t
*obj
, /* I - Response data to be copied... */
934 const char *prefix
, /* I - Prefix for name or NULL */
935 int element
) /* I - Parent element number */
937 ipp_attribute_t
*attr
; /* Attribute in response... */
938 int i
; /* Looping var */
939 char name
[1024], /* Name of attribute */
940 *nameptr
, /* Pointer into name */
941 value
[16384], /* Value(s) */
942 *valptr
; /* Pointer into value */
945 fprintf(stderr
, "DEBUG2: cgiSetIPPObjectVars(obj=%p, prefix=\"%s\", "
947 obj
, prefix
? prefix
: "(null)", element
);
950 * Set common CGI template variables...
954 cgiSetServerVersion();
957 * Loop through the attributes and set them for the template...
960 for (attr
= obj
; attr
&& attr
->group_tag
!= IPP_TAG_ZERO
; attr
= attr
->next
)
963 * Copy the attribute name, substituting "_" for "-"...
971 snprintf(name
, sizeof(name
), "%s.", prefix
);
972 nameptr
= name
+ strlen(name
);
977 for (i
= 0; attr
->name
[i
] && nameptr
< (name
+ sizeof(name
) - 1); i
++)
978 if (attr
->name
[i
] == '-')
981 *nameptr
++ = attr
->name
[i
];
986 * Add "job_printer_name" variable if we have a "job_printer_uri"
990 if (!strcmp(name
, "job_printer_uri"))
992 if ((valptr
= strrchr(attr
->values
[0].string
.text
, '/')) == NULL
)
997 cgiSetArray("job_printer_name", element
, valptr
);
1001 * Localize event names in "notify_events" variable...
1004 if (!strcmp(name
, "notify_events"))
1006 size_t remaining
; /* Remaining bytes in buffer */
1012 for (i
= 0; i
< attr
->num_values
; i
++)
1014 if (valptr
>= (value
+ sizeof(value
) - 3))
1023 remaining
= sizeof(value
) - (size_t)(valptr
- value
);
1025 if (!strcmp(attr
->values
[i
].string
.text
, "printer-stopped"))
1026 strlcpy(valptr
, _("Printer Paused"), remaining
);
1027 else if (!strcmp(attr
->values
[i
].string
.text
, "printer-added"))
1028 strlcpy(valptr
, _("Printer Added"), remaining
);
1029 else if (!strcmp(attr
->values
[i
].string
.text
, "printer-modified"))
1030 strlcpy(valptr
, _("Printer Modified"), remaining
);
1031 else if (!strcmp(attr
->values
[i
].string
.text
, "printer-deleted"))
1032 strlcpy(valptr
, _("Printer Deleted"), remaining
);
1033 else if (!strcmp(attr
->values
[i
].string
.text
, "job-created"))
1034 strlcpy(valptr
, _("Job Created"), remaining
);
1035 else if (!strcmp(attr
->values
[i
].string
.text
, "job-completed"))
1036 strlcpy(valptr
, _("Job Completed"), remaining
);
1037 else if (!strcmp(attr
->values
[i
].string
.text
, "job-stopped"))
1038 strlcpy(valptr
, _("Job Stopped"), remaining
);
1039 else if (!strcmp(attr
->values
[i
].string
.text
, "job-config-changed"))
1040 strlcpy(valptr
, _("Job Options Changed"), remaining
);
1041 else if (!strcmp(attr
->values
[i
].string
.text
, "server-restarted"))
1042 strlcpy(valptr
, _("Server Restarted"), remaining
);
1043 else if (!strcmp(attr
->values
[i
].string
.text
, "server-started"))
1044 strlcpy(valptr
, _("Server Started"), remaining
);
1045 else if (!strcmp(attr
->values
[i
].string
.text
, "server-stopped"))
1046 strlcpy(valptr
, _("Server Stopped"), remaining
);
1047 else if (!strcmp(attr
->values
[i
].string
.text
, "server-audit"))
1048 strlcpy(valptr
, _("Server Security Auditing"), remaining
);
1050 strlcpy(valptr
, attr
->values
[i
].string
.text
, remaining
);
1052 valptr
+= strlen(valptr
);
1055 cgiSetArray("notify_events", element
, value
);
1060 * Add "notify_printer_name" variable if we have a "notify_printer_uri"
1064 if (!strcmp(name
, "notify_printer_uri"))
1066 if ((valptr
= strrchr(attr
->values
[0].string
.text
, '/')) == NULL
)
1071 cgiSetArray("notify_printer_name", element
, valptr
);
1075 * Add "notify_recipient_name" variable if we have a "notify_recipient_uri"
1076 * attribute, and rewrite recipient URI...
1079 if (!strcmp(name
, "notify_recipient_uri"))
1081 char uri
[1024], /* New URI */
1082 scheme
[32], /* Scheme portion of URI */
1083 userpass
[256], /* Username/password portion of URI */
1084 host
[1024], /* Hostname portion of URI */
1085 resource
[1024], /* Resource portion of URI */
1086 *options
; /* Options in URI */
1087 int port
; /* Port number */
1090 httpSeparateURI(HTTP_URI_CODING_ALL
, attr
->values
[0].string
.text
,
1091 scheme
, sizeof(scheme
), userpass
, sizeof(userpass
),
1092 host
, sizeof(host
), &port
, resource
, sizeof(resource
));
1094 if (!strcmp(scheme
, "rss"))
1097 * RSS notification...
1100 if ((options
= strchr(resource
, '?')) != NULL
)
1106 * Link to remote feed...
1109 httpAssembleURI(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "http",
1110 userpass
, host
, port
, resource
);
1111 strlcpy(name
, uri
, sizeof(name
));
1116 * Link to local feed...
1119 snprintf(uri
, sizeof(uri
), "/rss%s", resource
);
1120 strlcpy(name
, resource
+ 1, sizeof(name
));
1129 strlcpy(uri
, attr
->values
[0].string
.text
, sizeof(uri
));
1130 strlcpy(name
, resource
, sizeof(name
));
1133 cgiSetArray("notify_recipient_uri", element
, uri
);
1134 cgiSetArray("notify_recipient_name", element
, name
);
1139 * Add "admin_uri" variable if we have a "printer_uri_supported"
1143 if (!strcmp(name
, "printer_uri_supported"))
1145 cgiRewriteURL(attr
->values
[0].string
.text
, value
, sizeof(value
),
1148 cgiSetArray("admin_uri", element
, value
);
1155 value
[0] = '\0'; /* Initially an empty string */
1156 valptr
= value
; /* Start at the beginning */
1158 for (i
= 0; i
< attr
->num_values
; i
++)
1161 strlcat(valptr
, ", ", sizeof(value
) - (size_t)(valptr
- value
));
1163 valptr
+= strlen(valptr
);
1165 switch (attr
->value_tag
)
1167 case IPP_TAG_INTEGER
:
1169 if (strncmp(name
, "time_at_", 8) == 0)
1170 _cupsStrDate(valptr
, sizeof(value
) - (size_t)(valptr
- value
), (time_t)ippGetInteger(attr
, i
));
1172 snprintf(valptr
, sizeof(value
) - (size_t)(valptr
- value
), "%d", ippGetInteger(attr
, i
));
1175 case IPP_TAG_BOOLEAN
:
1176 snprintf(valptr
, sizeof(value
) - (size_t)(valptr
- value
),
1177 "%d", attr
->values
[i
].boolean
);
1180 case IPP_TAG_NOVALUE
:
1181 strlcat(valptr
, "novalue", sizeof(value
) - (size_t)(valptr
- value
));
1184 case IPP_TAG_RANGE
:
1185 snprintf(valptr
, sizeof(value
) - (size_t)(valptr
- value
),
1186 "%d-%d", attr
->values
[i
].range
.lower
,
1187 attr
->values
[i
].range
.upper
);
1190 case IPP_TAG_RESOLUTION
:
1191 snprintf(valptr
, sizeof(value
) - (size_t)(valptr
- value
),
1192 "%dx%d%s", attr
->values
[i
].resolution
.xres
,
1193 attr
->values
[i
].resolution
.yres
,
1194 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
1199 if (strchr(attr
->values
[i
].string
.text
, ':') &&
1200 strcmp(name
, "device_uri"))
1206 cgiRewriteURL(attr
->values
[i
].string
.text
, valptr
, (int)(sizeof(value
) - (size_t)(valptr
- value
)), NULL
);
1210 case IPP_TAG_STRING
:
1213 case IPP_TAG_KEYWORD
:
1214 case IPP_TAG_CHARSET
:
1215 case IPP_TAG_LANGUAGE
:
1216 case IPP_TAG_MIMETYPE
:
1217 strlcat(valptr
, attr
->values
[i
].string
.text
,
1218 sizeof(value
) - (size_t)(valptr
- value
));
1221 case IPP_TAG_BEGIN_COLLECTION
:
1222 snprintf(value
, sizeof(value
), "%s%d", name
, i
+ 1);
1223 cgiSetIPPVars(attr
->values
[i
].collection
, NULL
, NULL
, value
,
1228 break; /* anti-compiler-warning-code */
1233 * Add the element...
1236 if (attr
->value_tag
!= IPP_TAG_BEGIN_COLLECTION
)
1238 cgiSetArray(name
, element
, value
);
1240 fprintf(stderr
, "DEBUG2: %s[%d]=\"%s\"\n", name
, element
, value
);
1244 return (attr
? attr
->next
: NULL
);
1249 * 'cgiSetIPPVars()' - Set CGI variables from an IPP response.
1252 int /* O - Maximum number of elements */
1253 cgiSetIPPVars(ipp_t
*response
, /* I - Response data to be copied... */
1254 const char *filter_name
, /* I - Filter name */
1255 const char *filter_value
, /* I - Filter value */
1256 const char *prefix
, /* I - Prefix for name or NULL */
1257 int parent_el
) /* I - Parent element number */
1259 int element
; /* Element in CGI array */
1260 ipp_attribute_t
*attr
, /* Attribute in response... */
1261 *filter
; /* Filtering attribute */
1264 fprintf(stderr
, "DEBUG2: cgiSetIPPVars(response=%p, filter_name=\"%s\", "
1265 "filter_value=\"%s\", prefix=\"%s\", parent_el=%d)\n",
1266 response
, filter_name
? filter_name
: "(null)",
1267 filter_value
? filter_value
: "(null)",
1268 prefix
? prefix
: "(null)", parent_el
);
1271 * Set common CGI template variables...
1275 cgiSetServerVersion();
1278 * Loop through the attributes and set them for the template...
1281 attr
= response
->attrs
;
1284 while (attr
&& attr
->group_tag
== IPP_TAG_OPERATION
)
1287 for (element
= parent_el
; attr
; element
++)
1290 * Copy attributes to a separator...
1293 while (attr
&& attr
->group_tag
== IPP_TAG_ZERO
)
1302 filter
!= NULL
&& filter
->group_tag
!= IPP_TAG_ZERO
;
1303 filter
= filter
->next
)
1304 if (filter
->name
&& !strcmp(filter
->name
, filter_name
) &&
1305 (filter
->value_tag
== IPP_TAG_STRING
||
1306 (filter
->value_tag
>= IPP_TAG_TEXTLANG
&&
1307 filter
->value_tag
<= IPP_TAG_MIMETYPE
)) &&
1308 filter
->values
[0].string
.text
!= NULL
&&
1309 !_cups_strcasecmp(filter
->values
[0].string
.text
, filter_value
))
1313 return (element
+ 1);
1315 if (filter
->group_tag
== IPP_TAG_ZERO
)
1323 attr
= cgiSetIPPObjectVars(attr
, prefix
, element
);
1326 fprintf(stderr
, "DEBUG2: Returning %d from cgiSetIPPVars()...\n", element
);
1333 * 'cgiShowIPPError()' - Show the last IPP error message.
1335 * The caller must still call cgiStartHTML() and cgiEndHTML().
1339 cgiShowIPPError(const char *message
) /* I - Contextual message */
1341 cgiSetVariable("MESSAGE", cgiText(message
));
1342 cgiSetVariable("ERROR", cupsLastErrorString());
1343 cgiCopyTemplateLang("error.tmpl");
1348 * 'cgiShowJobs()' - Show print jobs.
1352 cgiShowJobs(http_t
*http
, /* I - Connection to server */
1353 const char *dest
) /* I - Destination name or NULL */
1355 int i
; /* Looping var */
1356 const char *which_jobs
; /* Which jobs to show */
1357 ipp_t
*request
, /* IPP request */
1358 *response
; /* IPP response */
1359 cups_array_t
*jobs
; /* Array of job objects */
1360 ipp_attribute_t
*job
; /* Job object */
1361 int first
, /* First job to show */
1362 count
; /* Number of jobs */
1363 const char *var
, /* Form variable */
1364 *query
, /* Query string */
1365 *section
; /* Section in web interface */
1366 void *search
; /* Search data */
1367 char url
[1024], /* Printer URI */
1368 val
[1024]; /* Form variable */
1372 * Build an IPP_GET_JOBS request, which requires the following
1375 * attributes-charset
1376 * attributes-natural-language
1380 request
= ippNewRequest(IPP_GET_JOBS
);
1384 httpAssembleURIf(HTTP_URI_CODING_ALL
, url
, sizeof(url
), "ipp", NULL
,
1385 "localhost", ippPort(), "/printers/%s", dest
);
1386 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1390 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
,
1391 "ipp://localhost/");
1393 if ((which_jobs
= cgiGetVariable("which_jobs")) != NULL
&& *which_jobs
)
1394 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
, "which-jobs",
1397 if ((var
= cgiGetVariable("FIRST")) != NULL
)
1399 if ((first
= atoi(var
)) < 0)
1406 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
, "first-index", first
+ 1);
1408 cgiGetAttributes(request
, "jobs.tmpl");
1411 * Do the request and get back a response...
1414 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1417 * Get a list of matching job objects.
1420 if ((query
= cgiGetVariable("QUERY")) != NULL
&&
1421 !cgiGetVariable("CLEAR"))
1422 search
= cgiCompileSearch(query
);
1429 jobs
= cgiGetIPPObjects(response
, search
);
1430 count
= cupsArrayCount(jobs
) + first
;
1433 cgiFreeSearch(search
);
1436 * Figure out which jobs to display...
1439 section
= cgiGetVariable("SECTION");
1441 cgiClearVariables();
1444 cgiSetVariable("QUERY", query
);
1446 cgiSetVariable("SECTION", section
);
1448 sprintf(val
, "%d", count
);
1449 cgiSetVariable("TOTAL", val
);
1452 cgiSetVariable("WHICH_JOBS", which_jobs
);
1454 for (i
= 0, job
= (ipp_attribute_t
*)cupsArrayFirst(jobs
);
1455 i
< CUPS_PAGE_MAX
&& job
;
1456 i
++, job
= (ipp_attribute_t
*)cupsArrayNext(jobs
))
1457 cgiSetIPPObjectVars(job
, NULL
, i
);
1460 * Save navigation URLs...
1465 snprintf(val
, sizeof(val
), "/%s/%s", section
, dest
);
1466 cgiSetVariable("PRINTER_NAME", dest
);
1467 cgiSetVariable("PRINTER_URI_SUPPORTED", val
);
1470 strlcpy(val
, "/jobs/", sizeof(val
));
1472 cgiSetVariable("THISURL", val
);
1476 sprintf(val
, "%d", first
- CUPS_PAGE_MAX
);
1477 cgiSetVariable("PREV", val
);
1480 if ((first
+ CUPS_PAGE_MAX
) < count
)
1482 sprintf(val
, "%d", first
+ CUPS_PAGE_MAX
);
1483 cgiSetVariable("NEXT", val
);
1486 if (count
> CUPS_PAGE_MAX
)
1488 snprintf(val
, sizeof(val
), "%d", CUPS_PAGE_MAX
* (count
/ CUPS_PAGE_MAX
));
1489 cgiSetVariable("LAST", val
);
1493 * Then show everything...
1497 cgiSetVariable("SEARCH_DEST", dest
);
1499 cgiCopyTemplateLang("search.tmpl");
1501 cgiCopyTemplateLang("jobs-header.tmpl");
1503 if (count
> CUPS_PAGE_MAX
)
1504 cgiCopyTemplateLang("pager.tmpl");
1506 cgiCopyTemplateLang("jobs.tmpl");
1508 if (count
> CUPS_PAGE_MAX
)
1509 cgiCopyTemplateLang("pager.tmpl");
1511 cupsArrayDelete(jobs
);
1512 ippDelete(response
);
1518 * 'cgiText()' - Return localized text.
1521 const char * /* O - Localized message */
1522 cgiText(const char *message
) /* I - Message */
1524 static cups_lang_t
*language
= NULL
;
1529 language
= cupsLangDefault();
1531 return (_cupsLangString(language
, message
));