4 * CGI <-> IPP variable routines for CUPS.
6 * Copyright 2007-2015 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
17 * Include necessary headers...
20 #include "cgi-private.h"
24 * 'cgiGetAttributes()' - Get the list of attributes that are needed
25 * by the template file.
29 cgiGetAttributes(ipp_t
*request
, /* I - IPP request */
30 const char *tmpl
) /* I - Base filename */
32 int num_attrs
; /* Number of attributes */
33 char *attrs
[1000]; /* Attributes */
34 int i
; /* Looping var */
35 char filename
[1024], /* Filename */
36 locale
[16]; /* Locale name */
37 const char *directory
, /* Directory */
39 FILE *in
; /* Input file */
40 int ch
; /* Character from file */
41 char name
[255], /* Name of variable */
42 *nameptr
; /* Pointer into name */
46 * Convert the language to a locale name...
49 if ((lang
= getenv("LANG")) != NULL
)
51 for (i
= 0; lang
[i
] && i
< 15; i
++)
52 if (isalnum(lang
[i
] & 255))
53 locale
[i
] = (char)tolower(lang
[i
]);
63 * See if we have a template file for this language...
66 directory
= cgiGetTemplateDir();
68 snprintf(filename
, sizeof(filename
), "%s/%s/%s", directory
, locale
, tmpl
);
69 if (access(filename
, 0))
73 snprintf(filename
, sizeof(filename
), "%s/%s/%s", directory
, locale
, tmpl
);
74 if (access(filename
, 0))
75 snprintf(filename
, sizeof(filename
), "%s/%s", directory
, tmpl
);
79 * Open the template file...
82 if ((in
= fopen(filename
, "r")) == NULL
)
86 * Loop through the file adding attribute names as needed...
90 attrs
[0] = NULL
; /* Eliminate compiler warning */
92 while ((ch
= getc(in
)) != EOF
)
95 else if (ch
== '{' && num_attrs
< (int)(sizeof(attrs
) / sizeof(attrs
[0])))
101 for (nameptr
= name
; (ch
= getc(in
)) != EOF
;)
102 if (strchr("}]<>=!~ \t\n", ch
))
104 else if (nameptr
> name
&& ch
== '?')
106 else if (nameptr
< (name
+ sizeof(name
) - 1))
111 *nameptr
++ = (char)ch
;
116 if (!strncmp(name
, "printer_state_history", 21))
117 strlcpy(name
, "printer_state_history", sizeof(name
));
120 * Possibly add it to the list of attributes...
123 for (i
= 0; i
< num_attrs
; i
++)
124 if (!strcmp(attrs
[i
], name
))
129 attrs
[num_attrs
] = strdup(name
);
135 * If we have attributes, add a requested-attributes attribute to the
141 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
142 "requested-attributes", num_attrs
, NULL
, (const char **)attrs
);
144 for (i
= 0; i
< num_attrs
; i
++)
153 * 'cgiGetIPPObjects()' - Get the objects in an IPP response.
156 cups_array_t
* /* O - Array of objects */
157 cgiGetIPPObjects(ipp_t
*response
, /* I - IPP response */
158 void *search
) /* I - Search filter */
160 int i
; /* Looping var */
161 cups_array_t
*objs
; /* Array of objects */
162 ipp_attribute_t
*attr
, /* Current attribute */
163 *first
; /* First attribute for object */
164 ipp_tag_t group
; /* Current group tag */
165 int add
; /* Add this object to the array? */
171 for (add
= 0, first
= NULL
, objs
= cupsArrayNew(NULL
, NULL
),
172 group
= IPP_TAG_ZERO
, attr
= response
->attrs
;
176 if (attr
->group_tag
!= group
)
178 group
= attr
->group_tag
;
180 if (group
!= IPP_TAG_ZERO
&& group
!= IPP_TAG_OPERATION
)
185 else if (add
&& first
)
187 cupsArrayAdd(objs
, first
);
194 if (attr
->name
&& attr
->group_tag
!= IPP_TAG_OPERATION
&& !add
)
199 * Add all objects if there is no search...
207 * Check the search string against the string and integer values.
210 switch (attr
->value_tag
)
212 case IPP_TAG_TEXTLANG
:
213 case IPP_TAG_NAMELANG
:
216 case IPP_TAG_KEYWORD
:
218 case IPP_TAG_MIMETYPE
:
219 for (i
= 0; !add
&& i
< attr
->num_values
; i
++)
220 if (cgiDoSearch(search
, attr
->values
[i
].string
.text
))
224 case IPP_TAG_INTEGER
:
225 if (!strncmp(ippGetName(attr
), "time-at-", 8))
226 break; /* Ignore time-at-xxx */
228 for (i
= 0; !add
&& i
< attr
->num_values
; i
++)
230 char buf
[255]; /* Number buffer */
233 sprintf(buf
, "%d", attr
->values
[i
].integer
);
235 if (cgiDoSearch(search
, buf
))
248 cupsArrayAdd(objs
, first
);
255 * 'cgiMoveJobs()' - Move one or more jobs.
257 * At least one of dest or job_id must be non-zero/NULL.
261 cgiMoveJobs(http_t
*http
, /* I - Connection to server */
262 const char *dest
, /* I - Destination or NULL */
263 int job_id
) /* I - Job ID or 0 for all */
265 int i
; /* Looping var */
266 const char *user
; /* Username */
267 ipp_t
*request
, /* IPP request */
268 *response
; /* IPP response */
269 ipp_attribute_t
*attr
; /* Current attribute */
270 const char *name
; /* Destination name */
271 const char *job_printer_uri
; /* JOB_PRINTER_URI form variable */
272 char current_dest
[1024]; /* Current destination */
276 * Make sure we have a username...
279 if ((user
= getenv("REMOTE_USER")) == NULL
)
281 puts("Status: 401\n");
286 * See if the user has already selected a new destination...
289 if ((job_printer_uri
= cgiGetVariable("JOB_PRINTER_URI")) == NULL
)
292 * Make sure necessary form variables are set...
297 char temp
[255]; /* Temporary string */
300 sprintf(temp
, "%d", job_id
);
301 cgiSetVariable("JOB_ID", temp
);
305 cgiSetVariable("PRINTER_NAME", dest
);
308 * No new destination specified, show the user what the available
309 * printers/classes are...
315 * Get the current destination for job N...
318 char job_uri
[1024]; /* Job URI */
321 request
= ippNewRequest(IPP_GET_JOB_ATTRIBUTES
);
323 snprintf(job_uri
, sizeof(job_uri
), "ipp://localhost/jobs/%d", job_id
);
324 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri",
326 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
327 "requested-attributes", NULL
, "job-printer-uri");
329 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
331 if ((attr
= ippFindAttribute(response
, "job-printer-uri",
332 IPP_TAG_URI
)) != NULL
)
335 * Pull the name from the URI...
338 strlcpy(current_dest
, strrchr(attr
->values
[0].string
.text
, '/') + 1,
339 sizeof(current_dest
));
349 * Couldn't get the current destination...
352 cgiStartHTML(cgiText(_("Move Job")));
353 cgiShowIPPError(_("Unable to find destination for job"));
360 * Get the list of available destinations...
363 request
= ippNewRequest(CUPS_GET_PRINTERS
);
365 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
366 "requested-attributes", NULL
, "printer-uri-supported");
369 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
370 "requesting-user-name", NULL
, user
);
372 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
374 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
375 CUPS_PRINTER_SCANNER
);
377 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
379 for (i
= 0, attr
= ippFindAttribute(response
, "printer-uri-supported",
382 attr
= ippFindNextAttribute(response
, "printer-uri-supported",
386 * Pull the name from the URI...
389 name
= strrchr(attr
->values
[0].string
.text
, '/') + 1;
392 * If the name is not the same as the current destination, add it!
395 if (_cups_strcasecmp(name
, dest
))
397 cgiSetArray("JOB_PRINTER_URI", i
, attr
->values
[0].string
.text
);
398 cgiSetArray("JOB_PRINTER_NAME", i
, name
);
411 cgiStartHTML(cgiText(_("Move Job")));
413 cgiStartHTML(cgiText(_("Move All Jobs")));
415 if (cgiGetSize("JOB_PRINTER_NAME") > 0)
416 cgiCopyTemplateLang("job-move.tmpl");
420 cgiSetVariable("MESSAGE", cgiText(_("Unable to move job")));
422 cgiSetVariable("MESSAGE", cgiText(_("Unable to move jobs")));
424 cgiSetVariable("ERROR", cgiText(_("No destinations added.")));
425 cgiCopyTemplateLang("error.tmpl");
431 * Try moving the job or jobs...
434 char uri
[1024], /* Job/printer URI */
435 resource
[1024], /* Post resource */
436 refresh
[1024]; /* Refresh URL */
437 const char *job_printer_name
; /* New printer name */
440 request
= ippNewRequest(CUPS_MOVE_JOB
);
448 snprintf(resource
, sizeof(resource
), "/jobs/%d", job_id
);
450 snprintf(uri
, sizeof(uri
), "ipp://localhost/jobs/%d", job_id
);
451 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri",
457 * Move all active jobs on a destination...
460 snprintf(resource
, sizeof(resource
), "/%s/%s",
461 cgiGetVariable("SECTION"), dest
);
463 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
464 "localhost", ippPort(), "/%s/%s",
465 cgiGetVariable("SECTION"), dest
);
466 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
470 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-printer-uri",
471 NULL
, job_printer_uri
);
473 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
474 "requesting-user-name", NULL
, user
);
476 ippDelete(cupsDoRequest(http
, request
, resource
));
479 * Show the results...
482 job_printer_name
= strrchr(job_printer_uri
, '/') + 1;
484 if (cupsLastError() <= IPP_OK_CONFLICT
)
486 const char *path
= strstr(job_printer_uri
, "/printers/");
489 path
= strstr(job_printer_uri
, "/classes/");
490 cgiSetVariable("IS_CLASS", "YES");
495 cgiFormEncode(uri
, path
, sizeof(uri
));
496 snprintf(refresh
, sizeof(refresh
), "2;URL=%s", uri
);
497 cgiSetVariable("refresh_page", refresh
);
502 cgiStartHTML(cgiText(_("Move Job")));
504 cgiStartHTML(cgiText(_("Move All Jobs")));
506 if (cupsLastError() > IPP_OK_CONFLICT
)
509 cgiShowIPPError(_("Unable to move job"));
511 cgiShowIPPError(_("Unable to move jobs"));
515 cgiSetVariable("JOB_PRINTER_NAME", job_printer_name
);
516 cgiCopyTemplateLang("job-moved.tmpl");
525 * 'cgiPrintCommand()' - Print a CUPS command job.
529 cgiPrintCommand(http_t
*http
, /* I - Connection to server */
530 const char *dest
, /* I - Destination printer */
531 const char *command
, /* I - Command to send */
532 const char *title
) /* I - Page/job title */
534 int job_id
; /* Command file job */
535 char uri
[HTTP_MAX_URI
], /* Job URI */
536 resource
[1024], /* Printer resource path */
537 refresh
[1024], /* Refresh URL */
538 command_file
[1024]; /* Command "file" */
539 http_status_t status
; /* Document status */
540 cups_option_t hold_option
; /* job-hold-until option */
541 const char *user
; /* User name */
542 ipp_t
*request
, /* Get-Job-Attributes request */
543 *response
; /* Get-Job-Attributes response */
544 ipp_attribute_t
*attr
; /* Current job attribute */
545 static const char * const job_attrs
[] =/* Job attributes we want */
548 "job-printer-state-message"
553 * Create the CUPS command file...
556 snprintf(command_file
, sizeof(command_file
), "#CUPS-COMMAND\n%s\n", command
);
562 if (cgiSupportsMultipart())
566 cgiCopyTemplateLang("command.tmpl");
572 * Send the command file job...
575 hold_option
.name
= "job-hold-until";
576 hold_option
.value
= "no-hold";
578 if ((user
= getenv("REMOTE_USER")) != NULL
)
581 cupsSetUser("anonymous");
583 if ((job_id
= cupsCreateJob(http
, dest
, title
,
584 1, &hold_option
)) < 1)
586 cgiSetVariable("MESSAGE", cgiText(_("Unable to send command to printer driver")));
587 cgiSetVariable("ERROR", cupsLastErrorString());
589 cgiCopyTemplateLang("error.tmpl");
592 if (cgiSupportsMultipart())
597 status
= cupsStartDocument(http
, dest
, job_id
, NULL
, CUPS_FORMAT_COMMAND
, 1);
598 if (status
== HTTP_CONTINUE
)
599 status
= cupsWriteRequestData(http
, command_file
,
600 strlen(command_file
));
601 if (status
== HTTP_CONTINUE
)
602 cupsFinishDocument(http
, dest
);
604 if (cupsLastError() >= IPP_REDIRECTION_OTHER_SITE
)
606 cgiSetVariable("MESSAGE", cgiText(_("Unable to send command to printer driver")));
607 cgiSetVariable("ERROR", cupsLastErrorString());
609 cgiCopyTemplateLang("error.tmpl");
612 if (cgiSupportsMultipart())
615 cupsCancelJob(dest
, job_id
);
620 * Wait for the job to complete...
623 if (cgiSupportsMultipart())
628 * Get the current job state...
631 snprintf(uri
, sizeof(uri
), "ipp://localhost/jobs/%d", job_id
);
632 request
= ippNewRequest(IPP_GET_JOB_ATTRIBUTES
);
633 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri",
636 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
637 "requesting-user-name", NULL
, user
);
638 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
639 "requested-attributes", 2, NULL
, job_attrs
);
641 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
642 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
644 attr
= ippFindAttribute(response
, "job-state", IPP_TAG_ENUM
);
645 if (!attr
|| attr
->values
[0].integer
>= IPP_JOB_STOPPED
||
646 attr
->values
[0].integer
== IPP_JOB_HELD
)
653 * Job not complete, so update the status...
659 cgiCopyTemplateLang("command.tmpl");
668 * Send the final page that reloads the printer's page...
671 snprintf(resource
, sizeof(resource
), "/printers/%s", dest
);
673 cgiFormEncode(uri
, resource
, sizeof(uri
));
674 snprintf(refresh
, sizeof(refresh
), "5;URL=%s", uri
);
675 cgiSetVariable("refresh_page", refresh
);
678 cgiCopyTemplateLang("command.tmpl");
681 if (cgiSupportsMultipart())
687 * 'cgiPrintTestPage()' - Print a test page.
691 cgiPrintTestPage(http_t
*http
, /* I - Connection to server */
692 const char *dest
) /* I - Destination printer/class */
694 ipp_t
*request
, /* IPP request */
695 *response
; /* IPP response */
696 char uri
[HTTP_MAX_URI
], /* Printer URI */
697 resource
[1024], /* POST resource path */
698 refresh
[1024], /* Refresh URL */
699 filename
[1024]; /* Test page filename */
700 const char *datadir
; /* CUPS_DATADIR env var */
701 const char *user
; /* Username */
705 * See who is logged in...
708 user
= getenv("REMOTE_USER");
711 * Locate the test page file...
714 if ((datadir
= getenv("CUPS_DATADIR")) == NULL
)
715 datadir
= CUPS_DATADIR
;
717 snprintf(filename
, sizeof(filename
), "%s/data/testprint", datadir
);
720 * Point to the printer/class...
723 snprintf(resource
, sizeof(resource
), "/%s/%s", cgiGetVariable("SECTION"),
726 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
727 "localhost", ippPort(), "/%s/%s", cgiGetVariable("SECTION"),
731 * Build an IPP_PRINT_JOB request, which requires the following
735 * attributes-natural-language
737 * requesting-user-name
740 request
= ippNewRequest(IPP_PRINT_JOB
);
742 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
746 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
747 "requesting-user-name", NULL
, user
);
749 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "job-name",
753 * Do the request and get back a response...
756 if ((response
= cupsDoFileRequest(http
, request
, resource
,
759 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
764 if (cupsLastError() <= IPP_OK_CONFLICT
)
767 * Automatically reload the printer status page...
770 cgiFormEncode(uri
, resource
, sizeof(uri
));
771 snprintf(refresh
, sizeof(refresh
), "2;URL=%s", uri
);
772 cgiSetVariable("refresh_page", refresh
);
774 else if (cupsLastError() == IPP_NOT_AUTHORIZED
)
776 puts("Status: 401\n");
780 cgiStartHTML(cgiText(_("Print Test Page")));
782 if (cupsLastError() > IPP_OK_CONFLICT
)
783 cgiShowIPPError(_("Unable to print test page"));
786 cgiSetVariable("PRINTER_NAME", dest
);
788 cgiCopyTemplateLang("test-page.tmpl");
796 * 'cgiRewriteURL()' - Rewrite a printer URI into a web browser URL...
799 char * /* O - New URL */
800 cgiRewriteURL(const char *uri
, /* I - Current URI */
801 char *url
, /* O - New URL */
802 int urlsize
, /* I - Size of URL buffer */
803 const char *newresource
) /* I - Replacement resource */
805 char scheme
[HTTP_MAX_URI
],
806 userpass
[HTTP_MAX_URI
],
807 hostname
[HTTP_MAX_URI
],
808 rawresource
[HTTP_MAX_URI
],
809 resource
[HTTP_MAX_URI
],
810 /* URI components... */
811 *rawptr
, /* Pointer into rawresource */
812 *resptr
; /* Pointer into resource */
813 int port
; /* Port number */
814 static int ishttps
= -1; /* Using encryption? */
815 static const char *server
; /* Name of server */
816 static char servername
[1024];
817 /* Local server name */
818 static const char hexchars
[] = "0123456789ABCDEF";
819 /* Hexadecimal conversion characters */
823 * Check if we have been called before...
829 * No, initialize static vars for the conversion...
831 * First get the server name associated with the client interface as
832 * well as the locally configured hostname. We'll check *both* of
833 * these to see if the printer URL is local...
836 if ((server
= getenv("SERVER_NAME")) == NULL
)
839 httpGetHostname(NULL
, servername
, sizeof(servername
));
842 * Then flag whether we are using SSL on this connection...
845 ishttps
= getenv("HTTPS") != NULL
;
849 * Convert the URI to a URL...
852 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
, scheme
, sizeof(scheme
), userpass
,
853 sizeof(userpass
), hostname
, sizeof(hostname
), &port
,
854 rawresource
, sizeof(rawresource
));
856 if (!strcmp(scheme
, "ipp") ||
857 !strcmp(scheme
, "http") ||
858 !strcmp(scheme
, "https"))
863 * Force the specified resource name instead of the one in the URL...
866 strlcpy(resource
, newresource
, sizeof(resource
));
871 * Rewrite the resource string so it doesn't contain any
875 for (rawptr
= rawresource
, resptr
= resource
; *rawptr
; rawptr
++)
876 if ((*rawptr
& 128) || *rawptr
== '%' || *rawptr
== ' ' ||
877 *rawptr
== '#' || *rawptr
== '?' ||
878 *rawptr
== '.') /* For MSIE */
880 if (resptr
< (resource
+ sizeof(resource
) - 3))
883 *resptr
++ = hexchars
[(*rawptr
>> 4) & 15];
884 *resptr
++ = hexchars
[*rawptr
& 15];
887 else if (resptr
< (resource
+ sizeof(resource
) - 1))
894 * Map local access to a local URI...
897 if (!_cups_strcasecmp(hostname
, "127.0.0.1") ||
898 !_cups_strcasecmp(hostname
, "[::1]") ||
899 !_cups_strcasecmp(hostname
, "localhost") ||
900 !_cups_strncasecmp(hostname
, "localhost.", 10) ||
901 !_cups_strcasecmp(hostname
, server
) ||
902 !_cups_strcasecmp(hostname
, servername
))
905 * Make URI relative to the current server...
908 strlcpy(url
, resource
, (size_t)urlsize
);
913 * Rewrite URI with HTTP/HTTPS scheme...
917 snprintf(url
, (size_t)urlsize
, "%s://%s@%s:%d%s", ishttps
? "https" : "http", userpass
, hostname
, port
, resource
);
919 snprintf(url
, (size_t)urlsize
, "%s://%s:%d%s", ishttps
? "https" : "http", hostname
, port
, resource
);
923 strlcpy(url
, uri
, (size_t)urlsize
);
930 * 'cgiSetIPPObjectVars()' - Set CGI variables from an IPP object.
933 ipp_attribute_t
* /* O - Next object */
935 ipp_attribute_t
*obj
, /* I - Response data to be copied... */
936 const char *prefix
, /* I - Prefix for name or NULL */
937 int element
) /* I - Parent element number */
939 ipp_attribute_t
*attr
; /* Attribute in response... */
940 int i
; /* Looping var */
941 char name
[1024], /* Name of attribute */
942 *nameptr
, /* Pointer into name */
943 value
[16384], /* Value(s) */
944 *valptr
; /* Pointer into value */
947 fprintf(stderr
, "DEBUG2: cgiSetIPPObjectVars(obj=%p, prefix=\"%s\", "
949 obj
, prefix
? prefix
: "(null)", element
);
952 * Set common CGI template variables...
956 cgiSetServerVersion();
959 * Loop through the attributes and set them for the template...
962 for (attr
= obj
; attr
&& attr
->group_tag
!= IPP_TAG_ZERO
; attr
= attr
->next
)
965 * Copy the attribute name, substituting "_" for "-"...
973 snprintf(name
, sizeof(name
), "%s.", prefix
);
974 nameptr
= name
+ strlen(name
);
979 for (i
= 0; attr
->name
[i
] && nameptr
< (name
+ sizeof(name
) - 1); i
++)
980 if (attr
->name
[i
] == '-')
983 *nameptr
++ = attr
->name
[i
];
988 * Add "job_printer_name" variable if we have a "job_printer_uri"
992 if (!strcmp(name
, "job_printer_uri"))
994 if ((valptr
= strrchr(attr
->values
[0].string
.text
, '/')) == NULL
)
999 cgiSetArray("job_printer_name", element
, valptr
);
1003 * Localize event names in "notify_events" variable...
1006 if (!strcmp(name
, "notify_events"))
1008 size_t remaining
; /* Remaining bytes in buffer */
1014 for (i
= 0; i
< attr
->num_values
; i
++)
1016 if (valptr
>= (value
+ sizeof(value
) - 3))
1025 remaining
= sizeof(value
) - (size_t)(valptr
- value
);
1027 if (!strcmp(attr
->values
[i
].string
.text
, "printer-stopped"))
1028 strlcpy(valptr
, _("Printer Paused"), remaining
);
1029 else if (!strcmp(attr
->values
[i
].string
.text
, "printer-added"))
1030 strlcpy(valptr
, _("Printer Added"), remaining
);
1031 else if (!strcmp(attr
->values
[i
].string
.text
, "printer-modified"))
1032 strlcpy(valptr
, _("Printer Modified"), remaining
);
1033 else if (!strcmp(attr
->values
[i
].string
.text
, "printer-deleted"))
1034 strlcpy(valptr
, _("Printer Deleted"), remaining
);
1035 else if (!strcmp(attr
->values
[i
].string
.text
, "job-created"))
1036 strlcpy(valptr
, _("Job Created"), remaining
);
1037 else if (!strcmp(attr
->values
[i
].string
.text
, "job-completed"))
1038 strlcpy(valptr
, _("Job Completed"), remaining
);
1039 else if (!strcmp(attr
->values
[i
].string
.text
, "job-stopped"))
1040 strlcpy(valptr
, _("Job Stopped"), remaining
);
1041 else if (!strcmp(attr
->values
[i
].string
.text
, "job-config-changed"))
1042 strlcpy(valptr
, _("Job Options Changed"), remaining
);
1043 else if (!strcmp(attr
->values
[i
].string
.text
, "server-restarted"))
1044 strlcpy(valptr
, _("Server Restarted"), remaining
);
1045 else if (!strcmp(attr
->values
[i
].string
.text
, "server-started"))
1046 strlcpy(valptr
, _("Server Started"), remaining
);
1047 else if (!strcmp(attr
->values
[i
].string
.text
, "server-stopped"))
1048 strlcpy(valptr
, _("Server Stopped"), remaining
);
1049 else if (!strcmp(attr
->values
[i
].string
.text
, "server-audit"))
1050 strlcpy(valptr
, _("Server Security Auditing"), remaining
);
1052 strlcpy(valptr
, attr
->values
[i
].string
.text
, remaining
);
1054 valptr
+= strlen(valptr
);
1057 cgiSetArray("notify_events", element
, value
);
1062 * Add "notify_printer_name" variable if we have a "notify_printer_uri"
1066 if (!strcmp(name
, "notify_printer_uri"))
1068 if ((valptr
= strrchr(attr
->values
[0].string
.text
, '/')) == NULL
)
1073 cgiSetArray("notify_printer_name", element
, valptr
);
1077 * Add "notify_recipient_name" variable if we have a "notify_recipient_uri"
1078 * attribute, and rewrite recipient URI...
1081 if (!strcmp(name
, "notify_recipient_uri"))
1083 char uri
[1024], /* New URI */
1084 scheme
[32], /* Scheme portion of URI */
1085 userpass
[256], /* Username/password portion of URI */
1086 host
[1024], /* Hostname portion of URI */
1087 resource
[1024], /* Resource portion of URI */
1088 *options
; /* Options in URI */
1089 int port
; /* Port number */
1092 httpSeparateURI(HTTP_URI_CODING_ALL
, attr
->values
[0].string
.text
,
1093 scheme
, sizeof(scheme
), userpass
, sizeof(userpass
),
1094 host
, sizeof(host
), &port
, resource
, sizeof(resource
));
1096 if (!strcmp(scheme
, "rss"))
1099 * RSS notification...
1102 if ((options
= strchr(resource
, '?')) != NULL
)
1108 * Link to remote feed...
1111 httpAssembleURI(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "http",
1112 userpass
, host
, port
, resource
);
1113 strlcpy(name
, uri
, sizeof(name
));
1118 * Link to local feed...
1121 snprintf(uri
, sizeof(uri
), "/rss%s", resource
);
1122 strlcpy(name
, resource
+ 1, sizeof(name
));
1131 strlcpy(uri
, attr
->values
[0].string
.text
, sizeof(uri
));
1132 strlcpy(name
, resource
, sizeof(name
));
1135 cgiSetArray("notify_recipient_uri", element
, uri
);
1136 cgiSetArray("notify_recipient_name", element
, name
);
1141 * Add "admin_uri" variable if we have a "printer_uri_supported"
1145 if (!strcmp(name
, "printer_uri_supported"))
1147 cgiRewriteURL(attr
->values
[0].string
.text
, value
, sizeof(value
),
1150 cgiSetArray("admin_uri", element
, value
);
1157 value
[0] = '\0'; /* Initially an empty string */
1158 valptr
= value
; /* Start at the beginning */
1160 for (i
= 0; i
< attr
->num_values
; i
++)
1163 strlcat(valptr
, ", ", sizeof(value
) - (size_t)(valptr
- value
));
1165 valptr
+= strlen(valptr
);
1167 switch (attr
->value_tag
)
1169 case IPP_TAG_INTEGER
:
1171 if (strncmp(name
, "time_at_", 8) == 0)
1172 _cupsStrDate(valptr
, sizeof(value
) - (size_t)(valptr
- value
), (time_t)ippGetInteger(attr
, i
));
1174 snprintf(valptr
, sizeof(value
) - (size_t)(valptr
- value
), "%d", ippGetInteger(attr
, i
));
1177 case IPP_TAG_BOOLEAN
:
1178 snprintf(valptr
, sizeof(value
) - (size_t)(valptr
- value
),
1179 "%d", attr
->values
[i
].boolean
);
1182 case IPP_TAG_NOVALUE
:
1183 strlcat(valptr
, "novalue", sizeof(value
) - (size_t)(valptr
- value
));
1186 case IPP_TAG_RANGE
:
1187 snprintf(valptr
, sizeof(value
) - (size_t)(valptr
- value
),
1188 "%d-%d", attr
->values
[i
].range
.lower
,
1189 attr
->values
[i
].range
.upper
);
1192 case IPP_TAG_RESOLUTION
:
1193 snprintf(valptr
, sizeof(value
) - (size_t)(valptr
- value
),
1194 "%dx%d%s", attr
->values
[i
].resolution
.xres
,
1195 attr
->values
[i
].resolution
.yres
,
1196 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
1201 if (strchr(attr
->values
[i
].string
.text
, ':') &&
1202 strcmp(name
, "device_uri"))
1208 cgiRewriteURL(attr
->values
[i
].string
.text
, valptr
, (int)(sizeof(value
) - (size_t)(valptr
- value
)), NULL
);
1212 case IPP_TAG_STRING
:
1215 case IPP_TAG_KEYWORD
:
1216 case IPP_TAG_CHARSET
:
1217 case IPP_TAG_LANGUAGE
:
1218 case IPP_TAG_MIMETYPE
:
1219 strlcat(valptr
, attr
->values
[i
].string
.text
,
1220 sizeof(value
) - (size_t)(valptr
- value
));
1223 case IPP_TAG_BEGIN_COLLECTION
:
1224 snprintf(value
, sizeof(value
), "%s%d", name
, i
+ 1);
1225 cgiSetIPPVars(attr
->values
[i
].collection
, NULL
, NULL
, value
,
1230 break; /* anti-compiler-warning-code */
1235 * Add the element...
1238 if (attr
->value_tag
!= IPP_TAG_BEGIN_COLLECTION
)
1240 cgiSetArray(name
, element
, value
);
1242 fprintf(stderr
, "DEBUG2: %s[%d]=\"%s\"\n", name
, element
, value
);
1246 return (attr
? attr
->next
: NULL
);
1251 * 'cgiSetIPPVars()' - Set CGI variables from an IPP response.
1254 int /* O - Maximum number of elements */
1255 cgiSetIPPVars(ipp_t
*response
, /* I - Response data to be copied... */
1256 const char *filter_name
, /* I - Filter name */
1257 const char *filter_value
, /* I - Filter value */
1258 const char *prefix
, /* I - Prefix for name or NULL */
1259 int parent_el
) /* I - Parent element number */
1261 int element
; /* Element in CGI array */
1262 ipp_attribute_t
*attr
, /* Attribute in response... */
1263 *filter
; /* Filtering attribute */
1266 fprintf(stderr
, "DEBUG2: cgiSetIPPVars(response=%p, filter_name=\"%s\", "
1267 "filter_value=\"%s\", prefix=\"%s\", parent_el=%d)\n",
1268 response
, filter_name
? filter_name
: "(null)",
1269 filter_value
? filter_value
: "(null)",
1270 prefix
? prefix
: "(null)", parent_el
);
1273 * Set common CGI template variables...
1277 cgiSetServerVersion();
1280 * Loop through the attributes and set them for the template...
1283 attr
= response
->attrs
;
1286 while (attr
&& attr
->group_tag
== IPP_TAG_OPERATION
)
1289 for (element
= parent_el
; attr
; element
++)
1292 * Copy attributes to a separator...
1295 while (attr
&& attr
->group_tag
== IPP_TAG_ZERO
)
1304 filter
!= NULL
&& filter
->group_tag
!= IPP_TAG_ZERO
;
1305 filter
= filter
->next
)
1306 if (filter
->name
&& !strcmp(filter
->name
, filter_name
) &&
1307 (filter
->value_tag
== IPP_TAG_STRING
||
1308 (filter
->value_tag
>= IPP_TAG_TEXTLANG
&&
1309 filter
->value_tag
<= IPP_TAG_MIMETYPE
)) &&
1310 filter
->values
[0].string
.text
!= NULL
&&
1311 !_cups_strcasecmp(filter
->values
[0].string
.text
, filter_value
))
1315 return (element
+ 1);
1317 if (filter
->group_tag
== IPP_TAG_ZERO
)
1325 attr
= cgiSetIPPObjectVars(attr
, prefix
, element
);
1328 fprintf(stderr
, "DEBUG2: Returing %d from cgiSetIPPVars()...\n", element
);
1335 * 'cgiShowIPPError()' - Show the last IPP error message.
1337 * The caller must still call cgiStartHTML() and cgiEndHTML().
1341 cgiShowIPPError(const char *message
) /* I - Contextual message */
1343 cgiSetVariable("MESSAGE", cgiText(message
));
1344 cgiSetVariable("ERROR", cupsLastErrorString());
1345 cgiCopyTemplateLang("error.tmpl");
1350 * 'cgiShowJobs()' - Show print jobs.
1354 cgiShowJobs(http_t
*http
, /* I - Connection to server */
1355 const char *dest
) /* I - Destination name or NULL */
1357 int i
; /* Looping var */
1358 const char *which_jobs
; /* Which jobs to show */
1359 ipp_t
*request
, /* IPP request */
1360 *response
; /* IPP response */
1361 cups_array_t
*jobs
; /* Array of job objects */
1362 ipp_attribute_t
*job
; /* Job object */
1363 int ascending
, /* Order of jobs (0 = descending) */
1364 first
, /* First job to show */
1365 count
; /* Number of jobs */
1366 const char *var
, /* Form variable */
1367 *query
, /* Query string */
1368 *section
; /* Section in web interface */
1369 void *search
; /* Search data */
1370 char url
[1024], /* Printer URI */
1371 val
[1024]; /* Form variable */
1375 * Build an IPP_GET_JOBS request, which requires the following
1378 * attributes-charset
1379 * attributes-natural-language
1383 request
= ippNewRequest(IPP_GET_JOBS
);
1387 httpAssembleURIf(HTTP_URI_CODING_ALL
, url
, sizeof(url
), "ipp", NULL
,
1388 "localhost", ippPort(), "/printers/%s", dest
);
1389 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1393 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
,
1394 "ipp://localhost/");
1396 if ((which_jobs
= cgiGetVariable("which_jobs")) != NULL
&& *which_jobs
)
1397 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
, "which-jobs",
1400 cgiGetAttributes(request
, "jobs.tmpl");
1403 * Do the request and get back a response...
1406 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1409 * Get a list of matching job objects.
1412 if ((query
= cgiGetVariable("QUERY")) != NULL
&&
1413 !cgiGetVariable("CLEAR"))
1414 search
= cgiCompileSearch(query
);
1421 jobs
= cgiGetIPPObjects(response
, search
);
1422 count
= cupsArrayCount(jobs
);
1425 cgiFreeSearch(search
);
1428 * Figure out which jobs to display...
1431 if ((var
= cgiGetVariable("FIRST")) != NULL
)
1437 first
= count
- CUPS_PAGE_MAX
;
1439 first
= (first
/ CUPS_PAGE_MAX
) * CUPS_PAGE_MAX
;
1444 if ((var
= cgiGetVariable("ORDER")) != NULL
&& *var
)
1445 ascending
= !_cups_strcasecmp(var
, "asc");
1447 ascending
= !which_jobs
|| !*which_jobs
||
1448 !_cups_strcasecmp(which_jobs
, "not-completed");
1450 section
= cgiGetVariable("SECTION");
1452 cgiClearVariables();
1455 cgiSetVariable("QUERY", query
);
1457 cgiSetVariable("ORDER", ascending
? "asc" : "dec");
1459 cgiSetVariable("SECTION", section
);
1461 sprintf(val
, "%d", count
);
1462 cgiSetVariable("TOTAL", val
);
1465 cgiSetVariable("WHICH_JOBS", which_jobs
);
1469 for (i
= 0, job
= (ipp_attribute_t
*)cupsArrayIndex(jobs
, first
);
1470 i
< CUPS_PAGE_MAX
&& job
;
1471 i
++, job
= (ipp_attribute_t
*)cupsArrayNext(jobs
))
1472 cgiSetIPPObjectVars(job
, NULL
, i
);
1476 for (i
= 0, job
= (ipp_attribute_t
*)cupsArrayIndex(jobs
, count
- first
- 1);
1477 i
< CUPS_PAGE_MAX
&& job
;
1478 i
++, job
= (ipp_attribute_t
*)cupsArrayPrev(jobs
))
1479 cgiSetIPPObjectVars(job
, NULL
, i
);
1483 * Save navigation URLs...
1488 snprintf(val
, sizeof(val
), "/%s/%s", section
, dest
);
1489 cgiSetVariable("PRINTER_NAME", dest
);
1490 cgiSetVariable("PRINTER_URI_SUPPORTED", val
);
1493 strlcpy(val
, "/jobs/", sizeof(val
));
1495 cgiSetVariable("THISURL", val
);
1499 sprintf(val
, "%d", first
- CUPS_PAGE_MAX
);
1500 cgiSetVariable("PREV", val
);
1503 if ((first
+ CUPS_PAGE_MAX
) < count
)
1505 sprintf(val
, "%d", first
+ CUPS_PAGE_MAX
);
1506 cgiSetVariable("NEXT", val
);
1510 * Then show everything...
1514 cgiSetVariable("SEARCH_DEST", dest
);
1516 cgiCopyTemplateLang("search.tmpl");
1518 cgiCopyTemplateLang("jobs-header.tmpl");
1520 if (count
> CUPS_PAGE_MAX
)
1521 cgiCopyTemplateLang("pager.tmpl");
1523 cgiCopyTemplateLang("jobs.tmpl");
1525 if (count
> CUPS_PAGE_MAX
)
1526 cgiCopyTemplateLang("pager.tmpl");
1528 cupsArrayDelete(jobs
);
1529 ippDelete(response
);
1535 * 'cgiText()' - Return localized text.
1538 const char * /* O - Localized message */
1539 cgiText(const char *message
) /* I - Message */
1541 static cups_lang_t
*language
= NULL
;
1546 language
= cupsLangDefault();
1548 return (_cupsLangString(language
, message
));